0
0
mirror of https://github.com/florisboard/florisboard.git synced 2024-09-20 03:52:18 +02:00

Implement Kotlin coroutines to load EmojiKeyboardView async

- UI for EmojiKeyboardView is now loaded async upon creating the
  FlorisBoard UI, so it is ready when the user switches to the media
  context.
- Other small fixes.
This commit is contained in:
Patrick Goldinger 2020-05-20 20:19:19 +02:00
parent a5da7f1529
commit 315e6a3b2c
5 changed files with 47 additions and 29 deletions

View File

@ -37,4 +37,6 @@ dependencies {
implementation 'com.google.android:flexbox:2.0.1'
implementation "com.squareup.moshi:moshi-kotlin:1.9.2"
implementation 'com.google.android.material:material:1.1.0'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7"
}

View File

@ -66,7 +66,13 @@ class MediaInputManager(private val florisboard: FlorisBoard) : FlorisBoard.Even
override fun onTabReselected(tab: TabLayout.Tab) {}
})
setActiveTab(Tab.HOME)
for (tab in Tab.values()) {
val tabView = createTabViewFor(tab)
tabViews[tab] = tabView
mediaViewFlipper?.addView(tabView)
}
tabLayout?.selectTab(tabLayout?.getTabAt(1))
}
private fun onBottomButtonClick(v: View) {
@ -95,11 +101,6 @@ class MediaInputManager(private val florisboard: FlorisBoard) : FlorisBoard.Even
}
fun setActiveTab(newActiveTab: Tab) {
if (!tabViews.containsKey(newActiveTab)) {
val tabView = createTabViewFor(newActiveTab)
tabViews[newActiveTab] = tabView
mediaViewFlipper?.addView(tabView)
}
mediaViewFlipper?.displayedChild =
mediaViewFlipper?.indexOfChild(tabViews[newActiveTab]) ?: 0
activeTab = newActiveTab

View File

@ -6,7 +6,6 @@ import android.util.TypedValue
import android.view.Gravity
import android.view.MotionEvent
import android.widget.HorizontalScrollView
import androidx.core.content.ContextCompat
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.core.FlorisBoard
@ -15,13 +14,13 @@ class EmojiKeyView(
private val florisboard: FlorisBoard,
private val emojiKeyboardView: EmojiKeyboardView,
val data: EmojiKeyData
) : androidx.appcompat.widget.AppCompatButton(florisboard.context) {
) : androidx.appcompat.widget.AppCompatTextView(florisboard.context) {
private var isCancelled: Boolean = false
private val osHandler = Handler()
private var osHandler: Handler? = null
init {
setBackgroundColor(ContextCompat.getColor(context, android.R.color.transparent))
background = null
gravity = Gravity.CENTER
setPadding(0, 0, 0, 0)
setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.dimen.emoji_key_textSize))
@ -37,7 +36,10 @@ class EmojiKeyView(
MotionEvent.ACTION_DOWN -> {
isCancelled = false
val delayMillis = florisboard.prefs!!.longPressDelay
osHandler.postDelayed({
if (osHandler == null) {
osHandler = Handler()
}
osHandler?.postDelayed({
(parent.parent as HorizontalScrollView).requestDisallowInterceptTouchEvent(true)
emojiKeyboardView.isScrollBlocked = true
emojiKeyboardView.popupManager.show(this)
@ -63,7 +65,7 @@ class EmojiKeyView(
}
MotionEvent.ACTION_UP,
MotionEvent.ACTION_CANCEL -> {
osHandler.removeCallbacksAndMessages(null)
osHandler?.removeCallbacksAndMessages(null)
val retData = emojiKeyboardView.popupManager.getActiveEmojiKeyData(this)
emojiKeyboardView.popupManager.hide()
if (event.actionMasked != MotionEvent.ACTION_CANCEL && retData != null && !isCancelled) {

View File

@ -14,20 +14,19 @@ import com.google.android.material.tabs.TabLayout
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import dev.patrickgold.florisboard.ime.popup.KeyPopupManager
import kotlinx.coroutines.*
import java.util.*
@SuppressLint("ViewConstructor")
class EmojiKeyboardView(
private val florisboard: FlorisBoard
) : LinearLayout(florisboard.context) {
) : LinearLayout(florisboard.context), CoroutineScope by MainScope() {
private var activeCategory: EmojiCategory = EmojiCategory.SMILEYS_EMOTION
private var emojiViewFlipper: ViewFlipper
private val emojiKeyWidth = resources.getDimension(R.dimen.emoji_key_width).toInt()
private val emojiKeyHeight = resources.getDimension(R.dimen.emoji_key_height).toInt()
// TODO: run this task async (coroutines?) to avoid blocking the ui thread
private val layouts =
parseRawEmojiSpecsFile(context, "ime/emoji/emoji-test.txt")
private var layouts: EmojiLayoutDataMap? = null
private val uiLayouts = EnumMap<EmojiCategory, HorizontalScrollView>(EmojiCategory::class.java)
var isScrollBlocked: Boolean = false
@ -43,12 +42,6 @@ class EmojiKeyboardView(
emojiViewFlipper.measureAllChildren = false
addView(emojiViewFlipper)
for (category in EmojiCategory.values()) {
val hsv = buildLayoutForCategory(category)
uiLayouts[category] = hsv
emojiViewFlipper.addView(hsv)
}
val tabs = ViewGroup.inflate(context, R.layout.media_input_emoji_tabs, null) as TabLayout
addView(tabs)
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
@ -71,19 +64,37 @@ class EmojiKeyboardView(
override fun onTabUnselected(tab: TabLayout.Tab?) {}
})
setActiveCategory(EmojiCategory.SMILEYS_EMOTION)
launch {
layouts = withContext(Dispatchers.IO) {
parseRawEmojiSpecsFile(context, "ime/emoji/emoji-test.txt")
}
buildLayout()
setActiveCategory(EmojiCategory.SMILEYS_EMOTION)
}
}
private suspend fun buildLayout() = withContext(Dispatchers.Default) {
for (category in EmojiCategory.values()) {
val hsv = buildLayoutForCategory(category)
uiLayouts[category] = hsv
withContext(Dispatchers.Main) {
emojiViewFlipper.addView(hsv)
}
}
}
@SuppressLint("ClickableViewAccessibility")
private fun buildLayoutForCategory(category: EmojiCategory): HorizontalScrollView {
private suspend fun buildLayoutForCategory(
category: EmojiCategory
): HorizontalScrollView = withContext(Dispatchers.Default) {
val hsv = HorizontalScrollView(context)
hsv.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
val flexboxLayout = FlexboxLayout(context)
flexboxLayout.layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, emojiKeyHeight * 3)
flexboxLayout.flexDirection = FlexDirection.COLUMN
flexboxLayout.flexWrap = FlexWrap.WRAP
for (emojiKeyData in layouts[category].orEmpty()) {
val emojiKeyView = EmojiKeyView(florisboard, this, emojiKeyData)
for (emojiKeyData in layouts.orEmpty()[category].orEmpty()) {
val emojiKeyView = EmojiKeyView(florisboard, this@EmojiKeyboardView, emojiKeyData)
emojiKeyView.layoutParams = FlexboxLayout.LayoutParams(
emojiKeyWidth, emojiKeyHeight
)
@ -93,7 +104,7 @@ class EmojiKeyboardView(
return@setOnTouchListener isScrollBlocked
}
hsv.addView(flexboxLayout)
return hsv
return@withContext hsv
}
fun setActiveCategory(newActiveCategory: EmojiCategory) {

View File

@ -29,6 +29,8 @@ private const val BALD = "1F9B3"
private val NAME_JUNK_SPLIT_REGEX = "E([0-9]+)\\.([0-9]+)\\s+".toRegex()
private val CODE_POINT_REGEX = "([a-fA-F0-9]+)\\s".toRegex()
typealias EmojiLayoutDataMap = EnumMap<EmojiCategory, MutableList<EmojiKeyData>>
private fun listStringToListInt(list: List<String>): List<Int> {
val ret: MutableList<Int> = mutableListOf()
for (num in list) {
@ -41,8 +43,8 @@ private fun listStringToListInt(list: List<String>): List<Int> {
fun parseRawEmojiSpecsFile(
context: Context, path: String
): EnumMap<EmojiCategory, MutableList<EmojiKeyData>> {
val layouts = EnumMap<EmojiCategory, MutableList<EmojiKeyData>>(EmojiCategory::class.java)
): EmojiLayoutDataMap {
val layouts = EmojiLayoutDataMap(EmojiCategory::class.java)
for (category in EmojiCategory.values()) {
layouts[category] = mutableListOf()
}