From 75266f42bbfce9da67378b035d22afc24e885f8a Mon Sep 17 00:00:00 2001 From: Valere Date: Thu, 29 Aug 2019 16:49:22 +0200 Subject: [PATCH 1/2] Fix / EmojiCompat not initialized --- .../java/im/vector/riotx/EmojiCompatHelper.kt | 68 +++++++++++++++++++ .../java/im/vector/riotx/VectorApplication.kt | 16 +---- .../action/ViewReactionsEpoxyController.kt | 3 +- .../reactions/widget/ReactionButton.kt | 5 +- 4 files changed, 73 insertions(+), 19 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotx/EmojiCompatHelper.kt diff --git a/vector/src/main/java/im/vector/riotx/EmojiCompatHelper.kt b/vector/src/main/java/im/vector/riotx/EmojiCompatHelper.kt new file mode 100644 index 00000000..9e4a6087 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/EmojiCompatHelper.kt @@ -0,0 +1,68 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package im.vector.riotx + +import android.content.Context +import androidx.core.provider.FontRequest +import androidx.emoji.text.EmojiCompat +import androidx.emoji.text.FontRequestEmojiCompatConfig +import timber.log.Timber + +object EmojiCompatHelper { + + var initialized = false + + fun init(context: Context) { + val fontRequest = FontRequest( + "com.google.android.gms.fonts", + "com.google.android.gms", + "Noto Color Emoji Compat", + R.array.com_google_android_gms_fonts_certs + ) + //Use emoji compat for the benefit of emoji spans + val config = FontRequestEmojiCompatConfig(context, fontRequest) + // we want to replace all emojis with selected font + .setReplaceAll(true) + //Debug options +// .setEmojiSpanIndicatorEnabled(true) +// .setEmojiSpanIndicatorColor(Color.GREEN) + EmojiCompat.init(config) + .registerInitCallback(object : EmojiCompat.InitCallback() { + override fun onInitialized() { + Timber.v("Emoji compat onInitialized success ") + initialized = true + } + + override fun onFailed(throwable: Throwable?) { + Timber.e(throwable, "Failed to init EmojiCompat") + } + }) + } + + fun safeEmojiSpanify(sequence: CharSequence): CharSequence { + if (initialized) { + try { + return EmojiCompat.get().process(sequence) + } catch (throwable: Throwable) { + //Defensive coding against error (should not happend as it is initialized) + Timber.e(throwable, "Failed to init EmojiCompat") + return sequence + } + } else { + return sequence + } + } +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotx/VectorApplication.kt b/vector/src/main/java/im/vector/riotx/VectorApplication.kt index 4e09d790..36b4d589 100644 --- a/vector/src/main/java/im/vector/riotx/VectorApplication.kt +++ b/vector/src/main/java/im/vector/riotx/VectorApplication.kt @@ -109,21 +109,7 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration. FontsContractCompat.requestFont(this, fontRequest, emojiCompatFontProvider, getFontThreadHandler()) vectorConfiguration.initConfiguration() - //Use emoji compat for the benefit of emoji spans - val config = FontRequestEmojiCompatConfig(this, fontRequest) - .setReplaceAll(true) // we want to replace all emojis with selected font -// .setEmojiSpanIndicatorEnabled(true) -// .setEmojiSpanIndicatorColor(Color.GREEN) - EmojiCompat.init(config) - .registerInitCallback(object : EmojiCompat.InitCallback() { - override fun onInitialized() { - Timber.v("Emoji compat onInitialized success ") - } - - override fun onFailed(throwable: Throwable?) { - Timber.e(throwable,"Failed to init EmojiCompat") - } - }) + EmojiCompatHelper.init(this) NotificationUtils.createNotificationChannels(applicationContext) if (authenticator.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewReactionsEpoxyController.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewReactionsEpoxyController.kt index 33e1d4df..3c2ff93e 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewReactionsEpoxyController.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewReactionsEpoxyController.kt @@ -24,6 +24,7 @@ import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Incomplete import com.airbnb.mvrx.Success +import im.vector.riotx.EmojiCompatHelper import im.vector.riotx.R import im.vector.riotx.core.ui.list.genericFooterItem import im.vector.riotx.core.ui.list.genericLoaderItem @@ -52,7 +53,7 @@ class ViewReactionsEpoxyController(private val context: Context) reactionInfoSimpleItem { id(it.eventId) timeStamp(it.timestamp) - reactionKey(EmojiCompat.get().process(it.reactionKey)) + reactionKey(EmojiCompatHelper.safeEmojiSpanify(it.reactionKey)) authorDisplayName(it.authorName ?: it.authorId) } } diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/widget/ReactionButton.kt b/vector/src/main/java/im/vector/riotx/features/reactions/widget/ReactionButton.kt index 0644e962..c9bfa2df 100644 --- a/vector/src/main/java/im/vector/riotx/features/reactions/widget/ReactionButton.kt +++ b/vector/src/main/java/im/vector/riotx/features/reactions/widget/ReactionButton.kt @@ -21,7 +21,6 @@ import android.animation.AnimatorSet import android.animation.ObjectAnimator import android.content.Context import android.content.res.TypedArray -import android.graphics.Typeface import android.graphics.drawable.Drawable import android.util.AttributeSet import android.view.LayoutInflater @@ -35,7 +34,7 @@ import android.widget.TextView import androidx.annotation.ColorInt import androidx.annotation.ColorRes import androidx.core.content.ContextCompat -import androidx.emoji.text.EmojiCompat +import im.vector.riotx.EmojiCompatHelper import im.vector.riotx.R import im.vector.riotx.core.utils.TextUtils @@ -78,7 +77,7 @@ class ReactionButton @JvmOverloads constructor(context: Context, attrs: Attribut set(value) { field = value //maybe cache this for performances? - val emojiSpanned = EmojiCompat.get().process(value) + val emojiSpanned = EmojiCompatHelper.safeEmojiSpanify(value) emojiView?.text = emojiSpanned } From 35817245cb80ecaf748d68adcc28efe42d60a830 Mon Sep 17 00:00:00 2001 From: Valere Date: Thu, 29 Aug 2019 17:27:49 +0200 Subject: [PATCH 2/2] refactoring, code review --- ...ojiCompatHelper.kt => EmojiCompatWrapper.kt} | 17 ++++++++--------- .../java/im/vector/riotx/VectorApplication.kt | 6 ++---- .../im/vector/riotx/core/di/ScreenComponent.kt | 3 +++ .../im/vector/riotx/core/di/VectorComponent.kt | 3 +++ .../timeline/action/ViewReactionBottomSheet.kt | 4 +--- .../action/ViewReactionsEpoxyController.kt | 15 ++++++++------- .../features/reactions/widget/ReactionButton.kt | 14 ++++++++++++-- 7 files changed, 37 insertions(+), 25 deletions(-) rename vector/src/main/java/im/vector/riotx/{EmojiCompatHelper.kt => EmojiCompatWrapper.kt} (86%) diff --git a/vector/src/main/java/im/vector/riotx/EmojiCompatHelper.kt b/vector/src/main/java/im/vector/riotx/EmojiCompatWrapper.kt similarity index 86% rename from vector/src/main/java/im/vector/riotx/EmojiCompatHelper.kt rename to vector/src/main/java/im/vector/riotx/EmojiCompatWrapper.kt index 9e4a6087..b1832840 100644 --- a/vector/src/main/java/im/vector/riotx/EmojiCompatHelper.kt +++ b/vector/src/main/java/im/vector/riotx/EmojiCompatWrapper.kt @@ -16,22 +16,21 @@ package im.vector.riotx import android.content.Context +import androidx.appcompat.app.AppCompatActivity import androidx.core.provider.FontRequest import androidx.emoji.text.EmojiCompat import androidx.emoji.text.FontRequestEmojiCompatConfig import timber.log.Timber +import javax.inject.Inject +import javax.inject.Singleton -object EmojiCompatHelper { +@Singleton +class EmojiCompatWrapper @Inject constructor(private val context: Context) { - var initialized = false + private var initialized = false + + fun init(fontRequest: FontRequest) { - fun init(context: Context) { - val fontRequest = FontRequest( - "com.google.android.gms.fonts", - "com.google.android.gms", - "Noto Color Emoji Compat", - R.array.com_google_android_gms_fonts_certs - ) //Use emoji compat for the benefit of emoji spans val config = FontRequestEmojiCompatConfig(context, fontRequest) // we want to replace all emojis with selected font diff --git a/vector/src/main/java/im/vector/riotx/VectorApplication.kt b/vector/src/main/java/im/vector/riotx/VectorApplication.kt index 36b4d589..b62c44f5 100644 --- a/vector/src/main/java/im/vector/riotx/VectorApplication.kt +++ b/vector/src/main/java/im/vector/riotx/VectorApplication.kt @@ -19,13 +19,10 @@ package im.vector.riotx import android.app.Application import android.content.Context import android.content.res.Configuration -import android.graphics.Color import android.os.Handler import android.os.HandlerThread import androidx.core.provider.FontRequest import androidx.core.provider.FontsContractCompat -import androidx.emoji.text.EmojiCompat -import androidx.emoji.text.FontRequestEmojiCompatConfig import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent @@ -69,6 +66,7 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration. @Inject lateinit var authenticator: Authenticator @Inject lateinit var vectorConfiguration: VectorConfiguration @Inject lateinit var emojiCompatFontProvider: EmojiCompatFontProvider + @Inject lateinit var emojiCompatWrapper: EmojiCompatWrapper @Inject lateinit var vectorUncaughtExceptionHandler: VectorUncaughtExceptionHandler @Inject lateinit var activeSessionHolder: ActiveSessionHolder @Inject lateinit var notificationDrawerManager: NotificationDrawerManager @@ -109,7 +107,7 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration. FontsContractCompat.requestFont(this, fontRequest, emojiCompatFontProvider, getFontThreadHandler()) vectorConfiguration.initConfiguration() - EmojiCompatHelper.init(this) + emojiCompatWrapper.init(fontRequest) NotificationUtils.createNotificationChannels(applicationContext) if (authenticator.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) { diff --git a/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt b/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt index ffde2bc2..6bfbddba 100644 --- a/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt +++ b/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt @@ -58,6 +58,7 @@ import im.vector.riotx.features.rageshake.BugReportActivity import im.vector.riotx.features.rageshake.BugReporter import im.vector.riotx.features.rageshake.RageShake import im.vector.riotx.features.reactions.EmojiReactionPickerActivity +import im.vector.riotx.features.reactions.widget.ReactionButton import im.vector.riotx.features.roomdirectory.PublicRoomsFragment import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity import im.vector.riotx.features.roomdirectory.createroom.CreateRoomActivity @@ -181,6 +182,8 @@ interface ScreenComponent { fun inject(displayReadReceiptsBottomSheet: DisplayReadReceiptsBottomSheet) + fun inject(reactionButton: ReactionButton) + @Component.Factory interface Factory { fun create(vectorComponent: VectorComponent, diff --git a/vector/src/main/java/im/vector/riotx/core/di/VectorComponent.kt b/vector/src/main/java/im/vector/riotx/core/di/VectorComponent.kt index d1b87f0b..7cbbc306 100644 --- a/vector/src/main/java/im/vector/riotx/core/di/VectorComponent.kt +++ b/vector/src/main/java/im/vector/riotx/core/di/VectorComponent.kt @@ -24,6 +24,7 @@ import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.api.auth.Authenticator import im.vector.matrix.android.api.session.Session import im.vector.riotx.EmojiCompatFontProvider +import im.vector.riotx.EmojiCompatWrapper import im.vector.riotx.VectorApplication import im.vector.riotx.core.pushers.PushersManager import im.vector.riotx.features.configuration.VectorConfiguration @@ -70,6 +71,8 @@ interface VectorComponent { fun emojiCompatFontProvider(): EmojiCompatFontProvider + fun emojiCompatWrapper() : EmojiCompatWrapper + fun eventHtmlRenderer(): EventHtmlRenderer fun navigator(): Navigator diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewReactionBottomSheet.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewReactionBottomSheet.kt index 9d21c89e..83d61782 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewReactionBottomSheet.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewReactionBottomSheet.kt @@ -46,9 +46,7 @@ class ViewReactionBottomSheet : VectorBaseBottomSheetDialogFragment() { @BindView(R.id.bottom_sheet_display_reactions_list) lateinit var epoxyRecyclerView: EpoxyRecyclerView - private val epoxyController by lazy { - ViewReactionsEpoxyController(requireContext()) - } + @Inject lateinit var epoxyController: ViewReactionsEpoxyController override fun injectWith(screenComponent: ScreenComponent) { screenComponent.inject(this) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewReactionsEpoxyController.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewReactionsEpoxyController.kt index 3c2ff93e..904a2395 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewReactionsEpoxyController.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewReactionsEpoxyController.kt @@ -17,22 +17,23 @@ package im.vector.riotx.features.home.room.detail.timeline.action import android.content.Context -import android.graphics.Typeface -import android.text.format.DateUtils -import androidx.emoji.text.EmojiCompat import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Incomplete import com.airbnb.mvrx.Success -import im.vector.riotx.EmojiCompatHelper +import im.vector.riotx.EmojiCompatWrapper import im.vector.riotx.R +import im.vector.riotx.core.resources.StringProvider import im.vector.riotx.core.ui.list.genericFooterItem import im.vector.riotx.core.ui.list.genericLoaderItem +import javax.inject.Inject /** * Epoxy controller for reaction event list */ -class ViewReactionsEpoxyController(private val context: Context) +class ViewReactionsEpoxyController @Inject constructor( + private val stringProvider: StringProvider, + private val emojiCompatWrapper: EmojiCompatWrapper ) : TypedEpoxyController() { override fun buildModels(state: DisplayReactionsViewState) { @@ -45,7 +46,7 @@ class ViewReactionsEpoxyController(private val context: Context) is Fail -> { genericFooterItem { id("failure") - text(context.getString(R.string.unknown_error)) + text(stringProvider.getString(R.string.unknown_error)) } } is Success -> { @@ -53,7 +54,7 @@ class ViewReactionsEpoxyController(private val context: Context) reactionInfoSimpleItem { id(it.eventId) timeStamp(it.timestamp) - reactionKey(EmojiCompatHelper.safeEmojiSpanify(it.reactionKey)) + reactionKey(emojiCompatWrapper.safeEmojiSpanify(it.reactionKey)) authorDisplayName(it.authorName ?: it.authorId) } } diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/widget/ReactionButton.kt b/vector/src/main/java/im/vector/riotx/features/reactions/widget/ReactionButton.kt index c9bfa2df..483165ab 100644 --- a/vector/src/main/java/im/vector/riotx/features/reactions/widget/ReactionButton.kt +++ b/vector/src/main/java/im/vector/riotx/features/reactions/widget/ReactionButton.kt @@ -34,9 +34,11 @@ import android.widget.TextView import androidx.annotation.ColorInt import androidx.annotation.ColorRes import androidx.core.content.ContextCompat -import im.vector.riotx.EmojiCompatHelper +import im.vector.riotx.EmojiCompatWrapper import im.vector.riotx.R +import im.vector.riotx.core.di.HasScreenInjector import im.vector.riotx.core.utils.TextUtils +import javax.inject.Inject /** * An animated reaction button. @@ -46,6 +48,12 @@ class ReactionButton @JvmOverloads constructor(context: Context, attrs: Attribut defStyleAttr: Int = 0) : FrameLayout(context, attrs, defStyleAttr), View.OnClickListener, View.OnLongClickListener { + init { + if (context is HasScreenInjector) { + context.injector().inject(this) + } + } + companion object { private val DECCELERATE_INTERPOLATOR = DecelerateInterpolator() private val ACCELERATE_DECELERATE_INTERPOLATOR = AccelerateDecelerateInterpolator() @@ -53,6 +61,8 @@ class ReactionButton @JvmOverloads constructor(context: Context, attrs: Attribut } + @Inject lateinit var emojiCompatWrapper: EmojiCompatWrapper + private var emojiView: TextView? = null private var countTextView: TextView? = null @@ -77,7 +87,7 @@ class ReactionButton @JvmOverloads constructor(context: Context, attrs: Attribut set(value) { field = value //maybe cache this for performances? - val emojiSpanned = EmojiCompatHelper.safeEmojiSpanify(value) + val emojiSpanned = emojiCompatWrapper.safeEmojiSpanify(value) emojiView?.text = emojiSpanned }