Use EmojiCompat to build EmojiSpans from text

This commit is contained in:
Valere 2019-08-18 14:26:53 -04:00
parent 2be6058971
commit 7e142d201d
9 changed files with 40 additions and 25 deletions

View File

@ -5,10 +5,10 @@ Features:
- Display read receipts in timeline (#81)

Improvements:
-
- Reactions: Reinstate the ability to react with non-unicode keys (#307)

Other changes:
-
-

Bugfix:
- Fix text diff linebreak display (#441)

View File

@ -318,6 +318,8 @@ dependencies {

implementation 'diff_match_patch:diff_match_patch:current'

implementation "androidx.emoji:emoji-appcompat:1.0.0"

// TESTS
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'

View File

@ -19,10 +19,13 @@ 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
@ -105,6 +108,23 @@ 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")
}
})

NotificationUtils.createNotificationChannels(applicationContext)
if (authenticator.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) {
val lastAuthenticatedSession = authenticator.getLastAuthenticatedSession()!!

View File

@ -38,12 +38,8 @@ abstract class ReactionInfoSimpleItem : EpoxyModelWithHolder<ReactionInfoSimpleI
@EpoxyAttribute
var timeStamp: CharSequence? = null

@EpoxyAttribute
var emojiTypeFace: Typeface? = null

override fun bind(holder: Holder) {
holder.emojiReactionView.text = reactionKey
holder.emojiReactionView.typeface = emojiTypeFace ?: Typeface.DEFAULT
holder.displayNameView.text = authorDisplayName
timeStamp?.let {
holder.timeStampView.text = it

View File

@ -28,7 +28,6 @@ import com.airbnb.epoxy.EpoxyRecyclerView
import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.riotx.EmojiCompatFontProvider
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
@ -43,13 +42,12 @@ class ViewReactionBottomSheet : VectorBaseBottomSheetDialogFragment() {
private val viewModel: ViewReactionViewModel by fragmentViewModel(ViewReactionViewModel::class)

@Inject lateinit var viewReactionViewModelFactory: ViewReactionViewModel.Factory
@Inject lateinit var emojiCompatFontProvider: EmojiCompatFontProvider

@BindView(R.id.bottom_sheet_display_reactions_list)
lateinit var epoxyRecyclerView: EpoxyRecyclerView

private val epoxyController by lazy {
ViewReactionsEpoxyController(requireContext(), emojiCompatFontProvider.typeface)
ViewReactionsEpoxyController(requireContext())
}

override fun injectWith(screenComponent: ScreenComponent) {

View File

@ -19,6 +19,7 @@ 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
@ -30,7 +31,7 @@ import im.vector.riotx.core.ui.list.genericLoaderItem
/**
* Epoxy controller for reaction event list
*/
class ViewReactionsEpoxyController(private val context: Context, private val emojiCompatTypeface: Typeface?)
class ViewReactionsEpoxyController(private val context: Context)
: TypedEpoxyController<DisplayReactionsViewState>() {

override fun buildModels(state: DisplayReactionsViewState) {
@ -50,9 +51,8 @@ class ViewReactionsEpoxyController(private val context: Context, private val emo
state.mapReactionKeyToMemberList()?.forEach {
reactionInfoSimpleItem {
id(it.eventId)
emojiTypeFace(emojiCompatTypeface)
timeStamp(it.timestamp)
reactionKey(it.reactionKey)
reactionKey(EmojiCompat.get().process(it.reactionKey))
authorDisplayName(it.authorName ?: it.authorId)
}
}

View File

@ -151,7 +151,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
idToRefInFlow.add(reactionButton.id)
reactionButton.reactionString = reaction.key
reactionButton.reactionCount = reaction.count
reactionButton.emojiTypeFace = emojiTypeFace
//reactionButton.emojiTypeFace = emojiTypeFace
reactionButton.setChecked(reaction.addedByMe)
reactionButton.isEnabled = reaction.synced
}

View File

@ -35,6 +35,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.R
import im.vector.riotx.core.utils.TextUtils

@ -58,12 +59,6 @@ class ReactionButton @JvmOverloads constructor(context: Context, attrs: Attribut

private var reactionSelector: View? = null

var emojiTypeFace: Typeface? = null
set(value) {
field = value
emojiView?.typeface = value ?: Typeface.DEFAULT
}

private var dotsView: DotsView
private var circleView: CircleView
var reactedListener: ReactedListener? = null
@ -82,7 +77,9 @@ class ReactionButton @JvmOverloads constructor(context: Context, attrs: Attribut
var reactionString = "😀"
set(value) {
field = value
emojiView?.text = field
//maybe cache this for performances?
val emojiSpanned = EmojiCompat.get().process(value)
emojiView?.text = emojiSpanned
}

private var animationScaleFactor: Float = 0.toFloat()
@ -104,7 +101,7 @@ class ReactionButton @JvmOverloads constructor(context: Context, attrs: Attribut

countTextView?.text = TextUtils.formatCountToShortDecimal(reactionCount)

emojiView?.typeface = this.emojiTypeFace ?: Typeface.DEFAULT
// emojiView?.typeface = this.emojiTypeFace ?: Typeface.DEFAULT

val array = context.obtainStyledAttributes(attrs, R.styleable.ReactionButton, defStyleAttr, 0)


View File

@ -40,18 +40,20 @@
android:layout_width="wrap_content"
android:layout_height="20dp"
android:minWidth="20dp"
android:layout_gravity="center"
android:layout_marginStart="6dp"
android:layout_marginLeft="6dp"
android:gravity="center"
android:textColor="@color/black"
android:textSize="13sp"
android:maxEms="10"
android:ellipsize="middle"
android:singleLine="true"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@id/reactionCount"
tools:text="* Party Parrot Again *" />
tools:text="* Party Parrot Again * 👀" />

<TextView
android:id="@+id/reactionCount"
@ -59,8 +61,8 @@
android:layout_height="wrap_content"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintBaseline_toBaselineOf="@id/reactionText"
android:layout_marginStart="-4dp"
android:layout_marginLeft="-4dp"
android:layout_marginStart="2dp"
android:layout_marginLeft="2dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:gravity="center"