forked from GitHub-Mirror/riotX-android
Use Font emoji compat for quickReactions and pills
This commit is contained in:
parent
53c91dc0c2
commit
d2f648edec
@ -0,0 +1,48 @@
|
||||
package im.vector.riotredesign
|
||||
|
||||
import android.graphics.Typeface
|
||||
import androidx.core.provider.FontsContractCompat
|
||||
import timber.log.Timber
|
||||
|
||||
|
||||
class EmojiCompatFontProvider : FontsContractCompat.FontRequestCallback() {
|
||||
|
||||
var typeface: Typeface? = null
|
||||
set(value) {
|
||||
if (value != field) {
|
||||
field = value
|
||||
listeners.forEach {
|
||||
try {
|
||||
it.compatibilityFontUpdate(value)
|
||||
} catch (t: Throwable) {
|
||||
Timber.e(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val listeners = ArrayList<FontProviderListener>()
|
||||
|
||||
override fun onTypefaceRetrieved(typeface: Typeface) {
|
||||
this.typeface = typeface
|
||||
}
|
||||
|
||||
override fun onTypefaceRequestFailed(reason: Int) {
|
||||
Timber.e("Failed to load Emoji Compatible font, reason:$reason")
|
||||
}
|
||||
|
||||
fun addListener(listener: FontProviderListener) {
|
||||
if (!listeners.contains(listener)) {
|
||||
listeners.add(listener)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeListener(listener: FontProviderListener) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
|
||||
interface FontProviderListener {
|
||||
fun compatibilityFontUpdate(typeface: Typeface?)
|
||||
}
|
||||
}
|
@ -18,6 +18,10 @@ package im.vector.riotredesign
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import androidx.core.provider.FontRequest
|
||||
import androidx.core.provider.FontsContractCompat
|
||||
import android.content.res.Configuration
|
||||
import androidx.multidex.MultiDex
|
||||
import com.airbnb.epoxy.EpoxyAsyncUtil
|
||||
@ -41,6 +45,10 @@ import timber.log.Timber
|
||||
|
||||
class VectorApplication : Application() {
|
||||
|
||||
//font thread handler
|
||||
private var mFontThreadHandler: Handler? = null
|
||||
|
||||
|
||||
val vectorConfiguration: VectorConfiguration by inject()
|
||||
|
||||
override fun onCreate() {
|
||||
@ -63,10 +71,20 @@ class VectorApplication : Application() {
|
||||
val appModule = AppModule(applicationContext).definition
|
||||
val homeModule = HomeModule().definition
|
||||
val roomDirectoryModule = RoomDirectoryModule().definition
|
||||
startKoin(listOf(appModule, homeModule, roomDirectoryModule), logger = EmptyLogger())
|
||||
val koin = startKoin(listOf(appModule, homeModule, roomDirectoryModule), logger = EmptyLogger())
|
||||
|
||||
Matrix.getInstance().setApplicationFlavor(BuildConfig.FLAVOR_DESCRIPTION)
|
||||
|
||||
val fontRequest = FontRequest(
|
||||
"com.google.android.gms.fonts",
|
||||
"com.google.android.gms",
|
||||
"Noto Color Emoji Compat",
|
||||
R.array.com_google_android_gms_fonts_certs
|
||||
)
|
||||
|
||||
// val efp = koin.koinContext.get<EmojiCompatFontProvider>()
|
||||
FontsContractCompat.requestFont(this, fontRequest, koin.koinContext.get<EmojiCompatFontProvider>(), getFontThreadHandler())
|
||||
|
||||
vectorConfiguration.initConfiguration()
|
||||
}
|
||||
|
||||
@ -81,4 +99,13 @@ class VectorApplication : Application() {
|
||||
vectorConfiguration.onConfigurationChanged(newConfig)
|
||||
}
|
||||
|
||||
private fun getFontThreadHandler(): Handler {
|
||||
if (mFontThreadHandler == null) {
|
||||
val handlerThread = HandlerThread("fonts")
|
||||
handlerThread.start()
|
||||
mFontThreadHandler = Handler(handlerThread.looper)
|
||||
}
|
||||
return mFontThreadHandler!!
|
||||
}
|
||||
|
||||
}
|
@ -20,6 +20,7 @@ import android.content.Context
|
||||
import android.content.Context.MODE_PRIVATE
|
||||
import androidx.fragment.app.Fragment
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.riotredesign.EmojiCompatFontProvider
|
||||
import im.vector.riotredesign.core.error.ErrorFormatter
|
||||
import im.vector.riotredesign.core.resources.LocaleProvider
|
||||
import im.vector.riotredesign.core.resources.StringArrayProvider
|
||||
@ -90,5 +91,9 @@ class AppModule(private val context: Context) {
|
||||
DefaultNavigator(fragment) as Navigator
|
||||
}
|
||||
|
||||
single {
|
||||
EmojiCompatFontProvider()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -72,7 +72,8 @@ class HomeModule {
|
||||
val timelineMediaSizeProvider = TimelineMediaSizeProvider()
|
||||
val colorProvider = ColorProvider(fragment.requireContext())
|
||||
val timelineDateFormatter = get<TimelineDateFormatter>()
|
||||
val messageItemFactory = MessageItemFactory(colorProvider, timelineMediaSizeProvider, timelineDateFormatter, eventHtmlRenderer, get())
|
||||
val messageItemFactory = MessageItemFactory(colorProvider, timelineMediaSizeProvider,
|
||||
timelineDateFormatter, eventHtmlRenderer, get(), get())
|
||||
|
||||
val timelineItemFactory = TimelineItemFactory(
|
||||
messageItemFactory = messageItemFactory,
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package im.vector.riotredesign.features.home.room.detail.timeline.action
|
||||
|
||||
import android.graphics.Typeface
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
@ -28,7 +29,9 @@ import com.airbnb.mvrx.BaseMvRxFragment
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.riotredesign.EmojiCompatFontProvider
|
||||
import im.vector.riotredesign.R
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
/**
|
||||
* Quick Reaction Fragment (agree / like reactions)
|
||||
@ -54,6 +57,8 @@ class QuickReactionFragment : BaseMvRxFragment() {
|
||||
|
||||
var interactionListener: InteractionListener? = null
|
||||
|
||||
val fontProvider by inject<EmojiCompatFontProvider>()
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val view = inflater.inflate(R.layout.adapter_item_action_quick_reaction, container, false)
|
||||
ButterKnife.bind(this, view)
|
||||
@ -68,6 +73,10 @@ class QuickReactionFragment : BaseMvRxFragment() {
|
||||
quickReact3Text.text = QuickReactionViewModel.likePositive
|
||||
quickReact4Text.text = QuickReactionViewModel.likeNegative
|
||||
|
||||
listOf(quickReact1Text, quickReact2Text, quickReact3Text, quickReact4Text).forEach {
|
||||
it.typeface = fontProvider.typeface ?: Typeface.DEFAULT
|
||||
}
|
||||
|
||||
//configure click listeners
|
||||
quickReact1Text.setOnClickListener {
|
||||
viewModel.toggleAgree(true)
|
||||
|
@ -33,6 +33,7 @@ import im.vector.matrix.android.api.session.room.model.EditAggregatedSummary
|
||||
import im.vector.matrix.android.api.session.room.model.message.*
|
||||
import im.vector.matrix.android.api.session.room.send.SendState
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.riotredesign.EmojiCompatFontProvider
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotredesign.core.extensions.localDateTime
|
||||
@ -55,7 +56,8 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
private val timelineMediaSizeProvider: TimelineMediaSizeProvider,
|
||||
private val timelineDateFormatter: TimelineDateFormatter,
|
||||
private val htmlRenderer: EventHtmlRenderer,
|
||||
private val stringProvider: StringProvider) {
|
||||
private val stringProvider: StringProvider,
|
||||
private val emojiCompatFontProvider: EmojiCompatFontProvider) {
|
||||
|
||||
fun create(event: TimelineEvent,
|
||||
nextEvent: TimelineEvent?,
|
||||
@ -144,20 +146,21 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
.filename(messageContent.body)
|
||||
.iconRes(R.drawable.filetype_audio)
|
||||
.reactionPillCallback(callback)
|
||||
.emojiTypeFace(emojiCompatFontProvider.typeface)
|
||||
.avatarClickListener(
|
||||
DebouncedClickListener(View.OnClickListener { view ->
|
||||
DebouncedClickListener(View.OnClickListener {
|
||||
callback?.onAvatarClicked(informationData)
|
||||
}))
|
||||
.memberClickListener(
|
||||
DebouncedClickListener(View.OnClickListener { view ->
|
||||
DebouncedClickListener(View.OnClickListener {
|
||||
callback?.onMemberNameClicked(informationData)
|
||||
}))
|
||||
.cellClickListener(
|
||||
DebouncedClickListener(View.OnClickListener { view ->
|
||||
DebouncedClickListener(View.OnClickListener { view: View ->
|
||||
callback?.onEventCellClicked(informationData, messageContent, view)
|
||||
}))
|
||||
.clickListener(
|
||||
DebouncedClickListener(View.OnClickListener { _ ->
|
||||
DebouncedClickListener(View.OnClickListener {
|
||||
callback?.onAudioMessageClicked(messageContent)
|
||||
}))
|
||||
.longClickListener { view ->
|
||||
@ -173,6 +176,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
.informationData(informationData)
|
||||
.filename(messageContent.body)
|
||||
.reactionPillCallback(callback)
|
||||
.emojiTypeFace(emojiCompatFontProvider.typeface)
|
||||
.iconRes(R.drawable.filetype_attachment)
|
||||
.avatarClickListener(
|
||||
DebouncedClickListener(View.OnClickListener { view ->
|
||||
@ -221,6 +225,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
.informationData(informationData)
|
||||
.mediaData(data)
|
||||
.reactionPillCallback(callback)
|
||||
.emojiTypeFace(emojiCompatFontProvider.typeface)
|
||||
.avatarClickListener(
|
||||
DebouncedClickListener(View.OnClickListener { view ->
|
||||
callback?.onAvatarClicked(informationData)
|
||||
@ -268,6 +273,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
.informationData(informationData)
|
||||
.mediaData(thumbnailData)
|
||||
.reactionPillCallback(callback)
|
||||
.emojiTypeFace(emojiCompatFontProvider.typeface)
|
||||
.avatarClickListener(
|
||||
DebouncedClickListener(View.OnClickListener { view ->
|
||||
callback?.onAvatarClicked(informationData)
|
||||
@ -311,6 +317,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
}
|
||||
.informationData(informationData)
|
||||
.reactionPillCallback(callback)
|
||||
.emojiTypeFace(emojiCompatFontProvider.typeface)
|
||||
.avatarClickListener(
|
||||
DebouncedClickListener(View.OnClickListener { view ->
|
||||
callback?.onAvatarClicked(informationData)
|
||||
@ -384,6 +391,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
.message(message)
|
||||
.informationData(informationData)
|
||||
.reactionPillCallback(callback)
|
||||
.emojiTypeFace(emojiCompatFontProvider.typeface)
|
||||
.avatarClickListener(
|
||||
DebouncedClickListener(View.OnClickListener { view ->
|
||||
callback?.onAvatarClicked(informationData)
|
||||
@ -423,6 +431,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||
}
|
||||
.informationData(informationData)
|
||||
.reactionPillCallback(callback)
|
||||
.emojiTypeFace(emojiCompatFontProvider.typeface)
|
||||
.avatarClickListener(
|
||||
DebouncedClickListener(View.OnClickListener { view ->
|
||||
callback?.onAvatarClicked(informationData)
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package im.vector.riotredesign.features.home.room.detail.timeline.item
|
||||
|
||||
import android.graphics.Typeface
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@ -50,6 +51,9 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
|
||||
@EpoxyAttribute
|
||||
var memberClickListener: View.OnClickListener? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var emojiTypeFace: Typeface? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var reactionPillCallback: TimelineEventController.ReactionPillCallback? = null
|
||||
|
||||
@ -116,6 +120,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.setChecked(reaction.addedByMe)
|
||||
reactionButton.isEnabled = reaction.synced
|
||||
}
|
||||
|
@ -19,23 +19,20 @@ import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Typeface
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.util.TypedValue
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.widget.SearchView
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.provider.FontRequest
|
||||
import androidx.core.provider.FontsContractCompat
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import im.vector.riotredesign.EmojiCompatFontProvider
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.platform.VectorBaseActivity
|
||||
import kotlinx.android.synthetic.main.activity_emoji_reaction_picker.*
|
||||
import timber.log.Timber
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
/**
|
||||
*
|
||||
@ -44,20 +41,21 @@ import timber.log.Timber
|
||||
* TODO: Finish Refactor to vector base activity
|
||||
* TODO: Move font request to app
|
||||
*/
|
||||
class EmojiReactionPickerActivity : VectorBaseActivity() {
|
||||
class EmojiReactionPickerActivity : VectorBaseActivity(), EmojiCompatFontProvider.FontProviderListener {
|
||||
|
||||
|
||||
private lateinit var tabLayout: TabLayout
|
||||
|
||||
lateinit var viewModel: EmojiChooserViewModel
|
||||
|
||||
private var mHandler: Handler? = null
|
||||
|
||||
override fun getMenuRes(): Int = R.menu.menu_emoji_reaction_picker
|
||||
|
||||
override fun getLayoutRes(): Int = R.layout.activity_emoji_reaction_picker
|
||||
|
||||
override fun getTitleRes(): Int = R.string.title_activity_emoji_reaction_picker
|
||||
|
||||
val emojiCompatFontProvider by inject<EmojiCompatFontProvider>()
|
||||
|
||||
private var tabLayoutSelectionListener = object : TabLayout.BaseOnTabSelectedListener<TabLayout.Tab> {
|
||||
override fun onTabReselected(p0: TabLayout.Tab) {
|
||||
}
|
||||
@ -71,19 +69,13 @@ class EmojiReactionPickerActivity : VectorBaseActivity() {
|
||||
|
||||
}
|
||||
|
||||
private fun getFontThreadHandler(): Handler {
|
||||
if (mHandler == null) {
|
||||
val handlerThread = HandlerThread("fonts")
|
||||
handlerThread.start()
|
||||
mHandler = Handler(handlerThread.looper)
|
||||
}
|
||||
return mHandler!!
|
||||
}
|
||||
|
||||
override fun initUiAndData() {
|
||||
configureToolbar(emojiPickerToolbar)
|
||||
|
||||
requestEmojivUnicode10CompatibleFont()
|
||||
emojiCompatFontProvider.let {
|
||||
EmojiDrawView.configureTextPaint(this, it.typeface)
|
||||
it.addListener(this)
|
||||
}
|
||||
|
||||
tabLayout = findViewById(R.id.tabs)
|
||||
|
||||
@ -124,27 +116,13 @@ class EmojiReactionPickerActivity : VectorBaseActivity() {
|
||||
})
|
||||
}
|
||||
|
||||
private fun requestEmojivUnicode10CompatibleFont() {
|
||||
val fontRequest = FontRequest(
|
||||
"com.google.android.gms.fonts",
|
||||
"com.google.android.gms",
|
||||
"Noto Color Emoji Compat",
|
||||
R.array.com_google_android_gms_fonts_certs
|
||||
)
|
||||
|
||||
EmojiDrawView.configureTextPaint(this, null)
|
||||
val callback = object : FontsContractCompat.FontRequestCallback() {
|
||||
|
||||
override fun onTypefaceRetrieved(typeface: Typeface) {
|
||||
EmojiDrawView.configureTextPaint(this@EmojiReactionPickerActivity, typeface)
|
||||
override fun compatibilityFontUpdate(typeface: Typeface?) {
|
||||
EmojiDrawView.configureTextPaint(this, typeface)
|
||||
}
|
||||
|
||||
override fun onTypefaceRequestFailed(reason: Int) {
|
||||
Timber.e("Failed to load Emoji Compatible font, reason:$reason")
|
||||
}
|
||||
}
|
||||
|
||||
FontsContractCompat.requestFont(this, fontRequest, callback, getFontThreadHandler())
|
||||
override fun onDestroy() {
|
||||
emojiCompatFontProvider.removeListener(this)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
|
@ -21,6 +21,7 @@ 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
|
||||
@ -56,6 +57,11 @@ 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
|
||||
@ -97,6 +103,8 @@ class ReactionButton @JvmOverloads constructor(context: Context, attrs: Attribut
|
||||
|
||||
countTextView?.text = reactionCount.toString()
|
||||
|
||||
emojiView?.typeface = this.emojiTypeFace ?: Typeface.DEFAULT
|
||||
|
||||
val array = context.obtainStyledAttributes(attrs, R.styleable.ReactionButton, defStyleAttr, 0)
|
||||
|
||||
onDrawable = ContextCompat.getDrawable(context, R.drawable.rounded_rect_shape)
|
||||
|
Loading…
Reference in New Issue
Block a user