1
0
mirror of https://github.com/KokaKiwi/BarInsta synced 2024-11-22 14:47:29 +00:00

Convert Emoji parsing utils to kotlin. austinhuang0131/barinsta#1311

This commit is contained in:
Ammar Githam 2021-05-24 08:45:41 +09:00
parent 2ac05569e1
commit d611006438
13 changed files with 160 additions and 196 deletions

View File

@ -184,7 +184,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
getSupportFragmentManager().addOnBackStackChangedListener(this); getSupportFragmentManager().addOnBackStackChangedListener(this);
// Initialise the internal map // Initialise the internal map
AppExecutors.INSTANCE.getTasksThread().execute(() -> { AppExecutors.INSTANCE.getTasksThread().execute(() -> {
EmojiParser.setup(this); EmojiParser.Companion.getInstance(this);
EmojiVariantManager.getInstance(); EmojiVariantManager.getInstance();
}); });
initEmojiCompat(); initEmojiCompat();

View File

@ -31,7 +31,7 @@ public class DirectReactionViewHolder extends RecyclerView.ViewHolder {
this.onReactionClickListener = onReactionClickListener; this.onReactionClickListener = onReactionClickListener;
binding.info.setVisibility(View.GONE); binding.info.setVisibility(View.GONE);
binding.secondaryImage.setVisibility(View.VISIBLE); binding.secondaryImage.setVisibility(View.VISIBLE);
emojiParser = EmojiParser.getInstance(); emojiParser = EmojiParser.Companion.getInstance(itemView.getContext());
} }
public void bind(final DirectItemEmojiReaction reaction, public void bind(final DirectItemEmojiReaction reaction,

View File

@ -80,7 +80,7 @@ public class DirectItemContextMenu extends PopupWindow {
if (!showReactions && (options == null || options.isEmpty())) { if (!showReactions && (options == null || options.isEmpty())) {
throw new IllegalArgumentException("showReactions is set false and options are empty"); throw new IllegalArgumentException("showReactions is set false and options are empty");
} }
reactionsManager = ReactionsManager.getInstance(); reactionsManager = ReactionsManager.getInstance(context);
final Resources resources = context.getResources(); final Resources resources = context.getResources();
emojiSize = resources.getDimensionPixelSize(R.dimen.reaction_picker_emoji_size); emojiSize = resources.getDimensionPixelSize(R.dimen.reaction_picker_emoji_size);
emojiMargin = resources.getDimensionPixelSize(R.dimen.reaction_picker_emoji_margin); emojiMargin = resources.getDimensionPixelSize(R.dimen.reaction_picker_emoji_margin);

View File

@ -20,6 +20,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import awais.instagrabber.R; import awais.instagrabber.R;
import awais.instagrabber.customviews.helpers.GridSpacingItemDecoration; import awais.instagrabber.customviews.helpers.GridSpacingItemDecoration;
import awais.instagrabber.utils.Utils; import awais.instagrabber.utils.Utils;
import awais.instagrabber.utils.emoji.EmojiParser;
public class EmojiBottomSheetDialog extends BottomSheetDialogFragment { public class EmojiBottomSheetDialog extends BottomSheetDialogFragment {
public static final String TAG = EmojiBottomSheetDialog.class.getSimpleName(); public static final String TAG = EmojiBottomSheetDialog.class.getSimpleName();
@ -89,7 +90,8 @@ public class EmojiBottomSheetDialog extends BottomSheetDialogFragment {
grid.setHasFixedSize(true); grid.setHasFixedSize(true);
grid.setClipToPadding(false); grid.setClipToPadding(false);
grid.addItemDecoration(new GridSpacingItemDecoration(Utils.convertDpToPx(8))); grid.addItemDecoration(new GridSpacingItemDecoration(Utils.convertDpToPx(8)));
final EmojiGridAdapter adapter = new EmojiGridAdapter(null, (view, emoji) -> { final EmojiParser emojiParser = EmojiParser.Companion.getInstance(context);
final EmojiGridAdapter adapter = new EmojiGridAdapter(emojiParser, null, (view, emoji) -> {
if (callback != null) { if (callback != null) {
callback.onClick(view, emoji); callback.onClick(view, emoji);
} }

View File

@ -6,12 +6,14 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import awais.instagrabber.customviews.emoji.EmojiPicker.OnEmojiClickListener; import awais.instagrabber.customviews.emoji.EmojiPicker.OnEmojiClickListener;
import awais.instagrabber.utils.emoji.EmojiParser;
public class EmojiCategoryPageViewHolder extends RecyclerView.ViewHolder { public class EmojiCategoryPageViewHolder extends RecyclerView.ViewHolder {
// private static final String TAG = EmojiCategoryPageViewHolder.class.getSimpleName(); // private static final String TAG = EmojiCategoryPageViewHolder.class.getSimpleName();
private final View rootView; private final View rootView;
private final OnEmojiClickListener onEmojiClickListener; private final OnEmojiClickListener onEmojiClickListener;
private final EmojiParser emojiParser = EmojiParser.Companion.getInstance(itemView.getContext());
public EmojiCategoryPageViewHolder(@NonNull final View rootView, public EmojiCategoryPageViewHolder(@NonNull final View rootView,
@NonNull final RecyclerView itemView, @NonNull final RecyclerView itemView,
@ -24,6 +26,7 @@ public class EmojiCategoryPageViewHolder extends RecyclerView.ViewHolder {
public void bind(final EmojiCategory emojiCategory) { public void bind(final EmojiCategory emojiCategory) {
final RecyclerView emojiGrid = (RecyclerView) itemView; final RecyclerView emojiGrid = (RecyclerView) itemView;
final EmojiGridAdapter adapter = new EmojiGridAdapter( final EmojiGridAdapter adapter = new EmojiGridAdapter(
emojiParser,
emojiCategory.getType(), emojiCategory.getType(),
onEmojiClickListener, onEmojiClickListener,
(position, view, parent) -> { (position, view, parent) -> {

View File

@ -43,14 +43,14 @@ public class EmojiGridAdapter extends RecyclerView.Adapter<EmojiGridAdapter.Emoj
private final EmojiVariantManager emojiVariantManager; private final EmojiVariantManager emojiVariantManager;
private final AppExecutors appExecutors; private final AppExecutors appExecutors;
public EmojiGridAdapter(final EmojiCategoryType emojiCategoryType, public EmojiGridAdapter(@NonNull final EmojiParser emojiParser,
final EmojiCategoryType emojiCategoryType,
final OnEmojiClickListener onEmojiClickListener, final OnEmojiClickListener onEmojiClickListener,
final OnEmojiLongClickListener onEmojiLongClickListener) { final OnEmojiLongClickListener onEmojiLongClickListener) {
this.onEmojiClickListener = onEmojiClickListener; this.onEmojiClickListener = onEmojiClickListener;
this.onEmojiLongClickListener = onEmojiLongClickListener; this.onEmojiLongClickListener = onEmojiLongClickListener;
differ = new AsyncListDiffer<>(new AdapterListUpdateCallback(this), differ = new AsyncListDiffer<>(new AdapterListUpdateCallback(this),
new AsyncDifferConfig.Builder<>(diffCallback).build()); new AsyncDifferConfig.Builder<>(diffCallback).build());
final EmojiParser emojiParser = EmojiParser.getInstance();
final Map<EmojiCategoryType, EmojiCategory> categoryMap = emojiParser.getCategoryMap(); final Map<EmojiCategoryType, EmojiCategory> categoryMap = emojiParser.getCategoryMap();
emojiVariantManager = EmojiVariantManager.getInstance(); emojiVariantManager = EmojiVariantManager.getInstance();
appExecutors = AppExecutors.INSTANCE; appExecutors = AppExecutors.INSTANCE;

View File

@ -67,7 +67,9 @@ public class EmojiPicker extends LinearLayout {
viewPager2.setAdapter(new EmojiPickerPageAdapter(rootView, onEmojiClickListener)); viewPager2.setAdapter(new EmojiPickerPageAdapter(rootView, onEmojiClickListener));
viewPager2.setOffscreenPageLimit(1); viewPager2.setOffscreenPageLimit(1);
final EmojiParser emojiParser = EmojiParser.getInstance(); final Context context = getContext();
if (context == null) return;
final EmojiParser emojiParser = EmojiParser.Companion.getInstance(context);
final List<EmojiCategory> categories = emojiParser.getEmojiCategories(); final List<EmojiCategory> categories = emojiParser.getEmojiCategories();
new TabLayoutMediator(tabLayout, viewPager2, (tab, position) -> { new TabLayoutMediator(tabLayout, viewPager2, (tab, position) -> {

View File

@ -37,13 +37,14 @@ public class EmojiPickerPageAdapter extends RecyclerView.Adapter<EmojiCategoryPa
private final OnEmojiClickListener onEmojiClickListener; private final OnEmojiClickListener onEmojiClickListener;
private final AsyncListDiffer<EmojiCategory> differ; private final AsyncListDiffer<EmojiCategory> differ;
public EmojiPickerPageAdapter(final View rootView, public EmojiPickerPageAdapter(@NonNull final View rootView,
final OnEmojiClickListener onEmojiClickListener) { final OnEmojiClickListener onEmojiClickListener) {
this.rootView = rootView; this.rootView = rootView;
this.onEmojiClickListener = onEmojiClickListener; this.onEmojiClickListener = onEmojiClickListener;
differ = new AsyncListDiffer<>(new AdapterListUpdateCallback(this), differ = new AsyncListDiffer<>(new AdapterListUpdateCallback(this),
new AsyncDifferConfig.Builder<>(diffCallback).build()); new AsyncDifferConfig.Builder<>(diffCallback).build());
differ.submitList(EmojiParser.getInstance().getEmojiCategories()); final EmojiParser emojiParser = EmojiParser.Companion.getInstance(rootView.getContext());
differ.submitList(emojiParser.getEmojiCategories());
setHasStableIds(true); setHasStableIds(true);
} }

View File

@ -1,7 +1,10 @@
package awais.instagrabber.customviews.emoji; package awais.instagrabber.customviews.emoji;
import android.content.Context;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import org.json.JSONArray; import org.json.JSONArray;
@ -26,24 +29,24 @@ public class ReactionsManager {
private static ReactionsManager instance; private static ReactionsManager instance;
public static ReactionsManager getInstance() { public static ReactionsManager getInstance(@NonNull final Context context) {
if (instance == null) { if (instance == null) {
synchronized (LOCK) { synchronized (LOCK) {
if (instance == null) { if (instance == null) {
instance = new ReactionsManager(); instance = new ReactionsManager(context);
} }
} }
} }
return instance; return instance;
} }
private ReactionsManager() { private ReactionsManager(@NonNull final Context context) {
final EmojiParser emojiParser = EmojiParser.Companion.getInstance(context);
String reactionsJson = Utils.settingsHelper.getString(PREF_REACTIONS); String reactionsJson = Utils.settingsHelper.getString(PREF_REACTIONS);
if (TextUtils.isEmpty(reactionsJson)) { if (TextUtils.isEmpty(reactionsJson)) {
final ImmutableList<String> list = ImmutableList.of("❤️", "\uD83D\uDE02", "\uD83D\uDE2E", "\uD83D\uDE22", "\uD83D\uDE21", "\uD83D\uDC4D"); final ImmutableList<String> list = ImmutableList.of("❤️", "\uD83D\uDE02", "\uD83D\uDE2E", "\uD83D\uDE22", "\uD83D\uDE21", "\uD83D\uDC4D");
reactionsJson = new JSONArray(list).toString(); reactionsJson = new JSONArray(list).toString();
} }
final EmojiParser emojiParser = EmojiParser.getInstance();
final Map<String, Emoji> allEmojis = emojiParser.getAllEmojis(); final Map<String, Emoji> allEmojis = emojiParser.getAllEmojis();
try { try {
final JSONArray reactionsJsonArray = new JSONArray(reactionsJson); final JSONArray reactionsJsonArray = new JSONArray(reactionsJson);

View File

@ -0,0 +1,27 @@
package awais.instagrabber.utils
open class SingletonHolder<out T : Any, in A>(creator: (A) -> T) {
private var creator: ((A) -> T)? = creator
@Volatile
private var instance: T? = null
fun getInstance(arg: A): T {
val i = instance
if (i != null) {
return i
}
return synchronized(this) {
val i2 = instance
if (i2 != null) {
i2
} else {
val created = creator!!(arg)
instance = created
creator = null
created
}
}
}
}

View File

@ -1,52 +1,44 @@
package awais.instagrabber.utils.emoji; package awais.instagrabber.utils.emoji
import android.util.Log; import android.util.Log
import awais.instagrabber.customviews.emoji.Emoji
import awais.instagrabber.customviews.emoji.EmojiCategory
import awais.instagrabber.customviews.emoji.EmojiCategoryType
import awais.instagrabber.utils.extensions.TAG
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonParseException
import java.lang.reflect.Type
import com.google.gson.JsonDeserializationContext; class EmojiCategoryDeserializer : JsonDeserializer<EmojiCategory> {
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type; @Throws(JsonParseException::class)
import java.util.LinkedHashMap; override fun deserialize(
import java.util.Map; json: JsonElement,
typeOfT: Type,
import awais.instagrabber.customviews.emoji.Emoji; context: JsonDeserializationContext
import awais.instagrabber.customviews.emoji.EmojiCategory; ): EmojiCategory {
import awais.instagrabber.customviews.emoji.EmojiCategoryType; val jsonObject = json.asJsonObject
val typeElement = jsonObject["type"]
public class EmojiCategoryDeserializer implements JsonDeserializer<EmojiCategory> { val emojisObject = jsonObject.getAsJsonObject("emojis")
private static final String TAG = EmojiCategoryDeserializer.class.getSimpleName();
@Override
public EmojiCategory deserialize(final JsonElement json,
final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
final JsonObject jsonObject = json.getAsJsonObject();
final JsonElement typeElement = jsonObject.get("type");
final JsonObject emojisObject = jsonObject.getAsJsonObject("emojis");
if (typeElement == null || emojisObject == null) { if (typeElement == null || emojisObject == null) {
throw new JsonParseException("Invalid json for EmojiCategory"); throw JsonParseException("Invalid json for EmojiCategory")
} }
final String typeString = typeElement.getAsString(); val typeString = typeElement.asString
EmojiCategoryType type; val type: EmojiCategoryType = try {
try { EmojiCategoryType.valueOf(typeString)
type = EmojiCategoryType.valueOf(typeString); } catch (e: IllegalArgumentException) {
} catch (IllegalArgumentException e) { Log.e(TAG, "deserialize: ", e)
Log.e(TAG, "deserialize: ", e); EmojiCategoryType.OTHERS
type = EmojiCategoryType.OTHERS;
} }
final Map<String, Emoji> emojis = new LinkedHashMap<>(); val emojis: MutableMap<String, Emoji> = linkedMapOf()
for (final Map.Entry<String, JsonElement> emojiObjectEntry : emojisObject.entrySet()) { for ((unicode, value) in emojisObject.entrySet()) {
final String unicode = emojiObjectEntry.getKey();
final JsonElement value = emojiObjectEntry.getValue();
if (unicode == null || value == null) { if (unicode == null || value == null) {
throw new JsonParseException("Invalid json for EmojiCategory"); throw JsonParseException("Invalid json for EmojiCategory")
} }
final Emoji emoji = context.deserialize(value, Emoji.class); emojis[unicode] = context.deserialize(value, Emoji::class.java)
emojis.put(unicode, emoji);
} }
return new EmojiCategory(type, emojis); return EmojiCategory(type, emojis)
} }
} }

View File

@ -1,44 +1,40 @@
package awais.instagrabber.utils.emoji; package awais.instagrabber.utils.emoji
import com.google.gson.JsonArray; import awais.instagrabber.customviews.emoji.Emoji
import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer; import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement; import com.google.gson.JsonElement
import com.google.gson.JsonObject; import com.google.gson.JsonParseException
import com.google.gson.JsonParseException; import java.lang.reflect.Type
import java.lang.reflect.Type; class EmojiDeserializer : JsonDeserializer<Emoji> {
import java.util.LinkedList; @Throws(JsonParseException::class)
import java.util.List; override fun deserialize(
json: JsonElement,
import awais.instagrabber.customviews.emoji.Emoji; typeOfT: Type,
context: JsonDeserializationContext
public class EmojiDeserializer implements JsonDeserializer<Emoji> { ): Emoji {
@Override val jsonObject = json.asJsonObject
public Emoji deserialize(final JsonElement json, val unicodeElement = jsonObject["unicode"]
final Type typeOfT, val nameElement = jsonObject["name"]
final JsonDeserializationContext context) throws JsonParseException {
final JsonObject jsonObject = json.getAsJsonObject();
final JsonElement unicodeElement = jsonObject.get("unicode");
final JsonElement nameElement = jsonObject.get("name");
if (unicodeElement == null || nameElement == null) { if (unicodeElement == null || nameElement == null) {
throw new JsonParseException("Invalid json for Emoji class"); throw JsonParseException("Invalid json for Emoji class")
} }
final JsonElement variantsElement = jsonObject.get("variants"); val variantsElement = jsonObject["variants"]
final List<Emoji> variants = new LinkedList<>(); val variants: MutableList<Emoji> = mutableListOf()
if (variantsElement != null) { if (variantsElement != null) {
final JsonArray variantsArray = variantsElement.getAsJsonArray(); val variantsArray = variantsElement.asJsonArray
for (final JsonElement variantElement : variantsArray) { for (variantElement in variantsArray) {
final Emoji variant = context.deserialize(variantElement, Emoji.class); val variant = context.deserialize<Emoji>(variantElement, Emoji::class.java)
if (variant != null) { if (variant != null) {
variants.add(variant); variants.add(variant)
} }
} }
} }
return new Emoji( return Emoji(
unicodeElement.getAsString(), unicodeElement.asString,
nameElement.getAsString(), nameElement.asString,
variants variants
); )
} }
} }

View File

@ -1,115 +1,53 @@
package awais.instagrabber.utils.emoji; package awais.instagrabber.utils.emoji
import android.content.Context; import android.content.Context
import android.util.Log; import android.util.Log
import awais.instagrabber.R
import awais.instagrabber.customviews.emoji.Emoji
import awais.instagrabber.customviews.emoji.EmojiCategory
import awais.instagrabber.customviews.emoji.EmojiCategoryType
import awais.instagrabber.utils.NetworkUtils
import awais.instagrabber.utils.SingletonHolder
import awais.instagrabber.utils.extensions.TAG
import com.google.gson.FieldNamingPolicy
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import androidx.annotation.NonNull; class EmojiParser private constructor(context: Context) {
var allEmojis: Map<String, Emoji> = emptyMap()
import com.google.common.collect.ImmutableList; var categoryMap: Map<EmojiCategoryType, EmojiCategory> = emptyMap()
import com.google.gson.FieldNamingPolicy; val emojiCategories: List<EmojiCategory> by lazy {
import com.google.gson.Gson; categoryMap.values.toList()
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import awais.instagrabber.R;
import awais.instagrabber.customviews.emoji.Emoji;
import awais.instagrabber.customviews.emoji.EmojiCategory;
import awais.instagrabber.customviews.emoji.EmojiCategoryType;
import awais.instagrabber.utils.NetworkUtils;
public final class EmojiParser {
private static final String TAG = EmojiParser.class.getSimpleName();
private static final Object LOCK = new Object();
private static EmojiParser instance;
private Map<String, Emoji> allEmojis = Collections.emptyMap();
private Map<EmojiCategoryType, EmojiCategory> categoryMap = Collections.emptyMap();
private ImmutableList<EmojiCategory> categories;
public static void setup(@NonNull final Context context) {
if (instance == null) {
synchronized (LOCK) {
if (instance == null) {
instance = new EmojiParser(context);
}
}
}
} }
public static EmojiParser getInstance() { fun getEmoji(emoji: String): Emoji? {
if (instance == null) { return allEmojis[emoji]
throw new RuntimeException("Setup not done!");
}
return instance;
} }
private EmojiParser(final Context context) { init {
try (final InputStream in = context.getResources().openRawResource(R.raw.emojis)) { try {
final String json = NetworkUtils.readFromInputStream(in); context.applicationContext.resources.openRawResource(R.raw.emojis).use { `in` ->
final Gson gson = new GsonBuilder() val json = NetworkUtils.readFromInputStream(`in`)
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) val gson = GsonBuilder().apply {
.registerTypeAdapter(EmojiCategory.class, new EmojiCategoryDeserializer()) setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.registerTypeAdapter(Emoji.class, new EmojiDeserializer()) registerTypeAdapter(EmojiCategory::class.java, EmojiCategoryDeserializer())
.setLenient() registerTypeAdapter(Emoji::class.java, EmojiDeserializer())
.create(); setLenient()
final Type type = new TypeToken<Map<EmojiCategoryType, EmojiCategory>>() {}.getType(); }.create()
categoryMap = gson.fromJson(json, type); val type = object : TypeToken<Map<EmojiCategoryType, EmojiCategory>>() {}.type
categoryMap = gson.fromJson(json, type)
// Log.d(TAG, "EmojiParser: " + categoryMap); // Log.d(TAG, "EmojiParser: " + categoryMap);
allEmojis = categoryMap.values() allEmojis = categoryMap
.stream() .flatMap { (_, emojiCategory) -> emojiCategory.emojis.values }
.flatMap((Function<EmojiCategory, Stream<Emoji>>) emojiCategory -> { .flatMap { listOf(it) + it.variants }
final Map<String, Emoji> emojis = emojiCategory.getEmojis(); .filterNotNull()
return emojis.values().stream(); .map { it.unicode to it }
}) .toMap()
.flatMap(emoji -> ImmutableList.<Emoji>builder() }
.add(emoji) } catch (e: Exception) {
.addAll(emoji.getVariants()) Log.e(TAG, "EmojiParser: ", e)
.build()
.stream())
.collect(Collectors.toMap(
Emoji::getUnicode,
Function.identity(),
(u, v) -> u,
LinkedHashMap::new
));
} catch (Exception e) {
Log.e(TAG, "EmojiParser: ", e);
} }
} }
public Map<EmojiCategoryType, EmojiCategory> getCategoryMap() { companion object : SingletonHolder<EmojiParser, Context>(::EmojiParser)
return categoryMap;
} }
public List<EmojiCategory> getEmojiCategories() {
if (categories == null) {
final Collection<EmojiCategory> categoryCollection = categoryMap.values();
categories = ImmutableList.copyOf(categoryCollection);
}
return categories;
}
public Map<String, Emoji> getAllEmojis() {
return allEmojis;
}
public Emoji getEmoji(final String emoji) {
if (emoji == null) {
return null;
}
return allEmojis.get(emoji);
}
}