Browse Source
Convert Emoji parsing utils to kotlin. austinhuang0131/barinsta#1311
renovate/org.robolectric-robolectric-4.x
Convert Emoji parsing utils to kotlin. austinhuang0131/barinsta#1311
renovate/org.robolectric-robolectric-4.x
Ammar Githam
4 years ago
13 changed files with 161 additions and 197 deletions
-
2app/src/main/java/awais/instagrabber/activities/MainActivity.java
-
2app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectReactionViewHolder.java
-
2app/src/main/java/awais/instagrabber/customviews/DirectItemContextMenu.java
-
4app/src/main/java/awais/instagrabber/customviews/emoji/EmojiBottomSheetDialog.java
-
3app/src/main/java/awais/instagrabber/customviews/emoji/EmojiCategoryPageViewHolder.java
-
4app/src/main/java/awais/instagrabber/customviews/emoji/EmojiGridAdapter.java
-
4app/src/main/java/awais/instagrabber/customviews/emoji/EmojiPicker.java
-
5app/src/main/java/awais/instagrabber/customviews/emoji/EmojiPickerPageAdapter.java
-
11app/src/main/java/awais/instagrabber/customviews/emoji/ReactionsManager.java
-
27app/src/main/java/awais/instagrabber/utils/SingletonHolder.kt
-
74app/src/main/java/awais/instagrabber/utils/emoji/EmojiCategoryDeserializer.kt
-
60app/src/main/java/awais/instagrabber/utils/emoji/EmojiDeserializer.kt
-
156app/src/main/java/awais/instagrabber/utils/emoji/EmojiParser.kt
@ -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 |
|||
} |
|||
} |
|||
} |
|||
} |
@ -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; |
|||
import com.google.gson.JsonDeserializer; |
|||
import com.google.gson.JsonElement; |
|||
import com.google.gson.JsonObject; |
|||
import com.google.gson.JsonParseException; |
|||
class EmojiCategoryDeserializer : JsonDeserializer<EmojiCategory> { |
|||
|
|||
import java.lang.reflect.Type; |
|||
import java.util.LinkedHashMap; |
|||
import java.util.Map; |
|||
|
|||
import awais.instagrabber.customviews.emoji.Emoji; |
|||
import awais.instagrabber.customviews.emoji.EmojiCategory; |
|||
import awais.instagrabber.customviews.emoji.EmojiCategoryType; |
|||
|
|||
public class EmojiCategoryDeserializer implements JsonDeserializer<EmojiCategory> { |
|||
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"); |
|||
@Throws(JsonParseException::class) |
|||
override fun deserialize( |
|||
json: JsonElement, |
|||
typeOfT: Type, |
|||
context: JsonDeserializationContext |
|||
): EmojiCategory { |
|||
val jsonObject = json.asJsonObject |
|||
val typeElement = jsonObject["type"] |
|||
val emojisObject = jsonObject.getAsJsonObject("emojis") |
|||
if (typeElement == null || emojisObject == null) { |
|||
throw new JsonParseException("Invalid json for EmojiCategory"); |
|||
throw JsonParseException("Invalid json for EmojiCategory") |
|||
} |
|||
final String typeString = typeElement.getAsString(); |
|||
EmojiCategoryType type; |
|||
try { |
|||
type = EmojiCategoryType.valueOf(typeString); |
|||
} catch (IllegalArgumentException e) { |
|||
Log.e(TAG, "deserialize: ", e); |
|||
type = EmojiCategoryType.OTHERS; |
|||
val typeString = typeElement.asString |
|||
val type: EmojiCategoryType = try { |
|||
EmojiCategoryType.valueOf(typeString) |
|||
} catch (e: IllegalArgumentException) { |
|||
Log.e(TAG, "deserialize: ", e) |
|||
EmojiCategoryType.OTHERS |
|||
} |
|||
final Map<String, Emoji> emojis = new LinkedHashMap<>(); |
|||
for (final Map.Entry<String, JsonElement> emojiObjectEntry : emojisObject.entrySet()) { |
|||
final String unicode = emojiObjectEntry.getKey(); |
|||
final JsonElement value = emojiObjectEntry.getValue(); |
|||
val emojis: MutableMap<String, Emoji> = linkedMapOf() |
|||
for ((unicode, value) in emojisObject.entrySet()) { |
|||
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.put(unicode, emoji); |
|||
emojis[unicode] = context.deserialize(value, Emoji::class.java) |
|||
} |
|||
return new EmojiCategory(type, emojis); |
|||
return EmojiCategory(type, emojis) |
|||
} |
|||
} |
@ -1,44 +1,40 @@ |
|||
package awais.instagrabber.utils.emoji; |
|||
package awais.instagrabber.utils.emoji |
|||
|
|||
import com.google.gson.JsonArray; |
|||
import com.google.gson.JsonDeserializationContext; |
|||
import com.google.gson.JsonDeserializer; |
|||
import com.google.gson.JsonElement; |
|||
import com.google.gson.JsonObject; |
|||
import com.google.gson.JsonParseException; |
|||
import awais.instagrabber.customviews.emoji.Emoji |
|||
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 java.lang.reflect.Type; |
|||
import java.util.LinkedList; |
|||
import java.util.List; |
|||
|
|||
import awais.instagrabber.customviews.emoji.Emoji; |
|||
|
|||
public class EmojiDeserializer implements JsonDeserializer<Emoji> { |
|||
@Override |
|||
public Emoji deserialize(final JsonElement json, |
|||
final Type typeOfT, |
|||
final JsonDeserializationContext context) throws JsonParseException { |
|||
final JsonObject jsonObject = json.getAsJsonObject(); |
|||
final JsonElement unicodeElement = jsonObject.get("unicode"); |
|||
final JsonElement nameElement = jsonObject.get("name"); |
|||
class EmojiDeserializer : JsonDeserializer<Emoji> { |
|||
@Throws(JsonParseException::class) |
|||
override fun deserialize( |
|||
json: JsonElement, |
|||
typeOfT: Type, |
|||
context: JsonDeserializationContext |
|||
): Emoji { |
|||
val jsonObject = json.asJsonObject |
|||
val unicodeElement = jsonObject["unicode"] |
|||
val nameElement = jsonObject["name"] |
|||
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"); |
|||
final List<Emoji> variants = new LinkedList<>(); |
|||
val variantsElement = jsonObject["variants"] |
|||
val variants: MutableList<Emoji> = mutableListOf() |
|||
if (variantsElement != null) { |
|||
final JsonArray variantsArray = variantsElement.getAsJsonArray(); |
|||
for (final JsonElement variantElement : variantsArray) { |
|||
final Emoji variant = context.deserialize(variantElement, Emoji.class); |
|||
val variantsArray = variantsElement.asJsonArray |
|||
for (variantElement in variantsArray) { |
|||
val variant = context.deserialize<Emoji>(variantElement, Emoji::class.java) |
|||
if (variant != null) { |
|||
variants.add(variant); |
|||
variants.add(variant) |
|||
} |
|||
} |
|||
} |
|||
return new Emoji( |
|||
unicodeElement.getAsString(), |
|||
nameElement.getAsString(), |
|||
return Emoji( |
|||
unicodeElement.asString, |
|||
nameElement.asString, |
|||
variants |
|||
); |
|||
) |
|||
} |
|||
} |
@ -1,115 +1,53 @@ |
|||
package awais.instagrabber.utils.emoji; |
|||
|
|||
import android.content.Context; |
|||
import android.util.Log; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
|
|||
import com.google.common.collect.ImmutableList; |
|||
import com.google.gson.FieldNamingPolicy; |
|||
import com.google.gson.Gson; |
|||
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() { |
|||
if (instance == null) { |
|||
throw new RuntimeException("Setup not done!"); |
|||
} |
|||
return instance; |
|||
} |
|||
|
|||
private EmojiParser(final Context context) { |
|||
try (final InputStream in = context.getResources().openRawResource(R.raw.emojis)) { |
|||
final String json = NetworkUtils.readFromInputStream(in); |
|||
final Gson gson = new GsonBuilder() |
|||
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) |
|||
.registerTypeAdapter(EmojiCategory.class, new EmojiCategoryDeserializer()) |
|||
.registerTypeAdapter(Emoji.class, new EmojiDeserializer()) |
|||
.setLenient() |
|||
.create(); |
|||
final Type type = new TypeToken<Map<EmojiCategoryType, EmojiCategory>>() {}.getType(); |
|||
categoryMap = gson.fromJson(json, type); |
|||
package awais.instagrabber.utils.emoji |
|||
|
|||
import android.content.Context |
|||
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 |
|||
|
|||
class EmojiParser private constructor(context: Context) { |
|||
var allEmojis: Map<String, Emoji> = emptyMap() |
|||
var categoryMap: Map<EmojiCategoryType, EmojiCategory> = emptyMap() |
|||
val emojiCategories: List<EmojiCategory> by lazy { |
|||
categoryMap.values.toList() |
|||
} |
|||
|
|||
fun getEmoji(emoji: String): Emoji? { |
|||
return allEmojis[emoji] |
|||
} |
|||
|
|||
init { |
|||
try { |
|||
context.applicationContext.resources.openRawResource(R.raw.emojis).use { `in` -> |
|||
val json = NetworkUtils.readFromInputStream(`in`) |
|||
val gson = GsonBuilder().apply { |
|||
setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) |
|||
registerTypeAdapter(EmojiCategory::class.java, EmojiCategoryDeserializer()) |
|||
registerTypeAdapter(Emoji::class.java, EmojiDeserializer()) |
|||
setLenient() |
|||
}.create() |
|||
val type = object : TypeToken<Map<EmojiCategoryType, EmojiCategory>>() {}.type |
|||
categoryMap = gson.fromJson(json, type) |
|||
// Log.d(TAG, "EmojiParser: " + categoryMap); |
|||
allEmojis = categoryMap.values() |
|||
.stream() |
|||
.flatMap((Function<EmojiCategory, Stream<Emoji>>) emojiCategory -> { |
|||
final Map<String, Emoji> emojis = emojiCategory.getEmojis(); |
|||
return emojis.values().stream(); |
|||
}) |
|||
.flatMap(emoji -> ImmutableList.<Emoji>builder() |
|||
.add(emoji) |
|||
.addAll(emoji.getVariants()) |
|||
.build() |
|||
.stream()) |
|||
.collect(Collectors.toMap( |
|||
Emoji::getUnicode, |
|||
Function.identity(), |
|||
(u, v) -> u, |
|||
LinkedHashMap::new |
|||
)); |
|||
} catch (Exception e) { |
|||
Log.e(TAG, "EmojiParser: ", e); |
|||
allEmojis = categoryMap |
|||
.flatMap { (_, emojiCategory) -> emojiCategory.emojis.values } |
|||
.flatMap { listOf(it) + it.variants } |
|||
.filterNotNull() |
|||
.map { it.unicode to it } |
|||
.toMap() |
|||
} |
|||
} catch (e: Exception) { |
|||
Log.e(TAG, "EmojiParser: ", e) |
|||
} |
|||
|
|||
public Map<EmojiCategoryType, EmojiCategory> getCategoryMap() { |
|||
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); |
|||
} |
|||
companion object : SingletonHolder<EmojiParser, Context>(::EmojiParser) |
|||
} |
|||
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue