Commit d8543723 authored by Leonardo Aramaki's avatar Leonardo Aramaki

Fix some errors during saving and retrieval of data from Room. This fixes tone selection

parent 30b52d33
...@@ -33,7 +33,6 @@ import chat.rocket.common.RocketChatException ...@@ -33,7 +33,6 @@ import chat.rocket.common.RocketChatException
import chat.rocket.common.model.UserStatus import chat.rocket.common.model.UserStatus
import chat.rocket.common.util.ifNull import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.realtime.setDefaultStatus
import chat.rocket.core.internal.rest.getCustomEmojis import chat.rocket.core.internal.rest.getCustomEmojis
import chat.rocket.core.internal.rest.logout import chat.rocket.core.internal.rest.logout
import chat.rocket.core.internal.rest.me import chat.rocket.core.internal.rest.me
...@@ -41,7 +40,6 @@ import chat.rocket.core.internal.rest.unregisterPushToken ...@@ -41,7 +40,6 @@ import chat.rocket.core.internal.rest.unregisterPushToken
import chat.rocket.core.model.Myself import chat.rocket.core.model.Myself
import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.channels.Channel import kotlinx.coroutines.experimental.channels.Channel
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.withContext import kotlinx.coroutines.experimental.withContext
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
...@@ -142,7 +140,7 @@ class MainPresenter @Inject constructor( ...@@ -142,7 +140,7 @@ class MainPresenter @Inject constructor(
shortnameAlternates = customEmoji.aliases, shortnameAlternates = customEmoji.aliases,
siblings = mutableListOf(), siblings = mutableListOf(),
unicode = "", unicode = "",
default = true isDefault = true
)) ))
} }
......
...@@ -13,8 +13,8 @@ data class Emoji( ...@@ -13,8 +13,8 @@ data class Emoji(
@Ignore val keywords: List<String> = listOf(), @Ignore val keywords: List<String> = listOf(),
var category: String = "", var category: String = "",
var count: Int = 0, var count: Int = 0,
var siblings: List<String> = listOf(), var siblings: MutableList<String> = mutableListOf(), // Siblings are the same emoji with different skin tones.
var fitzpatrick: String = Fitzpatrick.Default.type, var fitzpatrick: String = Fitzpatrick.Default.type,
var url: String? = null, // Filled for custom emojis var url: String? = null, // Filled for custom emojis
var default: Boolean = true var isDefault: Boolean = true // Tell if this is the default emoji if it has siblings (usually a yellow-toned one).
) )
...@@ -2,6 +2,7 @@ package chat.rocket.android.emoji ...@@ -2,6 +2,7 @@ package chat.rocket.android.emoji
import android.content.Context import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Typeface
import android.text.Spannable import android.text.Spannable
import android.text.SpannableString import android.text.SpannableString
import android.text.Spanned import android.text.Spanned
...@@ -33,7 +34,13 @@ class EmojiParser { ...@@ -33,7 +34,13 @@ class EmojiParser {
val spannable = factory?.newSpannable(unicodedText) val spannable = factory?.newSpannable(unicodedText)
?: SpannableString.valueOf(unicodedText) ?: SpannableString.valueOf(unicodedText)
val typeface = EmojiRepository.cachedTypeface val typeface = try {
EmojiRepository.cachedTypeface
} catch (ex: UninitializedPropertyAccessException) {
// swallow this exception and create typeface now
Typeface.createFromAsset(context.assets, "fonts/emojione-android.ttf")
}
// Look for groups of emojis, set a EmojiTypefaceSpan with the emojione font. // Look for groups of emojis, set a EmojiTypefaceSpan with the emojione font.
val length = spannable.length val length = spannable.length
var inEmoji = false var inEmoji = false
...@@ -47,6 +54,7 @@ class EmojiParser { ...@@ -47,6 +54,7 @@ class EmojiParser {
offset += count offset += count
continue continue
} }
if (codepoint >= 0x200) { if (codepoint >= 0x200) {
if (!inEmoji) { if (!inEmoji) {
emojiStart = offset emojiStart = offset
...@@ -59,6 +67,7 @@ class EmojiParser { ...@@ -59,6 +67,7 @@ class EmojiParser {
} }
inEmoji = false inEmoji = false
} }
offset += count offset += count
if (offset >= length && inEmoji) { if (offset >= length && inEmoji) {
spannable.setSpan(EmojiTypefaceSpan("sans-serif", typeface), spannable.setSpan(EmojiTypefaceSpan("sans-serif", typeface),
......
...@@ -6,6 +6,7 @@ import android.graphics.Typeface ...@@ -6,6 +6,7 @@ import android.graphics.Typeface
import chat.rocket.android.emoji.internal.EmojiCategory import chat.rocket.android.emoji.internal.EmojiCategory
import chat.rocket.android.emoji.internal.PREF_EMOJI_RECENTS import chat.rocket.android.emoji.internal.PREF_EMOJI_RECENTS
import chat.rocket.android.emoji.internal.db.EmojiDatabase import chat.rocket.android.emoji.internal.db.EmojiDatabase
import chat.rocket.android.emoji.internal.isCustom
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.launch import kotlinx.coroutines.experimental.launch
...@@ -47,10 +48,9 @@ object EmojiRepository { ...@@ -47,10 +48,9 @@ object EmojiRepository {
for (emoji in emojis) { for (emoji in emojis) {
val unicodeIntList = mutableListOf<Int>() val unicodeIntList = mutableListOf<Int>()
emoji.category = emoji.category.toUpperCase() emoji.category = emoji.category
// If unicode is empty it's a custom emoji, just add it. if (emoji.isCustom()) {
if (emoji.unicode.isEmpty()) {
allEmojis.add(emoji) allEmojis.add(emoji)
continue continue
} }
...@@ -68,27 +68,27 @@ object EmojiRepository { ...@@ -68,27 +68,27 @@ object EmojiRepository {
val unicodeIntArray = unicodeIntList.toIntArray() val unicodeIntArray = unicodeIntList.toIntArray()
val unicode = String(unicodeIntArray, 0, unicodeIntArray.size) val unicode = String(unicodeIntArray, 0, unicodeIntArray.size)
val emojiWithUnicode = emoji.copy(unicode = unicode) emoji.unicode = unicode
if (hasFitzpatrick(emoji.shortname)) { if (hasFitzpatrick(emoji.shortname)) {
val matchResult = FITZPATRICK_REGEX.find(emoji.shortname) val matchResult = FITZPATRICK_REGEX.find(emoji.shortname)
val prefix = matchResult!!.groupValues[1] + ":" val prefix = matchResult!!.groupValues[1] + ":"
val fitzpatrick = Fitzpatrick.valueOf(matchResult.groupValues[2]) val fitzpatrick = Fitzpatrick.valueOf(matchResult.groupValues[2])
val defaultEmoji = allEmojis.firstOrNull { it.shortname == prefix } val defaultEmoji = allEmojis.firstOrNull { it.shortname == prefix }
val emojiWithFitzpatrick = emojiWithUnicode.copy(fitzpatrick = fitzpatrick.type) emoji.fitzpatrick = fitzpatrick.type
if (defaultEmoji != null) { emoji.isDefault = if (defaultEmoji != null) {
emojiWithFitzpatrick.default = false defaultEmoji.siblings.add(emoji.shortname)
defaultEmoji.siblings.toMutableList().add(emoji.shortname) false
} else { } else {
// This emoji doesn't have a default tone, ie. :man_in_business_suit_levitating_tone1: true
// In this case, the default emoji becomes the first toned one.
allEmojis.add(emojiWithFitzpatrick)
} }
} else {
allEmojis.add(emojiWithUnicode) emoji.isDefault = false
} }
allEmojis.add(emoji)
shortNameToUnicode.apply { shortNameToUnicode.apply {
put(emoji.shortname, unicode) put(emoji.shortname, unicode)
emoji.shortnameAlternates.forEach { alternate -> put(alternate, unicode) } emoji.shortnameAlternates.forEach { alternate -> put(alternate, unicode) }
...@@ -97,6 +97,7 @@ object EmojiRepository { ...@@ -97,6 +97,7 @@ object EmojiRepository {
saveEmojisToDatabase(allEmojis.toList()) saveEmojisToDatabase(allEmojis.toList())
// Prefetch all custom emojis to make cache.
val density = context.resources.displayMetrics.density val density = context.resources.displayMetrics.density
val px = (32 * density).toInt() val px = (32 * density).toInt()
...@@ -130,7 +131,7 @@ object EmojiRepository { ...@@ -130,7 +131,7 @@ object EmojiRepository {
internal suspend fun getEmojiSequenceByCategory(category: EmojiCategory): Sequence<Emoji> { internal suspend fun getEmojiSequenceByCategory(category: EmojiCategory): Sequence<Emoji> {
val list = withContext(CommonPool) { val list = withContext(CommonPool) {
db.emojiDao().loadEmojisByCategory(category.name.toLowerCase()) db.emojiDao().loadEmojisByCategory(category.name)
} }
return buildSequence { return buildSequence {
......
...@@ -14,10 +14,7 @@ import chat.rocket.android.emoji.EmojiParser ...@@ -14,10 +14,7 @@ import chat.rocket.android.emoji.EmojiParser
import chat.rocket.android.emoji.EmojiRepository import chat.rocket.android.emoji.EmojiRepository
import chat.rocket.android.emoji.Fitzpatrick import chat.rocket.android.emoji.Fitzpatrick
import chat.rocket.android.emoji.R import chat.rocket.android.emoji.R
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.engine.cache.ExternalPreferredCacheDiskCacheFactory
import com.bumptech.glide.request.RequestOptions
import kotlinx.android.synthetic.main.emoji_category_layout.view.* import kotlinx.android.synthetic.main.emoji_category_layout.view.*
import kotlinx.android.synthetic.main.emoji_image_row_item.view.* import kotlinx.android.synthetic.main.emoji_image_row_item.view.*
import kotlinx.android.synthetic.main.emoji_row_item.view.* import kotlinx.android.synthetic.main.emoji_row_item.view.*
...@@ -97,26 +94,24 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) : ...@@ -97,26 +94,24 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) :
private val listener: EmojiKeyboardListener private val listener: EmojiKeyboardListener
) : RecyclerView.Adapter<EmojiRowViewHolder>() { ) : RecyclerView.Adapter<EmojiRowViewHolder>() {
private val TYPE_CUSTOM = 1 private val CUSTOM = 1
private val TYPE_NORMAL = 2 private val NORMAL = 2
private val allEmojis = mutableListOf<Emoji>()
private val emojis = mutableListOf<Emoji>() private val emojis = mutableListOf<Emoji>()
fun addEmojis(emojis: List<Emoji>) {
this.emojis.clear()
this.emojis.addAll(emojis)
notifyDataSetChanged()
}
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {
return if (emojis[position].url != null) TYPE_CUSTOM else TYPE_NORMAL return if (emojis[position].isCustom()) CUSTOM else NORMAL
} }
suspend fun addEmojisFromSequence(emojiSequence: Sequence<Emoji>) { suspend fun addEmojisFromSequence(emojiSequence: Sequence<Emoji>) {
withContext(CommonPool) { withContext(CommonPool) {
emojiSequence.forEachIndexed { index, emoji -> emojiSequence.forEachIndexed { index, emoji ->
withContext(UI) { withContext(UI) {
allEmojis.add(emoji)
if (emoji.isDefault) {
emojis.add(emoji) emojis.add(emoji)
notifyItemInserted(index) notifyItemInserted(emojis.size - 1)
}
} }
} }
} }
...@@ -130,18 +125,22 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) : ...@@ -130,18 +125,22 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) :
override fun onBindViewHolder(holder: EmojiRowViewHolder, position: Int) { override fun onBindViewHolder(holder: EmojiRowViewHolder, position: Int) {
val emoji = emojis[position] val emoji = emojis[position]
holder.bind( holder.bind(
if (fitzpatrick != Fitzpatrick.Default) {
emoji.siblings.find { emoji.siblings.find {
it.endsWith(fitzpatrick.type) it.endsWith("${fitzpatrick.type}:")
}?.let { shortname -> }?.let { shortname ->
emojis.firstOrNull { allEmojis.firstOrNull {
it.shortname == shortname it.shortname == shortname
} }
} ?: emoji } ?: emoji
} else {
emoji
}
) )
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EmojiRowViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EmojiRowViewHolder {
val view = if (viewType == TYPE_CUSTOM) { val view = if (viewType == CUSTOM) {
LayoutInflater.from(parent.context).inflate(R.layout.emoji_image_row_item, parent, false) LayoutInflater.from(parent.context).inflate(R.layout.emoji_image_row_item, parent, false)
} else { } else {
LayoutInflater.from(parent.context).inflate(R.layout.emoji_row_item, parent, false) LayoutInflater.from(parent.context).inflate(R.layout.emoji_row_item, parent, false)
...@@ -160,6 +159,7 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) : ...@@ -160,6 +159,7 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) :
fun bind(emoji: Emoji) { fun bind(emoji: Emoji) {
with(itemView) { with(itemView) {
if (emoji.unicode.isNotEmpty()) { if (emoji.unicode.isNotEmpty()) {
// Handle simple emoji.
val parsedUnicode = unicodeCache[emoji.unicode] val parsedUnicode = unicodeCache[emoji.unicode]
emoji_view.setSpannableFactory(spannableFactory) emoji_view.setSpannableFactory(spannableFactory)
emoji_view.text = if (parsedUnicode == null) { emoji_view.text = if (parsedUnicode == null) {
...@@ -171,6 +171,7 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) : ...@@ -171,6 +171,7 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) :
parsedUnicode parsedUnicode
} }
} else { } else {
// Handle custom emoji.
GlideApp.with(context) GlideApp.with(context)
.load(emoji.url) .load(emoji.url)
.diskCacheStrategy(DiskCacheStrategy.ALL) .diskCacheStrategy(DiskCacheStrategy.ALL)
......
package chat.rocket.android.emoji.internal
import chat.rocket.android.emoji.Emoji
fun Emoji.isCustom(): Boolean = this.url != null
...@@ -2,17 +2,15 @@ package chat.rocket.android.emoji.internal.db ...@@ -2,17 +2,15 @@ package chat.rocket.android.emoji.internal.db
import androidx.room.TypeConverter import androidx.room.TypeConverter
internal object StringListConverter { class StringListConverter {
@TypeConverter @TypeConverter
@JvmStatic fun fromStringList(list: List<String>?): String {
fun toString(list: List<String>?): String? { return list?.joinToString(separator = ",") ?: ""
return if (list == null) null else list.joinToString(separator = ",")
} }
@TypeConverter @TypeConverter
@JvmStatic fun fromString(value: String?): List<String> {
fun toStringList(value: String?): List<String>? { return value?.split(",") ?: emptyList()
return value?.split(",")
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment