diff --git a/res/layout/emoji_drawer.xml b/res/layout/emoji_drawer.xml index ee12dbb0ad..900ff47aa3 100644 --- a/res/layout/emoji_drawer.xml +++ b/res/layout/emoji_drawer.xml @@ -11,6 +11,7 @@ android:visibility="visible" android:layout_width="match_parent" android:layout_height="match_parent" + android:background="#ff333333" android:minHeight="100dip"> <android.support.v4.view.PagerTabStrip @@ -18,7 +19,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" - android:background="#33b5e5" + android:background="#ff333333" android:textColor="#fff" android:paddingTop="3dp" android:paddingBottom="3dp" diff --git a/src/org/thoughtcrime/securesms/components/EmojiDrawer.java b/src/org/thoughtcrime/securesms/components/EmojiDrawer.java index f986d647b0..c936facd4e 100644 --- a/src/org/thoughtcrime/securesms/components/EmojiDrawer.java +++ b/src/org/thoughtcrime/securesms/components/EmojiDrawer.java @@ -1,7 +1,6 @@ package org.thoughtcrime.securesms.components; import android.content.Context; -import android.graphics.Color; import android.graphics.drawable.Drawable; import android.support.v4.view.PagerAdapter; import android.support.v4.view.PagerTabStrip; @@ -24,16 +23,19 @@ import android.widget.TextView; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.util.Emoji; -import java.io.File; -import java.io.IOException; - public class EmojiDrawer extends FrameLayout { + private static final int RECENT_TYPE = 0; + private static final int ALL_TYPE = 1; + private FrameLayout emojiGridLayout; private FrameLayout recentEmojiGridLayout; - private EditText composeText; private Emoji emoji; + private GridView emojiGrid; + private GridView recentEmojiGrid; + private ViewPager pager; + private PagerTabStrip pagerTabStrip; public EmojiDrawer(Context context) { super(context); @@ -59,32 +61,54 @@ public class EmojiDrawer extends FrameLayout { } private void initialize() { - this.emoji = Emoji.getInstance(getContext()); LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.emoji_drawer, this, true); - ViewPager pager = (ViewPager ) findViewById(R.id.emoji_pager ); - PagerTabStrip pagerTabStrip = (PagerTabStrip) findViewById(R.id.emoji_tab_strip); - this.emojiGridLayout = (FrameLayout) inflater.inflate(R.layout.emoji_grid_layout, null); - this.recentEmojiGridLayout = (FrameLayout) inflater.inflate(R.layout.emoji_grid_layout, null); - GridView emojiGrid = (GridView) emojiGridLayout.findViewById(R.id.emoji); - GridView recentEmojiGrid = (GridView) recentEmojiGridLayout.findViewById(R.id.emoji); - - pagerTabStrip.setBackgroundColor(Color.parseColor("#ff333333")); - pagerTabStrip.setTextSpacing(1); - pager.setBackgroundColor(Color.parseColor("#ff333333")); - emojiGrid.setAdapter(new AllEmojiGridAdapter()); - emojiGrid.setOnItemClickListener(new EmojiClickListener()); + initializeResources(); + initializeEmojiGrid(); + } + + private void initializeResources() { + LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + this.pager = (ViewPager ) findViewById(R.id.emoji_pager ); + this.pagerTabStrip = (PagerTabStrip) findViewById(R.id.emoji_tab_strip); + this.emojiGridLayout = (FrameLayout ) inflater.inflate(R.layout.emoji_grid_layout, null); + this.recentEmojiGridLayout = (FrameLayout ) inflater.inflate(R.layout.emoji_grid_layout, null); + this.emojiGrid = (GridView ) emojiGridLayout.findViewById(R.id.emoji); + this.recentEmojiGrid = (GridView ) recentEmojiGridLayout.findViewById(R.id.emoji); + this.emoji = Emoji.getInstance(getContext()); + } + + private void initializeEmojiGrid() { + emojiGrid.setAdapter(new EmojiGridAdapter(ALL_TYPE)); + emojiGrid.setOnItemClickListener(new EmojiClickListener(ALL_TYPE)); + recentEmojiGrid.setAdapter(new EmojiGridAdapter(RECENT_TYPE)); + recentEmojiGrid.setOnItemClickListener(new EmojiClickListener(RECENT_TYPE)); + pager.setAdapter(new EmojiPagerAdapter()); - pager.setCurrentItem(1); + + if (emoji.getRecentlyUsedAssetCount() <= 0) { + pager.setCurrentItem(1); + } } private class EmojiClickListener implements AdapterView.OnItemClickListener { + + private final int type; + + public EmojiClickListener(int type) { + this.type = type; + } + @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - int start = composeText.getSelectionStart(); - int end = composeText.getSelectionEnd (); - String characters = emoji.getEmojiUnicode(position); + String characters; + + if (type == ALL_TYPE ) characters = emoji.getEmojiUnicode(position); + else characters = emoji.getRecentEmojiUnicode(position); + + int start = composeText.getSelectionStart(); + int end = composeText.getSelectionEnd (); composeText.getText().replace(Math.min(start, end), Math.max(start, end), characters, 0, characters.length()); @@ -93,14 +117,27 @@ public class EmojiDrawer extends FrameLayout { TextView.BufferType.SPANNABLE); composeText.setSelection(end+2); + + if (type != RECENT_TYPE) { + emoji.setRecentlyUsed(position); + ((BaseAdapter)recentEmojiGrid.getAdapter()).notifyDataSetChanged(); + } } } - private class AllEmojiGridAdapter extends BaseAdapter { + private class EmojiGridAdapter extends BaseAdapter { + + private final int type; + + public EmojiGridAdapter(int type) { + this.type = type; + } @Override public int getCount() { - return emoji.getEmojiAssetCount(); + if (type == RECENT_TYPE) return emoji.getRecentlyUsedAssetCount(); + else return emoji.getEmojiAssetCount(); + } @Override @@ -115,7 +152,10 @@ public class EmojiDrawer extends FrameLayout { @Override public View getView(int position, View convertView, ViewGroup parent) { - Drawable drawable = emoji.getEmojiDrawable(position); + Drawable drawable; + + if (type == RECENT_TYPE) drawable = emoji.getRecentlyUsed(position); + else drawable = emoji.getEmojiDrawable(position); if (convertView != null && convertView instanceof ImageView) { ((ImageView)convertView).setImageDrawable(drawable); diff --git a/src/org/thoughtcrime/securesms/util/Emoji.java b/src/org/thoughtcrime/securesms/util/Emoji.java index 32fbab2776..0d40dae26d 100644 --- a/src/org/thoughtcrime/securesms/util/Emoji.java +++ b/src/org/thoughtcrime/securesms/util/Emoji.java @@ -1,16 +1,27 @@ package org.thoughtcrime.securesms.util; import android.content.Context; +import android.content.SharedPreferences; import android.graphics.drawable.Drawable; +import android.preference.PreferenceManager; import android.text.Spannable; import android.text.SpannableString; import android.text.style.ImageSpan; import android.util.Log; +import com.google.thoughtcrimegson.Gson; +import com.google.thoughtcrimegson.reflect.TypeToken; + import java.io.File; import java.io.IOException; +import java.lang.reflect.Type; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -48,9 +59,11 @@ public class Emoji { } public String getEmojiUnicode(int position) { - String hexString = emojiAssets[position].split("\\.")[0]; - Integer unicodePoint = Integer.parseInt(hexString, 16); - return new String(Character.toChars(unicodePoint)); + return getEmojiUnicodeFromAssetName(emojiAssets[position]); + } + + public String getRecentEmojiUnicode(int position) { + return getEmojiUnicodeFromAssetName(EmojiLRU.getRecentlyUsed(context).get(position)); } public Drawable getEmojiDrawable(int position) { @@ -74,7 +87,6 @@ public class Emoji { drawable.setBounds(0, 0, (int)(drawable.getIntrinsicWidth()*size), (int)(drawable.getIntrinsicHeight()*size)); - ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM); text.setSpan(imageSpan, matches.start(), matches.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); @@ -86,6 +98,25 @@ public class Emoji { return text; } + public void setRecentlyUsed(int position) { + String assetName = emojiAssets[position]; + EmojiLRU.putRecentlyUsed(context, assetName); + } + + public int getRecentlyUsedAssetCount() { + return EmojiLRU.getRecentlyUsed(context).size(); + } + + public Drawable getRecentlyUsed(int position) { + return getEmojiDrawable(EmojiLRU.getRecentlyUsed(context).get(position)); + } + + private String getEmojiUnicodeFromAssetName(String assetName) { + String hexString = assetName.split("\\.")[0]; + Integer unicodePoint = Integer.parseInt(hexString, 16); + return new String(Character.toChars(unicodePoint)); + } + private Drawable getEmojiDrawable(String assetName) { try { return Drawable.createFromStream(context.getAssets().open("emoji" + File.separator + assetName), null); @@ -103,4 +134,34 @@ public class Emoji { } } + private static class EmojiLRU { + + private static final String EMOJI_LRU_PREFERENCE = "pref_popular_emoji"; + private static final int EMOJI_LRU_SIZE = 10; + + public static List<String> getRecentlyUsed(Context context) { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); + String serialized = preferences.getString(EMOJI_LRU_PREFERENCE, "[]"); + Type type = new TypeToken<Collection<String>>(){}.getType(); + + return new Gson().fromJson(serialized, type); + } + + public static void putRecentlyUsed(Context context, String asset) { + LinkedHashSet<String> recentlyUsed = new LinkedHashSet<String>(getRecentlyUsed(context)); + recentlyUsed.add(asset); + + if (recentlyUsed.size() > 10) { + Iterator<String> iterator = recentlyUsed.iterator(); + iterator.next(); + iterator.remove(); + } + + String serialized = new Gson().toJson(recentlyUsed); + PreferenceManager.getDefaultSharedPreferences(context) + .edit() + .putString(EMOJI_LRU_PREFERENCE, serialized) + .commit(); + } + } }