Skip to content

Commit

Permalink
refactor(symbol): tidy TabView, TabManager and SimpleKeyDao
Browse files Browse the repository at this point in the history
  • Loading branch information
WhiredPlanck committed Mar 8, 2024
1 parent e6ca3be commit de112cd
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 138 deletions.
4 changes: 1 addition & 3 deletions app/src/main/java/com/osfans/trime/ime/bar/QuickBar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ class QuickBar(context: Context, service: TrimeInputMethodService) {
}

val oldTabBar by lazy {
TabBarBinding.inflate(LayoutInflater.from(context)).apply {
tabs.reset()
}
TabBarBinding.inflate(LayoutInflater.from(context))
}

enum class State {
Expand Down
13 changes: 7 additions & 6 deletions app/src/main/java/com/osfans/trime/ime/symbol/LiquidKeyboard.kt
Original file line number Diff line number Diff line change
Expand Up @@ -286,12 +286,13 @@ class LiquidKeyboard(
}

service.lifecycleScope.launch {
val all = when (type) {
SymbolKeyboardType.CLIPBOARD -> ClipboardHelper.getAll()
SymbolKeyboardType.COLLECTION -> CollectionHelper.getAll()
SymbolKeyboardType.DRAFT -> DraftHelper.getAll()
else -> emptyList()
}
val all =
when (type) {
SymbolKeyboardType.CLIPBOARD -> ClipboardHelper.getAll()
SymbolKeyboardType.COLLECTION -> CollectionHelper.getAll()
SymbolKeyboardType.DRAFT -> DraftHelper.getAll()
else -> emptyList()
}
dbAdapter.updateBeans(all)
}
// 注册剪贴板更新监听器
Expand Down
27 changes: 10 additions & 17 deletions app/src/main/java/com/osfans/trime/ime/symbol/SimpleKeyDao.kt
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
package com.osfans.trime.ime.symbol

@Suppress("ktlint:standard:function-naming")
object SimpleKeyDao {
fun SimpleKeyboard(string: String): List<SimpleKeyBean> {
val strings = string.split("\n+".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val list: MutableList<SimpleKeyBean> = ArrayList()
for (str in strings) {
if (str.isEmpty()) continue
val keyBean = SimpleKeyBean(str)
list.add(keyBean)
}
return list
fun simpleKeyboardData(raw: String): List<SimpleKeyBean> {
val lines = raw.split("\n+".toRegex()).dropLastWhile { it.isEmpty() }
return lines.filterNot { it.isEmpty() }.map { SimpleKeyBean(it) }
}

fun Single(string: String): List<SimpleKeyBean> {
val list: MutableList<SimpleKeyBean> = ArrayList()
var h = 0.toChar()
for (element in string) {
if (element in '\uD800'..'\udbff') {
fun singleData(raw: String): List<SimpleKeyBean> {
val list = mutableListOf<SimpleKeyBean>()
var h = Char(0)
for (element in raw) {
if (element.isHighSurrogate()) {
h = element
} else if (element in '\udc00'..'\udfff') {
list.add(SimpleKeyBean(java.lang.String.valueOf(charArrayOf(h, element))))
} else if (element.isLowSurrogate()) {
list.add(SimpleKeyBean(String(charArrayOf(h, element))))
} else {
list.add(SimpleKeyBean(element.toString()))
}
Expand Down
17 changes: 7 additions & 10 deletions app/src/main/java/com/osfans/trime/ime/symbol/TabManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,11 @@ object TabManager {
type: SymbolKeyboardType,
keyBeans: List<SimpleKeyBean>,
) {
if (name.trim { it <= ' ' }.isEmpty()) return
if (name.isBlank()) return
if (SymbolKeyboardType.hasKeys(type)) {
for (i in tabTags.indices) {
val tag = tabTags[i]
if (tag.text == name) {
keyboards[i] = keyBeans
return
}
val index = tabTags.indexOfFirst { it.text == name }
if (index >= 0) {
keyboards[index] = keyBeans
}
}
tabTags.add(TabTag(name, type))
Expand All @@ -84,13 +81,13 @@ object TabManager {
// 处理single类型和no_key类型。前者把字符串切分为多个按键,后者把字符串转换为命令
if (keys is String) {
when (type) {
SymbolKeyboardType.SINGLE -> addListTab(name, type, SimpleKeyDao.Single(keys))
SymbolKeyboardType.SINGLE -> addListTab(name, type, SimpleKeyDao.singleData(keys))
SymbolKeyboardType.NO_KEY -> {
val commandType = KeyCommandType.fromString(keys)
tabTags.add(TabTag(name, type, commandType))
keyboards.add(notKeyboard)
}
else -> addListTab(name, type, SimpleKeyDao.SimpleKeyboard(keys))
else -> addListTab(name, type, SimpleKeyDao.simpleKeyboardData(keys))
}
}

Expand Down Expand Up @@ -123,8 +120,8 @@ object TabManager {
}

fun selectTabByIndex(index: Int): List<SimpleKeyBean> {
if (index !in tabTags.indices) return listOf()
currentTabIndex = index
if (index >= tabTags.size) return listOf()
val tag = tabTags[index]
if (tag.type == SymbolKeyboardType.TABS) tabSwitchPosition = currentTabIndex
return keyboards[index]
Expand Down
154 changes: 52 additions & 102 deletions app/src/main/java/com/osfans/trime/ime/symbol/TabView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Typeface
import android.graphics.drawable.PaintDrawable
import android.util.AttributeSet
import android.view.MotionEvent
Expand All @@ -35,48 +34,43 @@ import com.osfans.trime.ime.enums.KeyCommandType
import com.osfans.trime.ime.enums.SymbolKeyboardType
import com.osfans.trime.util.GraphicUtils.drawText
import com.osfans.trime.util.GraphicUtils.measureText
import com.osfans.trime.util.dp2px
import com.osfans.trime.util.sp
import splitties.dimensions.dp
import timber.log.Timber
import kotlin.math.abs

// 这是滑动键盘顶部的view,展示了键盘布局的多个标签。
// 为了公用候选栏的皮肤参数以及外观,大部分代码从Candidate.java复制而来。
class TabView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
private val theme = ThemeManager.activeTheme
private var highlightIndex = 0
private var tabTags: ArrayList<TabTag>? = null
private var candidateHighlight: PaintDrawable? = null
private val separatorPaint: Paint
private val candidatePaint: Paint
private var candidateFont: Typeface? = null
private var candidateTextColor = 0
private var hilitedCandidateTextColor = 0
private var candidateViewHeight = 0
private var commentHeight = 0
private var candidateSpacing = 0
private var candidatePadding = 0
private var isCommentOnTop = false
private var shouldCandidateUseCursor = false
private val tabTags = mutableListOf<TabTag>()
private val candidateHighlight =
PaintDrawable(ColorManager.getColor("hilited_candidate_back_color")!!).apply {
setCornerRadius(theme.style.getFloat("layout/round_corner"))
}
private val separatorPaint =
Paint().apply {
color = ColorManager.getColor("candidate_separator_color") ?: Color.BLACK
}
private val candidatePaint =
Paint().apply {
isAntiAlias = true
strokeWidth = 0f
textSize = sp(theme.style.getFloat("candidate_text_size"))
typeface = candidateFont
}
private val candidateFont = FontManager.getTypeface("candidate_font")
private val candidateTextColor = ColorManager.getColor("candidate_text_color")!!
private val hilitedCandidateTextColor = ColorManager.getColor("hilited_candidate_text_color")!!
private val candidateViewHeight = theme.style.getInt("candidate_view_height")
private val commentHeight = theme.style.getInt("comment_height")
private val candidateSpacing = theme.style.getFloat("candidate_spacing")
private val candidatePadding = theme.style.getFloat("candidate_padding")
private val isCommentOnTop = theme.style.getBoolean("comment_on_top")
private val shouldCandidateUseCursor = theme.style.getBoolean("comment_on_top")

// private final Rect[] tabGeometries = new Rect[MAX_CANDIDATE_COUNT + 2];
fun reset() {
val theme = ThemeManager.activeTheme
candidateHighlight = PaintDrawable(ColorManager.getColor("hilited_candidate_back_color")!!)
candidateHighlight!!.setCornerRadius(theme.style.getFloat("layout/round_corner"))
separatorPaint.color = ColorManager.getColor("candidate_separator_color")!!
candidateSpacing = dp2px(theme.style.getFloat("candidate_spacing")).toInt()
candidatePadding = dp2px(theme.style.getFloat("candidate_padding")).toInt()
candidateTextColor = ColorManager.getColor("candidate_text_color")!!
hilitedCandidateTextColor = ColorManager.getColor("hilited_candidate_text_color")!!
commentHeight = dp2px(theme.style.getFloat("comment_height")).toInt()
candidateViewHeight = dp2px(theme.style.getFloat("candidate_view_height")).toInt()
candidateFont = FontManager.getTypeface("candidate_font")
candidatePaint.textSize = sp(theme.style.getFloat("candidate_text_size"))
candidatePaint.setTypeface(candidateFont)
isCommentOnTop = theme.style.getBoolean("comment_on_top")
shouldCandidateUseCursor = theme.style.getBoolean("candidate_use_cursor")
invalidate()
}

override fun onMeasure(
widthMeasureSpec: Int,
Expand All @@ -85,7 +79,7 @@ class TabView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
val h = if (isCommentOnTop) candidateViewHeight + commentHeight else candidateViewHeight
setMeasuredDimension(
MeasureSpec.makeMeasureSpec(widthMeasureSpec, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(h, MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(dp(h), MeasureSpec.AT_MOST),
)
}

Expand All @@ -94,62 +88,51 @@ class TabView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
}

val highlightLeft: Int
get() = tabTags!![highlightIndex].geometry.left
get() = tabTags[highlightIndex].geometry.left
val highlightRight: Int
get() = tabTags!![highlightIndex].geometry.right
get() = tabTags[highlightIndex].geometry.right

override fun onDraw(canvas: Canvas) {
if (tabTags == null) return
if (tabTags.isEmpty()) return
super.onDraw(canvas)

// Draw highlight background
if (isHighlighted(highlightIndex)) {
candidateHighlight!!.bounds = tabTags!![highlightIndex].geometry
candidateHighlight!!.draw(canvas)
candidateHighlight.bounds = tabTags[highlightIndex].geometry
candidateHighlight.draw(canvas)
}
// Draw tab text
val tabY = (
/* (shouldShowComment && isCommentOnTop)
? tabTags.get(0).geometry.centerY()
- (candidatePaint.ascent() + candidatePaint.descent()) / 2.0f
+ commentHeight / 2.0f
: */
tabTags!![0].geometry.centerY() -
val tabY =
tabTags[0].geometry.centerY() -
(candidatePaint.ascent() + candidatePaint.descent()) / 2.0f
)
for ((i, computedTab) in tabTags!!.withIndex()) {
for ((i, computedTab) in tabTags.withIndex()) {
// Calculate a position where the text could be centered in the rectangle.
val tabX = computedTab.geometry.centerX().toFloat()
candidatePaint.color = if (isHighlighted(i)) hilitedCandidateTextColor else candidateTextColor
canvas.drawText(computedTab.text, tabX, tabY, candidatePaint, candidateFont!!)
canvas.drawText(computedTab.text, tabX, tabY, candidatePaint, candidateFont)
// Draw the separator at the right edge of each candidate.
canvas.drawRect(
(
computedTab.geometry.right - candidateSpacing
).toFloat(),
computedTab.geometry.right - dp(candidateSpacing),
computedTab.geometry.top.toFloat(),
(
computedTab.geometry.right + candidateSpacing
).toFloat(),
computedTab.geometry.right + dp(candidateSpacing),
computedTab.geometry.bottom.toFloat(),
separatorPaint,
)
}
}

fun updateTabWidth() {
tabTags = TabManager.tabCandidates
tabTags.clear()
tabTags.addAll(TabManager.tabCandidates)
highlightIndex = TabManager.selectedOrZero
var x = 0
for ((i, computedTab) in tabTags!!.withIndex()) {
for ((i, computedTab) in tabTags.withIndex()) {
computedTab.geometry.set(x, 0, (x + getTabWidth(i)).toInt(), height)
x = (x + (getTabWidth(i) + candidateSpacing)).toInt()
}
updateLayoutParams {
Timber.d("updateTabWidth: layoutPrams from: height=$height, width=$width")
width = x
height = if (isCommentOnTop) candidateViewHeight + commentHeight else candidateViewHeight
Timber.d("updateTabWidth: layoutPrams to: height=$height, width=$width")
height = dp(if (isCommentOnTop) candidateViewHeight + commentHeight else candidateViewHeight)
}
invalidate()
}
Expand All @@ -162,24 +145,17 @@ class TabView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
) {
super.onSizeChanged(w, h, oldw, oldh)
updateTabWidth()
Timber.d("onSizeChanged() w=$w, Height=$oldh=>$h")
}

override fun performClick(): Boolean {
return super.performClick()
}

var x0 = 0
var y0 = 0
private var x0 = 0
private var y0 = 0
private var time0: Long = 0

init {
candidatePaint = Paint()
candidatePaint.isAntiAlias = true
candidatePaint.strokeWidth = 0f
separatorPaint = Paint()
separatorPaint.color = Color.BLACK
reset()
setWillNotDraw(false)
}

Expand All @@ -195,58 +171,32 @@ class TabView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {

MotionEvent.ACTION_MOVE -> if (abs(x - x0) > 100) time0 = 0
MotionEvent.ACTION_UP -> {
val i = getTabIndex(x, y)
val i = tabTags.indexOfFirst { it.geometry.contains(x, y) }
if (i > -1) {
performClick()
val tag = TabManager.tabTags[i]
if (tag.type == SymbolKeyboardType.NO_KEY) {
when (tag.command) {
KeyCommandType.EXIT -> TrimeInputMethodService.getService().selectLiquidKeyboard(-1)
KeyCommandType.DEL_LEFT, KeyCommandType.DEL_RIGHT, KeyCommandType.REDO, KeyCommandType.UNDO -> {}
else -> {}
if (tag.command == KeyCommandType.EXIT) {
TrimeInputMethodService.getService().selectLiquidKeyboard(-1)
}
} else if (System.currentTimeMillis() - time0 < 500) {
highlightIndex = i
invalidate()
TrimeInputMethodService.getService().selectLiquidKeyboard(i)
}
Timber.d("index=" + i + " length=" + tabTags!!.size)
Timber.d("index=" + i + " length=" + tabTags.size)
}
}
}
return true
}

/**
* 獲得觸摸處候選項序號
*
* @param x 觸摸點橫座標
* @param y 觸摸點縱座標
* @return `>=0`: 觸摸點 (x, y) 處候選項序號,從0開始編號; `-1`: 觸摸點 (x, y) 處無候選項;
*/
private fun getTabIndex(
x: Int,
y: Int,
): Int {
// Rect r = new Rect();
var retIndex = -1 // Returns -1 if there is no tab in the hitting rectangle.
for (computedTab in tabTags!!) {
/* Enlarge the rectangle to be more responsive to user clicks.
// r.set(tabGeometries[j++]);
//r.inset(0, CANDIDATE_TOUCH_OFFSET); */
if (computedTab.geometry.contains(x, y)) {
retIndex = tabTags!!.indexOf(computedTab)
}
}
return retIndex
}

private fun getTabWidth(i: Int): Float {
val s = tabTags!![i].text
val s = tabTags[i].text
return if (s.isNotEmpty()) {
2 * candidatePadding + candidatePaint.measureText(s, candidateFont!!)
2 * dp(candidatePadding) + candidatePaint.measureText(s, candidateFont)
} else {
(2 * candidatePadding).toFloat()
2 * dp(candidatePadding)
}
}
}

0 comments on commit de112cd

Please sign in to comment.