Skip to content

Commit

Permalink
fix: candidate view in LiquidKeyboard didn't show all bulk candidates
Browse files Browse the repository at this point in the history
Now it's able to show the top 30 candidates, we will make it support lazy load to show all candidates in the future.
  • Loading branch information
WhiredPlanck committed Aug 27, 2024
1 parent e5f7309 commit e7e9543
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 81 deletions.
75 changes: 27 additions & 48 deletions app/src/main/java/com/osfans/trime/ime/symbol/CandidateAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@

package com.osfans.trime.ime.symbol

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.StateListDrawable
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter4.BaseQuickAdapter
import com.osfans.trime.core.CandidateListItem
import com.osfans.trime.core.Rime
import com.osfans.trime.data.theme.ColorManager
Expand All @@ -26,49 +28,45 @@ import splitties.views.dsl.constraintlayout.centerHorizontally
import splitties.views.dsl.constraintlayout.topOfParent

// 显示长度不固定,字体大小正常的内容。用于类型 CANDIDATE, VAR_LENGTH
class CandidateAdapter(theme: Theme) : RecyclerView.Adapter<CandidateAdapter.ViewHolder>() {
private val mCandidates = mutableListOf<CandidateListItem>()

class CandidateAdapter(private val theme: Theme) : BaseQuickAdapter<CandidateListItem, CandidateAdapter.ViewHolder>() {
enum class CommentPosition {
UNKNOWN,
TOP,
BOTTOM,
RIGHT,
}

@SuppressLint("NotifyDataSetChanged")
fun updateCandidates(candidates: List<CandidateListItem>) {
mCandidates.clear()
mCandidates.addAll(candidates)
notifyItemRangeChanged(0, candidates.size)
}

override fun getItemCount(): Int {
return mCandidates.size
}

private val mCandidateTextSize = theme.generalStyle.candidateTextSize.toFloat().coerceAtLeast(1f)
private val mCandidateFont = FontManager.getTypeface("candidate_font")
private val mCandidateTextColor = ColorManager.getColor("candidate_text_color")
private val mHilitedCandidateTextColor = ColorManager.getColor("hilited_candidate_text_color")
private val mHilitedCandidateBackColor = ColorManager.getColor("hilited_candidate_back_color")
private val mCommentPosition = theme.generalStyle.commentPosition
private val mCommentTextSize = theme.generalStyle.commentTextSize.toFloat().coerceAtLeast(1f)
private val mCommentFont = FontManager.getTypeface("comment_font")
private val mCommentTextColor = ColorManager.getColor("comment_text_color")
private val mBackground =
ColorManager.getDrawable(
key = "key_back_color",
border = theme.generalStyle.candidateBorder,
borderColorKey = "key_border_color",
roundCorner = theme.generalStyle.roundCorner,
)

override fun onCreateViewHolder(
context: Context,
parent: ViewGroup,
viewType: Int,
): ViewHolder {
val binding = LiquidEntryViewBinding.inflate(LayoutInflater.from(parent.context))
binding.root.background = mBackground
binding.root.background =
StateListDrawable().apply {
addState(
intArrayOf(),
ColorManager.getDrawable(
context = context,
key = "key_back_color",
border = theme.generalStyle.candidateBorder,
borderColorKey = "key_border_color",
roundCorner = theme.generalStyle.roundCorner,
),
)
mHilitedCandidateBackColor?.let {
addState(intArrayOf(android.R.attr.state_pressed), ColorDrawable(it))
}
}
binding.candidate.apply {
textSize = mCandidateTextSize
typeface = mCandidateFont
Expand Down Expand Up @@ -118,33 +116,14 @@ class CandidateAdapter(theme: Theme) : RecyclerView.Adapter<CandidateAdapter.Vie
val comment: TextView = binding.comment
}

@SuppressLint("ClickableViewAccessibility")
override fun onBindViewHolder(
holder: ViewHolder,
position: Int,
item: CandidateListItem?,
) {
val item = mCandidates[position]
holder.candidate.text = item.text
holder.comment.text = item.comment

// 如果设置了回调,则设置点击事件
holder.itemView.setOnClickListener { listener?.invoke(item, position) }

// 点击时产生背景变色效果
holder.itemView.setOnTouchListener { _, motionEvent: MotionEvent ->
if (motionEvent.action == MotionEvent.ACTION_DOWN) {
mHilitedCandidateTextColor?.let { holder.candidate.setTextColor(it) }
}
false
item?.run {
holder.candidate.text = text
holder.comment.text = comment
}
}

/** 添加 候选点击事件 Listener 回调 */
private var listener: (CandidateListItem.(Int) -> Unit)? = null

/** @param listener position
* */
fun setListener(listener: (CandidateListItem.(Int) -> Unit)?) {
this.listener = listener
}
}
60 changes: 27 additions & 33 deletions app/src/main/java/com/osfans/trime/ime/symbol/LiquidKeyboard.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,12 @@ import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ItemAnimator
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import com.google.android.flexbox.FlexDirection
import com.google.android.flexbox.FlexWrap
import com.chad.library.adapter4.util.setOnDebouncedItemClick
import com.google.android.flexbox.FlexboxLayoutManager
import com.google.android.flexbox.JustifyContent
import com.osfans.trime.core.CandidateListItem
import com.osfans.trime.core.Rime
import com.osfans.trime.daemon.RimeSession
import com.osfans.trime.data.SymbolHistory
import com.osfans.trime.data.db.ClipboardHelper
import com.osfans.trime.data.db.CollectionHelper
Expand All @@ -27,7 +25,7 @@ import com.osfans.trime.data.theme.Theme
import com.osfans.trime.ime.core.TrimeInputMethodService
import com.osfans.trime.ime.dependency.InputScope
import com.osfans.trime.ime.keyboard.KeyboardSwitcher
import com.osfans.trime.ime.text.TextInputManager
import com.osfans.trime.ime.text.Candidate
import com.osfans.trime.ime.window.BoardWindow
import com.osfans.trime.ime.window.ResidentWindow
import kotlinx.coroutines.launch
Expand All @@ -40,13 +38,13 @@ import timber.log.Timber
class LiquidKeyboard(
private val context: Context,
private val service: TrimeInputMethodService,
private val rime: RimeSession,
private val theme: Theme,
) : BoardWindow.BarBoardWindow(), ResidentWindow, ClipboardHelper.OnClipboardUpdateListener {
private lateinit var liquidLayout: LiquidLayout
private val symbolHistory = SymbolHistory(180)
private lateinit var currentBoardType: SymbolBoardType
private lateinit var currentBoardAdapter: RecyclerView.Adapter<*>
private var defaultKeyboardAnimation: ItemAnimator? = null

private val simpleAdapter by lazy {
val itemWidth = context.dp(theme.liquid.getInt("single_width"))
Expand All @@ -70,25 +68,33 @@ class LiquidKeyboard(

private val varLengthAdapter by lazy {
CandidateAdapter(theme).apply {
setListener { position ->
setOnDebouncedItemClick { _, _, position ->
val item = items[position]
when (currentBoardType) {
SymbolBoardType.CANDIDATE -> {
TextInputManager.instanceOrNull()
?.onCandidatePressed(position)
service.lifecycleScope.launch {
rime.runOnReady {
if (selectCandidate(position)) {
service.commitRimeText()
}
}
}
if (Rime.isComposing) {
val candidates = Rime.candidatesWithoutSwitch
updateCandidates(candidates.toList())
keyboardView.scrollToPosition(0)
service.lifecycleScope.launch {
val candidates = rime.runOnReady { getCandidates(0, Candidate.MAX_CANDIDATE_COUNT) }
submitList(candidates.toList())
keyboardView.scrollToPosition(0)
}
} else {
service.selectLiquidKeyboard(-1)
}
}
SymbolBoardType.SYMBOL -> service.inputSymbol(this.text)
SymbolBoardType.SYMBOL -> service.inputSymbol(item.text)
SymbolBoardType.TABS -> {
val realPosition = TabManager.tabTags.indexOfFirst { it.text == this.text }
val realPosition = TabManager.tabTags.indexOfFirst { it.text == item.text }
select(realPosition)
}
else -> service.currentInputConnection?.commitText(this.text, 1)
else -> service.currentInputConnection?.commitText(item.text, 1)
}
}
}
Expand Down Expand Up @@ -136,11 +142,7 @@ class LiquidKeyboard(
* 使用FlexboxLayoutManager时调用此函数获取
*/
private val flexboxLayoutManager by lazy {
FlexboxLayoutManager(context).apply {
flexDirection = FlexDirection.ROW // 主轴为水平方向,起点在左端。
flexWrap = FlexWrap.WRAP // 按正常方向换行
justifyContent = JustifyContent.FLEX_START // 交叉轴的起点对齐
}
FlexboxLayoutManager(context)
}

/**
Expand All @@ -160,7 +162,10 @@ class LiquidKeyboard(
SymbolBoardType.CLIPBOARD -> initDbData { ClipboardHelper.getAll() }
SymbolBoardType.COLLECTION -> initDbData { CollectionHelper.getAll() }
SymbolBoardType.DRAFT -> initDbData { DraftHelper.getAll() }
SymbolBoardType.CANDIDATE -> initVarLengthKeys(Rime.candidatesWithoutSwitch.toList())
SymbolBoardType.CANDIDATE ->
service.lifecycleScope.launch {
initVarLengthKeys(rime.runOnReady { getCandidates(0, Candidate.MAX_CANDIDATE_COUNT) }.toList())
}
SymbolBoardType.SYMBOL,
SymbolBoardType.VAR_LENGTH,
SymbolBoardType.TABS,
Expand All @@ -187,9 +192,6 @@ class LiquidKeyboard(
adapter = simpleAdapter
setItemViewCacheSize(10)
setHasFixedSize(true)
defaultKeyboardAnimation?.let {
keyboardView.itemAnimator = it
}
// 添加分割线
// 设置添加删除动画
// 调用ListView的setSelected(!ListView.isSelected())方法,这样就能及时刷新布局
Expand All @@ -208,9 +210,6 @@ class LiquidKeyboard(
adapter = dbAdapter
setItemViewCacheSize(10)
setHasFixedSize(false)
defaultKeyboardAnimation?.let {
keyboardView.itemAnimator = it
}
// 调用ListView的setSelected(!ListView.isSelected())方法,这样就能及时刷新布局
isSelected = true
}
Expand All @@ -228,16 +227,11 @@ class LiquidKeyboard(
layoutManager = flexboxLayoutManager
adapter = varLengthAdapter
setItemViewCacheSize(50)
// CandidateAdapter现在使用notifyItemRangeChanged,保存并禁用layout变化的缺省动画。
keyboardView.itemAnimator?.let {
defaultKeyboardAnimation = it
keyboardView.itemAnimator = null
}
setHasFixedSize(false)
isSelected = true
}
}
varLengthAdapter.updateCandidates(data)
varLengthAdapter.submitList(data)
}

/**
Expand Down

0 comments on commit e7e9543

Please sign in to comment.