aboutsummaryrefslogtreecommitdiffstats
path: root/libs/emojicon/src/main/java/github/ankushsachdeva
diff options
context:
space:
mode:
Diffstat (limited to 'libs/emojicon/src/main/java/github/ankushsachdeva')
-rw-r--r--libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiAdapter.java83
-rw-r--r--libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiRecentAdapter.java21
-rw-r--r--libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/Emojicon.java53
-rw-r--r--libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconGroup.java39
-rw-r--r--libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconGroupsLoader.java92
-rw-r--r--libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconPopupDelegate.java196
-rw-r--r--libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconRecentsManager.java98
-rw-r--r--libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconsPopup.java691
-rw-r--r--libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/RecentsEmojiconGroup.java28
-rw-r--r--libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/RepeatTouchListener.java74
-rw-r--r--libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/StaticEmojiconGroup.java29
-rw-r--r--libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/Updatable.java8
12 files changed, 946 insertions, 466 deletions
diff --git a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiAdapter.java b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiAdapter.java
index e3dc221d..b9dd5e59 100644
--- a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiAdapter.java
+++ b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiAdapter.java
@@ -16,59 +16,86 @@
package github.ankushsachdeva.emojicon;
-import github.ankushsachdeva.emojicon.EmojiconGridView.OnEmojiconClickedListener;
-import github.ankushsachdeva.emojicon.emoji.Emojicon;
-
+import java.util.ArrayList;
import java.util.List;
import android.content.Context;
+import android.view.LayoutInflater;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
+import android.widget.BaseAdapter;
import android.widget.TextView;
-import github.ankushsachdeva.emojicon.R;
-
/**
* @author Ankush Sachdeva (sankush@yahoo.co.in)
*/
-class EmojiAdapter extends ArrayAdapter<Emojicon> {
- OnEmojiconClickedListener emojiClickListener;
- public EmojiAdapter(Context context, List<Emojicon> data) {
- super(context, R.layout.emojicon_item, data);
+class EmojiAdapter extends BaseAdapter {
+ private final List<Emojicon> mEmojicons = new ArrayList<>();
+ private OnEmojiClickedListener mClickListener;
+ private final Context mContext;
+
+ public EmojiAdapter(Context context) {
+ this.mContext = context;
+ }
+
+ public void setEmojiconList(List<Emojicon> emojiconList) {
+ mEmojicons.clear();
+ mEmojicons.addAll(emojiconList);
+ notifyDataSetChanged();
+ }
+
+ public void setClickListener(OnEmojiClickedListener clickListener) {
+ mClickListener = clickListener;
+ }
+
+ @Override
+ public int getCount() {
+ return mEmojicons.size();
}
- public EmojiAdapter(Context context, Emojicon[] data) {
- super(context, R.layout.emojicon_item, data);
+ @Override
+ public Emojicon getItem(int position) {
+ return mEmojicons.get(position);
}
-
- public void setEmojiClickListener(OnEmojiconClickedListener listener){
- this.emojiClickListener = listener;
+
+ @Override
+ public long getItemId(int position) {
+ return position;
}
-
+
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
- v = View.inflate(getContext(), R.layout.emojicon_item, null);
+ v = LayoutInflater.from(mContext).inflate(R.layout.emojicon_item, null);
+ v.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mClickListener != null) {
+ mClickListener.onEmojiClicked(((ViewHolder) v.getTag()).mEmoji);
+ }
+ }
+ });
ViewHolder holder = new ViewHolder();
- holder.icon = (TextView) v.findViewById(R.id.emojicon_icon);
+ holder.mEmojiContainer = (TextView) v.findViewById(R.id.emojiContainer);
+ holder.mEmojiId = (TextView) v.findViewById(R.id.emojiId);
v.setTag(holder);
}
Emojicon emoji = getItem(position);
ViewHolder holder = (ViewHolder) v.getTag();
- holder.icon.setText(emoji.getEmoji());
- holder.icon.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- emojiClickListener.onEmojiconClicked(getItem(position));
- }
- });
+ holder.mEmoji = emoji;
+ holder.mEmojiId.setText(emoji.getId());
+ holder.mEmojiContainer.setText(emoji.toString());
return v;
}
- class ViewHolder {
- TextView icon;
+ private class ViewHolder {
+ TextView mEmojiContainer;
+ TextView mEmojiId;
+ Emojicon mEmoji;
+ }
+
+ public interface OnEmojiClickedListener {
+ void onEmojiClicked(Emojicon emojicon);
}
} \ No newline at end of file
diff --git a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiRecentAdapter.java b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiRecentAdapter.java
new file mode 100644
index 00000000..cb4bfb8c
--- /dev/null
+++ b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiRecentAdapter.java
@@ -0,0 +1,21 @@
+package github.ankushsachdeva.emojicon;
+
+import android.content.Context;
+
+/**
+ * Created by aleksandr.naumov on 14.05.2015.
+ */
+class EmojiRecentAdapter extends EmojiAdapter implements Updatable {
+ private final EmojiconRecentsManager mRecentsManager;
+
+ public EmojiRecentAdapter(Context context, EmojiconRecentsManager mRecentsManager) {
+ super(context);
+ this.mRecentsManager = mRecentsManager;
+ update();
+ }
+
+ @Override
+ public void update() {
+ setEmojiconList(mRecentsManager.getEmojiList());
+ }
+}
diff --git a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/Emojicon.java b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/Emojicon.java
new file mode 100644
index 00000000..bf8874b2
--- /dev/null
+++ b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/Emojicon.java
@@ -0,0 +1,53 @@
+package github.ankushsachdeva.emojicon;
+
+import java.nio.charset.Charset;
+
+/**
+ * Created by aleksandr.naumov on 13.05.2015.
+ */
+public class Emojicon {
+ private final String mStringRepresentation;
+
+ public Emojicon(String stringRepresentation) {
+ byte bytes[] = new byte[stringRepresentation.length() / 2];
+ for (int i = 0; i < stringRepresentation.length(); i += 2) {
+ try {
+ bytes[i / 2] = (byte) Integer.parseInt(stringRepresentation.substring(i, i + 2), 16);
+ } catch (NumberFormatException ex) {
+ throw new RuntimeException(String.format("Cannot parse '%s' as emojicon code", stringRepresentation), ex);
+ }
+ }
+ this.mStringRepresentation = new String(bytes, Charset.forName("Utf-8"));
+ }
+
+ @Override
+ public String toString() {
+ return mStringRepresentation;
+ }
+
+ public String getId() {
+ String id = "";
+ for (byte b : mStringRepresentation.getBytes()) {
+ id += String.format("%x", b);
+ }
+ return id;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Emojicon emojicon = (Emojicon) o;
+ return mStringRepresentation.equals(emojicon.mStringRepresentation);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return mStringRepresentation.hashCode();
+ }
+}
diff --git a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconGroup.java b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconGroup.java
new file mode 100644
index 00000000..22ac8f88
--- /dev/null
+++ b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconGroup.java
@@ -0,0 +1,39 @@
+package github.ankushsachdeva.emojicon;
+
+import android.content.Context;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by aleksandr.naumov on 14.05.2015.
+ */
+abstract class EmojiconGroup {
+ protected final int mIconResId;
+
+ public EmojiconGroup(int iconResId) {
+ mIconResId = iconResId;
+ }
+
+ public static EmojiconGroup fromString(String allEmojicons, int mIconResId) {
+ return new StaticEmojiconGroup(extractEmojicons(allEmojicons), mIconResId);
+ }
+
+ private static List<Emojicon> extractEmojicons(String emojiconsString) {
+ List<Emojicon> emojicons = new ArrayList<>();
+ for (String emojiconString : emojiconsString.split(" ")) {
+ if(!emojiconString.isEmpty()) {
+ emojicons.add(new Emojicon(emojiconString));
+ }
+ }
+ return emojicons;
+ }
+
+ public abstract List<Emojicon> getEmojicons();
+
+ public abstract EmojiAdapter createAdapter(Context context);
+
+ public int getIconResId() {
+ return mIconResId;
+ }
+}
diff --git a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconGroupsLoader.java b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconGroupsLoader.java
new file mode 100644
index 00000000..350e710d
--- /dev/null
+++ b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconGroupsLoader.java
@@ -0,0 +1,92 @@
+package github.ankushsachdeva.emojicon;
+
+import android.content.Context;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by aleksandr.naumov on 14.05.2015.
+ */
+class EmojiconGroupsLoader {
+ private static EmojiconGroupsLoader sInstance;
+ private final List<EmojiconGroup> mGroups;
+
+ public static synchronized EmojiconGroupsLoader getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new EmojiconGroupsLoader(context);
+ }
+ return sInstance;
+ }
+
+ private EmojiconGroupsLoader(Context context) {
+ try {
+ mGroups = parseEmojiXml(context);
+ } catch (IOException | XmlPullParserException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private List<EmojiconGroup> parseEmojiXml(Context context) throws IOException, XmlPullParserException {
+ ArrayList<EmojiconGroup> groups = new ArrayList<>();
+ XmlPullParser parser = context.getResources().getXml(R.xml.emoji);
+ parser.next();
+ String groupName = null;
+ for (int eventType = parser.getEventType(); eventType != XmlPullParser.END_DOCUMENT; eventType = parser.next()) {
+ switch (eventType) {
+ case XmlPullParser.START_TAG:
+ if ("group".equals(parser.getName())) {
+ groupName = parser.getAttributeValue(0);
+ }
+ break;
+ case XmlPullParser.TEXT:
+ if (groupName != null) {
+ groups.add(EmojiconGroup.fromString(
+ parser.getText(),
+ getGroupNameIcon(groupName)
+ ));
+ groupName = null;
+ }
+ break;
+ }
+ }
+ return groups;
+ }
+
+ private int getGroupNameIcon(String groupName) {
+ for (KnownGroupNames knownGroupName : KnownGroupNames.values()) {
+ if (groupName.toLowerCase().equals(knownGroupName.name().toLowerCase())) {
+ return knownGroupName.getIconResId();
+ }
+ }
+ throw new IllegalArgumentException(String.format("Unknown group name '%s'", groupName));
+ }
+
+ public List<EmojiconGroup> getGroups() {
+ return mGroups;
+ }
+
+ public enum KnownGroupNames {
+ RECENT(R.drawable.ic_emoji_recent_light),
+ SMILES(R.drawable.ic_emoji_people_light),
+ NATURE(R.drawable.ic_emoji_nature_light),
+ OBJECTS(R.drawable.ic_emoji_objects_light),
+ TECH(R.drawable.ic_emoji_places_light),
+ SYMBOLS(R.drawable.ic_emoji_symbols_light);
+
+ private final int iconResId;
+
+ KnownGroupNames(int iconResId) {
+ this.iconResId = iconResId;
+ }
+
+ public int getIconResId() {
+ return iconResId;
+ }
+ }
+}
diff --git a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconPopupDelegate.java b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconPopupDelegate.java
new file mode 100644
index 00000000..48952cdb
--- /dev/null
+++ b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconPopupDelegate.java
@@ -0,0 +1,196 @@
+package github.ankushsachdeva.emojicon;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.view.ContextThemeWrapper;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.PopupWindow;
+
+/**
+ * Created by aleksandr.naumov on 15.05.2015.
+ */
+public class EmojiconPopupDelegate {
+ public static final String KEY_EMOJI_POPUP_SHOWN = "key_emoji_popup_shown";
+ private Context mContext;
+ private EmojiconsPopup mPopup;
+ private EditText mPrefferredEditText;
+ private boolean mPendingShow;
+ private View mRootView;
+
+ @Nullable
+ private PopupShownListener mListener;
+
+ public void setShowHideListener(PopupShownListener listener) {
+ this.mListener = listener;
+ }
+
+ public void setInputEditText(EditText editText) {
+ mPrefferredEditText = editText;
+ }
+
+ public void attach(View rootView) {
+ mContext = createThemedContext(rootView.getContext());
+ mRootView = rootView;
+ mPopup = new EmojiconsPopup(rootView, mContext);
+ mPopup.setOnDismissListener(new DismissListener());
+ mPopup.setOnSoftKeyboardOpenCloseListener(new KeyboardOpenCloseListener());
+ mPopup.setOnEmojiconClickedListener(new EmojiconClickedListener());
+ mPopup.setOnEmojiconBackspaceClickedListener(new BackspaceClickedListener());
+ mPopup.attachGlobalLayoutListener();
+ if (mPendingShow) {
+ show();
+ }
+ }
+
+ private Context createThemedContext(Context context) {
+ TypedArray typedArray = context.obtainStyledAttributes(null, new int[]{R.attr.emojicon_theme});
+ int themeId = typedArray.getResourceId(0, R.style.Emojicon);
+ typedArray.recycle();
+ return new ContextThemeWrapper(context, themeId);
+ }
+
+ public void detach() {
+ hide();
+ if (mPopup != null) {
+ mPopup.detachGlobalLayoutListener();
+ mPopup = null;
+ }
+ mContext = null;
+ mPrefferredEditText = null;
+ mRootView = null;
+ }
+
+ public void saveState(Bundle bundle) {
+ bundle.putBoolean(KEY_EMOJI_POPUP_SHOWN, isShown());
+ }
+
+ public void restoreState(Bundle bundle) {
+ if (bundle.containsKey(KEY_EMOJI_POPUP_SHOWN)) {
+ if (bundle.getBoolean(KEY_EMOJI_POPUP_SHOWN)) {
+ show();
+ } else {
+ hide();
+ }
+ }
+ }
+
+ public void show() {
+ if (mPopup != null && !mPopup.isShowing()) {
+ if (mPopup.isKeyBoardOpen()) {
+ //If keyboard is visible, simply show the emoji popup
+ mPopup.showAtBottom();
+ } else {
+ //else, open the text keyboard first and immediately after that show the emoji popup
+ mPrefferredEditText.setFocusableInTouchMode(true);
+ mPrefferredEditText.requestFocus();
+ mPopup.showAtBottomPending();
+ final InputMethodManager inputMethodManager = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputMethodManager.showSoftInput(mPrefferredEditText, InputMethodManager.SHOW_IMPLICIT);
+ }
+ mPendingShow = false;
+ notifyShown();
+ } else if (!mPendingShow) {
+ mPendingShow = true;
+ notifyShown();
+ }
+ }
+
+ public void hide() {
+ if (mPopup != null && mPopup.isShowing()) {
+ mPopup.dismiss();
+ notifyHidden();
+ } else if (mPendingShow) {
+ mPendingShow = false;
+ notifyHidden();
+ }
+ }
+
+ private void notifyShown() {
+ if (mListener != null) {
+ mListener.onPopupShown();
+ }
+ }
+
+ private void notifyHidden() {
+ if (mListener != null) {
+ mListener.onPopupHidden();
+ }
+ }
+
+ public boolean isShown() {
+ return mPopup != null ? mPopup.isShowing() : mPendingShow;
+ }
+
+ public void toggle() {
+ if (isShown()) {
+ hide();
+ } else {
+ show();
+ }
+ }
+
+ @Nullable
+ public EditText findFocusedEditText() {
+ View view = mRootView != null ? mRootView.findFocus() : null;
+ if (view instanceof EditText) {
+ return (EditText) view;
+ } else {
+ return null;
+ }
+ }
+
+ public interface PopupShownListener {
+ void onPopupShown();
+
+ void onPopupHidden();
+ }
+
+ private class BackspaceClickedListener implements EmojiconsPopup.OnEmojiconBackspaceClickedListener {
+ @Override
+ public void onEmojiconBackspaceClicked(View v) {
+ EditText currentFocus = findFocusedEditText();
+ if (currentFocus != null) {
+ KeyEvent event = new KeyEvent(0, 0, 0, KeyEvent.KEYCODE_DEL, 0, 0, 0, 0, KeyEvent.KEYCODE_ENDCALL);
+ currentFocus.dispatchKeyEvent(event);
+ }
+ }
+ }
+
+ private class EmojiconClickedListener implements EmojiconsPopup.OnEmojiconClickedListener {
+
+ @Override
+ public void onEmojiconClicked(Emojicon emojicon) {
+ EditText currentFocus = findFocusedEditText();
+ if (currentFocus != null) {
+ String textToInsert = emojicon.toString();
+ int start = Math.max(currentFocus.getSelectionStart(), 0);
+ int end = Math.max(currentFocus.getSelectionEnd(), 0);
+ currentFocus.getText().replace(Math.min(start, end), Math.max(start, end), textToInsert, 0, textToInsert.length());
+ }
+ }
+ }
+
+ private class KeyboardOpenCloseListener implements EmojiconsPopup.OnSoftKeyboardOpenCloseListener {
+ @Override
+ public void onKeyboardOpen(int keyBoardHeight) {
+
+ }
+
+ @Override
+ public void onKeyboardClose() {
+ hide();
+ }
+ }
+
+ private class DismissListener implements PopupWindow.OnDismissListener {
+ @Override
+ public void onDismiss() {
+ notifyHidden();
+ }
+ }
+}
diff --git a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconRecentsManager.java b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconRecentsManager.java
index 9fbb987e..6110d012 100644
--- a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconRecentsManager.java
+++ b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconRecentsManager.java
@@ -16,43 +16,33 @@
package github.ankushsachdeva.emojicon;
-import github.ankushsachdeva.emojicon.emoji.Emojicon;
-
-import java.util.ArrayList;
-import java.util.StringTokenizer;
+import java.util.Iterator;
+import java.util.LinkedList;
import android.content.Context;
import android.content.SharedPreferences;
/**
-* @author Daniele Ricci
-*/
-public class EmojiconRecentsManager extends ArrayList<Emojicon> {
-
- private static final String PREFERENCE_NAME = "emojicon";
- private static final String PREF_RECENTS = "recent_emojis";
- private static final String PREF_PAGE = "recent_page";
+ * @author Daniele Ricci
+ */
+class EmojiconRecentsManager {
- private static final Object LOCK = new Object();
- private static EmojiconRecentsManager sInstance;
+ private static final String PREFERENCE_NAME = "emojicon_v2";
+ private static final String PREF_RECENTS = "recent_emojis_v2";
+ private static final String PREF_PAGE = "recent_page_v2";
+ private static final String EMOJI_DIVIDER = " ";
+ private final LinkedList<Emojicon> mEmoji;
private Context mContext;
- private EmojiconRecentsManager(Context context) {
+ public EmojiconRecentsManager(Context context) {
mContext = context.getApplicationContext();
- loadRecents();
+ mEmoji = loadRecent();
}
- public static EmojiconRecentsManager getInstance(Context context) {
- if (sInstance == null) {
- synchronized (LOCK) {
- if (sInstance == null) {
- sInstance = new EmojiconRecentsManager(context);
- }
- }
- }
- return sInstance;
+ public LinkedList<Emojicon> getEmojiList() {
+ return mEmoji;
}
public int getRecentPage() {
@@ -64,61 +54,31 @@ public class EmojiconRecentsManager extends ArrayList<Emojicon> {
}
public void push(Emojicon object) {
- // FIXME totally inefficient way of adding the emoji to the adapter
- // TODO this should be probably replaced by a deque
- if (contains(object)) {
- super.remove(object);
+ if (mEmoji.contains(object)) {
+ mEmoji.remove(object);
}
- add(0, object);
- }
-
- @Override
- public boolean add(Emojicon object) {
- boolean ret = super.add(object);
- return ret;
+ mEmoji.addFirst(object);
}
- @Override
- public void add(int index, Emojicon object) {
- super.add(index, object);
- }
-
- @Override
- public boolean remove(Object object) {
- boolean ret = super.remove(object);
- return ret;
- }
-
private SharedPreferences getPreferences() {
return mContext.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
}
- private void loadRecents() {
- SharedPreferences prefs = getPreferences();
- String str = prefs.getString(PREF_RECENTS, "");
- StringTokenizer tokenizer = new StringTokenizer(str, "~");
- while (tokenizer.hasMoreTokens()) {
- try {
- add(new Emojicon(tokenizer.nextToken()));
- }
- catch (NumberFormatException e) {
- // ignored
- }
+ private LinkedList<Emojicon> loadRecent() {
+ String allEmoji = getPreferences().getString(PREF_RECENTS, "");
+ if (allEmoji != null) {
+ return new LinkedList<>(EmojiconGroup.fromString(allEmoji, 0).getEmojicons());
+ } else {
+ return new LinkedList<>();
}
}
-
- public void saveRecents() {
+
+ public void save() {
StringBuilder str = new StringBuilder();
- int c = size();
- for (int i = 0; i < c; i++) {
- Emojicon e = get(i);
- str.append(e.getEmoji());
- if (i < (c - 1)) {
- str.append('~');
- }
+ for (Iterator<Emojicon> iterator = mEmoji.iterator(); iterator.hasNext(); ) {
+ Emojicon emojicon = iterator.next();
+ str.append(emojicon.getId()).append(iterator.hasNext() ? EMOJI_DIVIDER : "");
}
- SharedPreferences prefs = getPreferences();
- prefs.edit().putString(PREF_RECENTS, str.toString()).commit();
+ getPreferences().edit().putString(PREF_RECENTS, str.toString()).apply();
}
-
}
diff --git a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconsPopup.java b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconsPopup.java
index 12bc16e0..5bcafccf 100644
--- a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconsPopup.java
+++ b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/EmojiconsPopup.java
@@ -16,32 +16,25 @@
package github.ankushsachdeva.emojicon;
-import github.ankushsachdeva.emojicon.EmojiconGridView.OnEmojiconClickedListener;
-import github.ankushsachdeva.emojicon.emoji.Emojicon;
-import github.ankushsachdeva.emojicon.emoji.Nature;
-import github.ankushsachdeva.emojicon.emoji.Objects;
-import github.ankushsachdeva.emojicon.emoji.People;
-import github.ankushsachdeva.emojicon.emoji.Places;
-import github.ankushsachdeva.emojicon.emoji.Symbols;
-
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.List;
-import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
-import android.os.Handler;
-import android.os.SystemClock;
+import android.support.annotation.Nullable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
+import android.util.SparseArray;
import android.view.Gravity;
import android.view.LayoutInflater;
-import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.WindowManager.LayoutParams;
+import android.widget.GridView;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
import android.widget.PopupWindow;
@@ -49,360 +42,320 @@ import android.widget.PopupWindow;
* @author Ankush Sachdeva (sankush@yahoo.co.in).
*/
-public class EmojiconsPopup extends PopupWindow implements ViewPager.OnPageChangeListener, EmojiconRecents {
- private int mEmojiTabLastSelectedIndex = -1;
- private View[] mEmojiTabs;
- private PagerAdapter mEmojisAdapter;
- private EmojiconRecentsManager mRecentsManager;
- private int keyBoardHeight = 0;
- private Boolean pendingOpen = false;
- private Boolean isOpened = false;
- OnEmojiconClickedListener onEmojiconClickedListener;
- OnEmojiconBackspaceClickedListener onEmojiconBackspaceClickedListener;
- OnSoftKeyboardOpenCloseListener onSoftKeyboardOpenCloseListener;
- View rootView;
- Context mContext;
-
- private ViewPager emojisPager;
- /**
- * Constructor
- * @param rootView The top most layout in your view hierarchy. The difference of this view and the screen height will be used to calculate the keyboard height.
- * @param mContext The context of current activity.
- */
- public EmojiconsPopup(View rootView, Context mContext){
- super(mContext);
- this.mContext = mContext;
- this.rootView = rootView;
- View customView = createCustomView();
- setContentView(customView);
- setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
- //default size
- setSize((int) mContext.getResources().getDimension(R.dimen.keyboard_height), LayoutParams.MATCH_PARENT);
- }
- /**
- * Set the listener for the event of keyboard opening or closing.
- */
- public void setOnSoftKeyboardOpenCloseListener(OnSoftKeyboardOpenCloseListener listener){
- this.onSoftKeyboardOpenCloseListener = listener;
- }
-
- /**
- * Set the listener for the event when any of the emojicon is clicked
- */
- public void setOnEmojiconClickedListener(OnEmojiconClickedListener listener){
- this.onEmojiconClickedListener = listener;
- }
-
- /**
- * Set the listener for the event when backspace on emojicon popup is clicked
- */
- public void setOnEmojiconBackspaceClickedListener(OnEmojiconBackspaceClickedListener listener){
- this.onEmojiconBackspaceClickedListener = listener;
- }
-
- /**
- * Use this function to show the emoji popup.
- * NOTE: Since, the soft keyboard sizes are variable on different android devices, the
- * library needs you to open the soft keyboard atleast once before calling this function.
- * If that is not possible see showAtBottomPending() function.
- *
- */
- public void showAtBottom(){
- showAtLocation(rootView, Gravity.BOTTOM, 0, 0);
- }
- /**
- * Use this function when the soft keyboard has not been opened yet. This
- * will show the emoji popup after the keyboard is up next time.
- * Generally, you will be calling InputMethodManager.showSoftInput function after
- * calling this function.
- */
- public void showAtBottomPending(){
- if(isKeyBoardOpen())
- showAtBottom();
- else
- pendingOpen = true;
- }
-
- /**
- *
- * @return Returns true if the soft keyboard is open, false otherwise.
- */
- public Boolean isKeyBoardOpen(){
- return isOpened;
- }
-
- /**
- * Dismiss the popup
- */
- @Override
- public void dismiss() {
- super.dismiss();
- EmojiconRecentsManager
- .getInstance(mContext).saveRecents();
- }
-
- /**
- * Call this function to resize the emoji popup according to your soft keyboard size
- */
- public void setSizeForSoftKeyboard(){
- rootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- Rect r = new Rect();
- rootView.getWindowVisibleDisplayFrame(r);
-
- int screenHeight = rootView.getRootView()
- .getHeight();
- int heightDifference = screenHeight
- - (r.bottom - r.top);
- int resourceId = mContext.getResources()
- .getIdentifier("status_bar_height",
- "dimen", "android");
- if (resourceId > 0) {
- heightDifference -= mContext.getResources()
- .getDimensionPixelSize(resourceId);
- }
- if (heightDifference > 100) {
- keyBoardHeight = heightDifference;
- setSize(LayoutParams.MATCH_PARENT, keyBoardHeight);
- if(isOpened == false){
- if(onSoftKeyboardOpenCloseListener!=null)
- onSoftKeyboardOpenCloseListener.onKeyboardOpen(keyBoardHeight);
- }
- isOpened = true;
- if(pendingOpen){
- showAtBottom();
- pendingOpen = false;
- }
- }
- else{
- isOpened = false;
- if(onSoftKeyboardOpenCloseListener!=null)
- onSoftKeyboardOpenCloseListener.onKeyboardClose();
- }
- }
- });
- }
-
- /**
- * Manually set the popup window size
- * @param width Width of the popup
- * @param height Height of the popup
- */
- public void setSize(int width, int height){
- setWidth(width);
- setHeight(height);
- }
-
- private View createCustomView() {
- LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
- View view = inflater.inflate(R.layout.emojicons, null, false);
- emojisPager = (ViewPager) view.findViewById(R.id.emojis_pager);
- emojisPager.setOnPageChangeListener(this);
- EmojiconRecents recents = this;
- mEmojisAdapter = new EmojisPagerAdapter(
- Arrays.asList(
- new EmojiconRecentsGridView(mContext, null, null, this),
- new EmojiconGridView(mContext, People.DATA, recents, this),
- new EmojiconGridView(mContext, Nature.DATA, recents, this),
- new EmojiconGridView(mContext, Objects.DATA, recents, this),
- new EmojiconGridView(mContext, Places.DATA, recents, this),
- new EmojiconGridView(mContext, Symbols.DATA, recents, this)
- )
- );
- emojisPager.setAdapter(mEmojisAdapter);
- mEmojiTabs = new View[6];
- mEmojiTabs[0] = view.findViewById(R.id.emojis_tab_0_recents);
- mEmojiTabs[1] = view.findViewById(R.id.emojis_tab_1_people);
- mEmojiTabs[2] = view.findViewById(R.id.emojis_tab_2_nature);
- mEmojiTabs[3] = view.findViewById(R.id.emojis_tab_3_objects);
- mEmojiTabs[4] = view.findViewById(R.id.emojis_tab_4_cars);
- mEmojiTabs[5] = view.findViewById(R.id.emojis_tab_5_punctuation);
- for (int i = 0; i < mEmojiTabs.length; i++) {
- final int position = i;
- mEmojiTabs[i].setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- emojisPager.setCurrentItem(position);
- }
- });
- }
- view.findViewById(R.id.emojis_backspace).setOnTouchListener(new RepeatListener(1000, 50, new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- if(onEmojiconBackspaceClickedListener != null)
- onEmojiconBackspaceClickedListener.onEmojiconBackspaceClicked(v);
- }
- }));
-
- // get last selected page
- mRecentsManager = EmojiconRecentsManager.getInstance(view.getContext());
- int page = mRecentsManager.getRecentPage();
- // last page was recents, check if there are recents to use
- // if none was found, go to page 1
- if (page == 0 && mRecentsManager.size() == 0) {
- page = 1;
- }
-
- if (page == 0) {
- onPageSelected(page);
- }
- else {
- emojisPager.setCurrentItem(page, false);
- }
- return view;
- }
-
- @Override
- public void addRecentEmoji(Context context, Emojicon emojicon) {
- EmojiconRecentsGridView fragment = ((EmojisPagerAdapter)emojisPager.getAdapter()).getRecentFragment();
- fragment.addRecentEmoji(context, emojicon);
- }
-
-
- @Override
- public void onPageScrolled(int i, float v, int i2) {
- }
-
- @Override
- public void onPageSelected(int i) {
- if (mEmojiTabLastSelectedIndex == i) {
- return;
- }
- switch (i) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- if (mEmojiTabLastSelectedIndex >= 0 && mEmojiTabLastSelectedIndex < mEmojiTabs.length) {
- mEmojiTabs[mEmojiTabLastSelectedIndex].setSelected(false);
- }
- mEmojiTabs[i].setSelected(true);
- mEmojiTabLastSelectedIndex = i;
- mRecentsManager.setRecentPage(i);
- break;
- }
- }
-
- @Override
- public void onPageScrollStateChanged(int i) {
- }
-
- private static class EmojisPagerAdapter extends PagerAdapter {
- private List<EmojiconGridView> views;
- public EmojiconRecentsGridView getRecentFragment(){
- for (EmojiconGridView it : views) {
- if(it instanceof EmojiconRecentsGridView)
- return (EmojiconRecentsGridView)it;
- }
- return null;
- }
- public EmojisPagerAdapter(List<EmojiconGridView> views) {
- super();
- this.views = views;
- }
-
- @Override
- public int getCount() {
- return views.size();
- }
-
-
- @Override
- public Object instantiateItem(ViewGroup container, int position) {
- View v = views.get(position).rootView;
- ((ViewPager)container).addView(v, 0);
- return v;
- }
-
- @Override
- public void destroyItem(ViewGroup container, int position, Object view) {
- ((ViewPager)container).removeView((View)view);
- }
-
- @Override
- public boolean isViewFromObject(View view, Object key) {
- return key == view;
- }
- }
-
- /**
- * A class, that can be used as a TouchListener on any view (e.g. a Button).
- * It cyclically runs a clickListener, emulating keyboard-like behaviour. First
- * click is fired immediately, next before initialInterval, and subsequent before
- * normalInterval.
- * <p/>
- * <p>Interval is scheduled before the onClick completes, so it has to run fast.
- * If it runs slow, it does not generate skipped onClicks.
- */
- public static class RepeatListener implements View.OnTouchListener {
-
- private Handler handler = new Handler();
-
- private int initialInterval;
- private final int normalInterval;
- private final View.OnClickListener clickListener;
-
- private Runnable handlerRunnable = new Runnable() {
- @Override
- public void run() {
- if (downView == null) {
- return;
- }
- handler.removeCallbacksAndMessages(downView);
- handler.postAtTime(this, downView, SystemClock.uptimeMillis() + normalInterval);
- clickListener.onClick(downView);
- }
- };
-
- private View downView;
-
- /**
- * @param initialInterval The interval before first click event
- * @param normalInterval The interval before second and subsequent click
- * events
- * @param clickListener The OnClickListener, that will be called
- * periodically
- */
- public RepeatListener(int initialInterval, int normalInterval, View.OnClickListener clickListener) {
- if (clickListener == null)
- throw new IllegalArgumentException("null runnable");
- if (initialInterval < 0 || normalInterval < 0)
- throw new IllegalArgumentException("negative interval");
-
- this.initialInterval = initialInterval;
- this.normalInterval = normalInterval;
- this.clickListener = clickListener;
- }
-
- public boolean onTouch(View view, MotionEvent motionEvent) {
- switch (motionEvent.getAction()) {
- case MotionEvent.ACTION_DOWN:
- downView = view;
- handler.removeCallbacks(handlerRunnable);
- handler.postAtTime(handlerRunnable, downView, SystemClock.uptimeMillis() + initialInterval);
- clickListener.onClick(view);
- return true;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_OUTSIDE:
- handler.removeCallbacksAndMessages(downView);
- downView = null;
- return true;
- }
- return false;
- }
- }
-
- public interface OnEmojiconBackspaceClickedListener {
- void onEmojiconBackspaceClicked(View v);
- }
-
- public interface OnSoftKeyboardOpenCloseListener{
- void onKeyboardOpen(int keyBoardHeight);
- void onKeyboardClose();
- }
+public class EmojiconsPopup extends PopupWindow implements ViewPager.OnPageChangeListener, EmojiAdapter.OnEmojiClickedListener {
+ private View[] mEmojiTabs;
+ private EmojiconRecentsManager mRecentsManager;
+ private int keyBoardHeight = 0;
+ private boolean mWaitingForKbOpen = false;
+ private boolean mIsOpened = false;
+ private View mRootView;
+ private Context mContext;
+ private ViewPager mEmojisPager;
+
+ @Nullable
+ private OnSoftKeyboardOpenCloseListener mSoftKeyboardOpenCloseListener;
+
+ @Nullable
+ private OnEmojiconClickedListener mEmojiconClickedListener;
+
+ @Nullable
+ private OnEmojiconBackspaceClickedListener mEmojiconBackspaceClickedListener;
+
+ private GlobalLayoutListener mGlobalLayoutListener = new GlobalLayoutListener();
+
+ /**
+ * Constructor
+ *
+ * @param rootView The top most layout in your view hierarchy. The difference of this view and the screen height will be used to calculate the keyboard height.
+ * @param context The context of current activity.
+ */
+ public EmojiconsPopup(View rootView, Context context) {
+ super(context, null, R.attr.emojicon_dialog_style);
+ mContext = context;
+ mRootView = rootView;
+ mRecentsManager = new EmojiconRecentsManager(context);
+ setContentView(createCustomView());
+ setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+ }
+
+ /**
+ * Set the listener for the event of keyboard opening or closing.
+ */
+ public void setOnSoftKeyboardOpenCloseListener(OnSoftKeyboardOpenCloseListener listener) {
+ this.mSoftKeyboardOpenCloseListener = listener;
+ }
+
+ /**
+ * Set the listener for the event when any of the emojicon is clicked
+ */
+ public void setOnEmojiconClickedListener(OnEmojiconClickedListener listener) {
+ this.mEmojiconClickedListener = listener;
+ }
+
+ /**
+ * Set the listener for the event when backspace on emojicon popup is clicked
+ */
+ public void setOnEmojiconBackspaceClickedListener(OnEmojiconBackspaceClickedListener listener) {
+ this.mEmojiconBackspaceClickedListener = listener;
+ }
+
+ /**
+ * Use this function to show the emoji popup.
+ * NOTE: Since, the soft keyboard sizes are variable on different android devices, the
+ * library needs you to open the soft keyboard atleast once before calling this function.
+ * If that is not possible see showAtBottomPending() function.
+ */
+ public void showAtBottom() {
+ showAtLocation(mRootView, Gravity.BOTTOM, 0, 0);
+ }
+
+ /**
+ * Use this function when the soft keyboard has not been opened yet. This
+ * will show the emoji popup after the keyboard is up next time.
+ * Generally, you will be calling InputMethodManager.showSoftInput function after
+ * calling this function.
+ */
+ public void showAtBottomPending() {
+ if (isKeyBoardOpen()) {
+ showAtBottom();
+ } else {
+ mWaitingForKbOpen = true;
+ }
+ }
+
+ /**
+ * @return Returns true if the soft keyboard is open, false otherwise.
+ */
+ public Boolean isKeyBoardOpen() {
+ return mIsOpened;
+ }
+
+ /**
+ * Dismiss the popup
+ */
+ @Override
+ public void dismiss() {
+ super.dismiss();
+ mRecentsManager.save();
+ }
+
+ /**
+ * Call this function to resize the emoji popup according to your soft keyboard size
+ */
+ public void attachGlobalLayoutListener() {
+ mRootView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener);
+ }
+
+ public void detachGlobalLayoutListener() {
+ mRootView.getViewTreeObserver().removeGlobalOnLayoutListener(mGlobalLayoutListener);
+ }
+
+ /**
+ * Manually set the popup window size
+ *
+ * @param width Width of the popup
+ * @param height Height of the popup
+ */
+ public void setSize(int width, int height) {
+ setWidth(width);
+ setHeight(height);
+ }
+
+ private View createCustomView() {
+ View view = LayoutInflater.from(mContext).inflate(R.layout.emojicons, null);
+ List<EmojiconGroup> displayedGroups = collectDisplayedGroups();
+ initViewPager(view, displayedGroups);
+ initTabs(view, displayedGroups);
+ initCurrentPage();
+ return view;
+ }
+
+ private void initCurrentPage() {
+ // get last selected page
+ int page = mRecentsManager.getRecentPage();
+ // last page was recents, check if there are recents to use
+ // if none was found, go to page 1
+ if (page == 0 && mRecentsManager.getEmojiList().isEmpty()) {
+ page = 1;
+ }
+ if (page == 0) {
+ onPageSelected(page);
+ } else {
+ mEmojisPager.setCurrentItem(page, false);
+ }
+ }
+
+ private void initTabs(View view, List<EmojiconGroup> displayedGroups) {
+ LinearLayout tabHostLayout = (LinearLayout) view.findViewById(R.id.emojis_tab);
+ mEmojiTabs = new View[displayedGroups.size()];
+ for (int i = 0; i < displayedGroups.size(); i++) {
+ final int position = i;
+ mEmojiTabs[i] = inflateTab(tabHostLayout, displayedGroups.get(i).getIconResId());
+ mEmojiTabs[i].setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mEmojisPager.setCurrentItem(position);
+ }
+ });
+ inflateDivider(tabHostLayout);
+ }
+ View backSpace = inflateTab(tabHostLayout, R.drawable.ic_keyboard_delete);
+ backSpace.setOnTouchListener(new RepeatTouchListener(1000, 50, new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mEmojiconBackspaceClickedListener != null) {
+ mEmojiconBackspaceClickedListener.onEmojiconBackspaceClicked(v);
+ }
+ }
+ }));
+ }
+
+ private View inflateTab(LinearLayout tabHostLayout, int iconResId) {
+ ImageButton tabView = (ImageButton) LayoutInflater.from(mContext)
+ .inflate(R.layout.emojicon_tab, tabHostLayout, false);
+
+ tabHostLayout.addView(tabView);
+ tabView.setImageDrawable(mContext.getResources().getDrawable(iconResId));
+ return tabView;
+ }
+
+ private View inflateDivider(LinearLayout tabHostLayout) {
+ return LayoutInflater.from(mContext).inflate(R.layout.emojicon_tab_divider, tabHostLayout);
+ }
+
+ private void initViewPager(View view, List<EmojiconGroup> displayedGroups) {
+ mEmojisPager = (ViewPager) view.findViewById(R.id.emojis_pager);
+ mEmojisPager.setOnPageChangeListener(this);
+ mEmojisPager.setAdapter(new EmojisPagerAdapter(displayedGroups));
+ }
+
+ private List<EmojiconGroup> collectDisplayedGroups() {
+ List<EmojiconGroup> groups = new ArrayList<>();
+ groups.add(new RecentsEmojiconGroup(mRecentsManager, EmojiconGroupsLoader.KnownGroupNames.RECENT.getIconResId()));
+ groups.addAll(EmojiconGroupsLoader.getInstance(mContext).getGroups());
+ return groups;
+ }
+
+ @Override
+ public void onPageScrolled(int i, float v, int i2) {
+ // ignore
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ for (int i = 0; i < mEmojiTabs.length; i++) {
+ mEmojiTabs[i].setSelected(i == position);
+ }
+ mRecentsManager.setRecentPage(position);
+ EmojiAdapter adapter = ((EmojisPagerAdapter) mEmojisPager.getAdapter()).getPageAdapter(position);
+ if (adapter instanceof Updatable) {
+ ((Updatable) adapter).update();
+ }
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int i) {
+ // ignore
+ }
+
+ @Override
+ public void onEmojiClicked(Emojicon emojicon) {
+ mRecentsManager.push(emojicon);
+ if (mEmojiconClickedListener != null) {
+ mEmojiconClickedListener.onEmojiconClicked(emojicon);
+ }
+ }
+
+ private class EmojisPagerAdapter extends PagerAdapter {
+ private final List<EmojiconGroup> mGroups;
+ private final SparseArray<EmojiAdapter> mAdapters = new SparseArray<>();
+
+ public EmojisPagerAdapter(List<EmojiconGroup> groups) {
+ mGroups = groups;
+ }
+
+ public EmojiAdapter getPageAdapter(int pageIndex) {
+ return mAdapters.get(pageIndex);
+ }
+
+ @Override
+ public int getCount() {
+ return mGroups.size();
+ }
+
+ @Override
+ public GridView instantiateItem(ViewGroup container, final int viewPosition) {
+ GridView gridView = (GridView) LayoutInflater.from(mContext).inflate(R.layout.emojicon_grid, container, false);
+ container.addView(gridView);
+ final EmojiAdapter adapter = mGroups.get(viewPosition).createAdapter(mContext);
+ gridView.setAdapter(adapter);
+ adapter.setClickListener(EmojiconsPopup.this);
+ mAdapters.put(viewPosition, adapter);
+ return gridView;
+ }
+
+ @Override
+ public void destroyItem(ViewGroup container, int position, Object view) {
+ container.removeView((View) view);
+ mAdapters.remove(position);
+ }
+
+ @Override
+ public boolean isViewFromObject(View view, Object key) {
+ return key == view;
+ }
+ }
+
+ public interface OnEmojiconClickedListener {
+ void onEmojiconClicked(Emojicon emojicon);
+ }
+
+ public interface OnEmojiconBackspaceClickedListener {
+ void onEmojiconBackspaceClicked(View v);
+ }
+
+ public interface OnSoftKeyboardOpenCloseListener {
+ void onKeyboardOpen(int keyBoardHeight);
+
+ void onKeyboardClose();
+ }
+
+ private class GlobalLayoutListener implements OnGlobalLayoutListener {
+ @Override
+ public void onGlobalLayout() {
+ Rect r = new Rect();
+ mRootView.getWindowVisibleDisplayFrame(r);
+
+ int screenHeight = mRootView.getRootView().getHeight();
+ int heightDifference = screenHeight - (r.bottom - r.top);
+ int resourceId = mContext.getResources()
+ .getIdentifier("status_bar_height", "dimen", "android");
+ if (resourceId > 0) {
+ heightDifference -= mContext.getResources().getDimensionPixelSize(resourceId);
+ }
+ if (heightDifference > 100) {
+ int oldHeight = getHeight();
+ keyBoardHeight = heightDifference;
+ setSize(LayoutParams.MATCH_PARENT, keyBoardHeight);
+ if (!mIsOpened) {
+ if (mSoftKeyboardOpenCloseListener != null) {
+ mSoftKeyboardOpenCloseListener.onKeyboardOpen(keyBoardHeight);
+ }
+ }
+ mIsOpened = true;
+ if (mWaitingForKbOpen) {
+ showAtBottom();
+ mWaitingForKbOpen = false;
+ } else if(isShowing() && oldHeight != keyBoardHeight) {
+ dismiss();
+ showAtBottom();
+ }
+ } else {
+ mIsOpened = false;
+ if (mSoftKeyboardOpenCloseListener != null) {
+ mSoftKeyboardOpenCloseListener.onKeyboardClose();
+ }
+ }
+ }
+ }
}
diff --git a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/RecentsEmojiconGroup.java b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/RecentsEmojiconGroup.java
new file mode 100644
index 00000000..815aca2d
--- /dev/null
+++ b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/RecentsEmojiconGroup.java
@@ -0,0 +1,28 @@
+package github.ankushsachdeva.emojicon;
+
+import android.content.Context;
+
+import java.util.List;
+
+/**
+ * Created by aleksandr.naumov on 14.05.2015.
+ */
+class RecentsEmojiconGroup extends EmojiconGroup {
+
+ private final EmojiconRecentsManager mRecentsManager;
+
+ public RecentsEmojiconGroup(EmojiconRecentsManager mRecentsManager, int iconResId) {
+ super(iconResId);
+ this.mRecentsManager = mRecentsManager;
+ }
+
+ @Override
+ public List<Emojicon> getEmojicons() {
+ return mRecentsManager.getEmojiList();
+ }
+
+ @Override
+ public EmojiAdapter createAdapter(Context context) {
+ return new EmojiRecentAdapter(context, mRecentsManager);
+ }
+}
diff --git a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/RepeatTouchListener.java b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/RepeatTouchListener.java
new file mode 100644
index 00000000..e8f8e0fb
--- /dev/null
+++ b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/RepeatTouchListener.java
@@ -0,0 +1,74 @@
+package github.ankushsachdeva.emojicon;
+
+import android.os.Handler;
+import android.os.SystemClock;
+import android.view.MotionEvent;
+import android.view.View;
+
+/**
+ * A class, that can be used as a TouchListener on any view (e.g. a Button).
+ * It cyclically runs a clickListener, emulating keyboard-like behaviour. First
+ * click is fired immediately, next before initialInterval, and subsequent before
+ * normalInterval.
+ * <p/>
+ * <p>Interval is scheduled before the onClick completes, so it has to run fast.
+ * If it runs slow, it does not generate skipped onClicks.
+ */
+class RepeatTouchListener implements View.OnTouchListener {
+
+ private Handler handler = new Handler();
+
+ private int initialInterval;
+ private final int normalInterval;
+ private final View.OnClickListener clickListener;
+
+ private Runnable handlerRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (downView == null) {
+ return;
+ }
+ handler.removeCallbacksAndMessages(downView);
+ handler.postAtTime(this, downView, SystemClock.uptimeMillis() + normalInterval);
+ clickListener.onClick(downView);
+ }
+ };
+
+ private View downView;
+
+ /**
+ * @param initialInterval The interval before first click event
+ * @param normalInterval The interval before second and subsequent click
+ * events
+ * @param clickListener The OnClickListener, that will be called
+ * periodically
+ */
+ public RepeatTouchListener(int initialInterval, int normalInterval, View.OnClickListener clickListener) {
+ if (clickListener == null)
+ throw new IllegalArgumentException("null runnable");
+ if (initialInterval < 0 || normalInterval < 0)
+ throw new IllegalArgumentException("negative interval");
+
+ this.initialInterval = initialInterval;
+ this.normalInterval = normalInterval;
+ this.clickListener = clickListener;
+ }
+
+ public boolean onTouch(View view, MotionEvent motionEvent) {
+ switch (motionEvent.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ downView = view;
+ handler.removeCallbacks(handlerRunnable);
+ handler.postAtTime(handlerRunnable, downView, SystemClock.uptimeMillis() + initialInterval);
+ clickListener.onClick(view);
+ return true;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_OUTSIDE:
+ handler.removeCallbacksAndMessages(downView);
+ downView = null;
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/StaticEmojiconGroup.java b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/StaticEmojiconGroup.java
new file mode 100644
index 00000000..ae9a767d
--- /dev/null
+++ b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/StaticEmojiconGroup.java
@@ -0,0 +1,29 @@
+package github.ankushsachdeva.emojicon;
+
+import android.content.Context;
+
+import java.util.List;
+
+/**
+ * Created by aleksandr.naumov on 13.05.2015.
+ */
+class StaticEmojiconGroup extends EmojiconGroup {
+ private final List<Emojicon> mEmojicons;
+
+ public StaticEmojiconGroup(List<Emojicon> emojicons, int iconResId) {
+ super(iconResId);
+ mEmojicons = emojicons;
+ }
+
+ @Override
+ public List<Emojicon> getEmojicons() {
+ return mEmojicons;
+ }
+
+ @Override
+ public EmojiAdapter createAdapter(Context context) {
+ EmojiAdapter adapter = new EmojiAdapter(context);
+ adapter.setEmojiconList(getEmojicons());
+ return adapter;
+ }
+}
diff --git a/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/Updatable.java b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/Updatable.java
new file mode 100644
index 00000000..04ce9f11
--- /dev/null
+++ b/libs/emojicon/src/main/java/github/ankushsachdeva/emojicon/Updatable.java
@@ -0,0 +1,8 @@
+package github.ankushsachdeva.emojicon;
+
+/**
+ * Created by aleksandr.naumov on 14.05.2015.
+ */
+interface Updatable {
+ void update();
+}