Skip to content

Commit f84dddd

Browse files
committed
Minor refactor in ExpandedCandidateWindow
Improve performance a little and fix a rare crash (hopefully)
1 parent d85b544 commit f84dddd

File tree

7 files changed

+57
-55
lines changed

7 files changed

+57
-55
lines changed

app/src/main/java/org/fcitx/fcitx5/android/input/candidates/expanded/CandidatesPagingSource.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* SPDX-License-Identifier: LGPL-2.1-or-later
3-
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
3+
* SPDX-FileCopyrightText: Copyright 2021-2024 Fcitx5 for Android Contributors
44
*/
55
package org.fcitx.fcitx5.android.input.candidates.expanded
66

@@ -13,7 +13,7 @@ class CandidatesPagingSource(val fcitx: FcitxConnection, val total: Int, val off
1313
PagingSource<Int, String>() {
1414

1515
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, String> {
16-
// use candidate index for key, null means load from beginning (including offset)
16+
// use candidate index for key, null means load from beginning (with offset)
1717
val startIndex = params.key ?: offset
1818
val pageSize = params.loadSize
1919
Timber.d("getCandidates(offset=$startIndex, limit=$pageSize)")

app/src/main/java/org/fcitx/fcitx5/android/input/candidates/expanded/ExpandedCandidateLayout.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* SPDX-License-Identifier: LGPL-2.1-or-later
3-
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
3+
* SPDX-FileCopyrightText: Copyright 2021-2024 Fcitx5 for Android Contributors
44
*/
55
package org.fcitx.fcitx5.android.input.candidates.expanded
66

@@ -10,7 +10,12 @@ import androidx.constraintlayout.widget.ConstraintLayout
1010
import org.fcitx.fcitx5.android.R
1111
import org.fcitx.fcitx5.android.data.theme.Theme
1212
import org.fcitx.fcitx5.android.data.theme.ThemeManager
13-
import org.fcitx.fcitx5.android.input.keyboard.*
13+
import org.fcitx.fcitx5.android.input.keyboard.BackspaceKey
14+
import org.fcitx.fcitx5.android.input.keyboard.BaseKeyboard
15+
import org.fcitx.fcitx5.android.input.keyboard.ImageKeyView
16+
import org.fcitx.fcitx5.android.input.keyboard.ImageLayoutSwitchKey
17+
import org.fcitx.fcitx5.android.input.keyboard.KeyDef
18+
import org.fcitx.fcitx5.android.input.keyboard.ReturnKey
1419
import splitties.views.backgroundColor
1520
import splitties.views.dsl.constraintlayout.bottomOfParent
1621
import splitties.views.dsl.constraintlayout.lParams

app/src/main/java/org/fcitx/fcitx5/android/input/candidates/expanded/GridPagingCandidateViewAdapter.kt

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,24 @@ import splitties.views.dsl.core.matchParent
1717

1818
abstract class GridPagingCandidateViewAdapter(theme: Theme) : PagingCandidateViewAdapter(theme) {
1919

20+
companion object {
21+
// 20f here is chosen randomly, since we only care about the ratio
22+
private const val TEXT_SIZE = 20f
23+
}
24+
2025
// cache measureWidth
21-
private val measuredWidths = LruCache<String, Float>(200)
26+
private val measuredWidths = object : LruCache<String, Float>(200) {
27+
private val cachedPaint = Paint().apply { textSize = TEXT_SIZE }
28+
private val cachedRect = Rect()
29+
override fun create(key: String): Float {
30+
cachedPaint.getTextBounds(key, 0, key.length, cachedRect)
31+
return cachedRect.width() / TEXT_SIZE
32+
}
33+
}
2234

2335
fun measureWidth(position: Int): Float {
2436
val candidate = getItem(position) ?: return 0f
25-
return measuredWidths[candidate] ?: run {
26-
val paint = Paint()
27-
val bounds = Rect()
28-
// 20f here is chosen randomly, since we only care about the ratio
29-
paint.textSize = 20f
30-
paint.getTextBounds(candidate, 0, candidate.length, bounds)
31-
(bounds.width() / 20f).also { measuredWidths.put(candidate, it) }
32-
}
37+
return measuredWidths[candidate]
3338
}
3439

3540
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CandidateViewHolder {

app/src/main/java/org/fcitx/fcitx5/android/input/candidates/expanded/window/BaseExpandedCandidateWindow.kt

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
/*
22
* SPDX-License-Identifier: LGPL-2.1-or-later
3-
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
3+
* SPDX-FileCopyrightText: Copyright 2021-2024 Fcitx5 for Android Contributors
44
*/
55

66
package org.fcitx.fcitx5.android.input.candidates.expanded.window
77

88
import android.graphics.drawable.ShapeDrawable
99
import android.graphics.drawable.shapes.RectShape
1010
import android.view.View
11-
import androidx.lifecycle.LifecycleCoroutineScope
12-
import androidx.lifecycle.findViewTreeLifecycleOwner
1311
import androidx.lifecycle.lifecycleScope
1412
import androidx.paging.Pager
1513
import androidx.paging.PagingConfig
1614
import androidx.recyclerview.widget.RecyclerView
17-
import kotlinx.coroutines.Dispatchers
1815
import kotlinx.coroutines.Job
16+
import kotlinx.coroutines.flow.collectLatest
1917
import kotlinx.coroutines.launch
2018
import org.fcitx.fcitx5.android.daemon.launchOnReady
2119
import org.fcitx.fcitx5.android.data.prefs.AppPrefs
@@ -26,10 +24,10 @@ import org.fcitx.fcitx5.android.input.bar.KawaiiBarComponent
2624
import org.fcitx.fcitx5.android.input.broadcast.InputBroadcastReceiver
2725
import org.fcitx.fcitx5.android.input.broadcast.ReturnKeyDrawableComponent
2826
import org.fcitx.fcitx5.android.input.candidates.CandidateViewHolder
29-
import org.fcitx.fcitx5.android.input.candidates.horizontal.HorizontalCandidateComponent
30-
import org.fcitx.fcitx5.android.input.candidates.expanded.PagingCandidateViewAdapter
3127
import org.fcitx.fcitx5.android.input.candidates.expanded.CandidatesPagingSource
3228
import org.fcitx.fcitx5.android.input.candidates.expanded.ExpandedCandidateLayout
29+
import org.fcitx.fcitx5.android.input.candidates.expanded.PagingCandidateViewAdapter
30+
import org.fcitx.fcitx5.android.input.candidates.horizontal.HorizontalCandidateComponent
3331
import org.fcitx.fcitx5.android.input.dependency.fcitx
3432
import org.fcitx.fcitx5.android.input.dependency.inputMethodService
3533
import org.fcitx.fcitx5.android.input.dependency.theme
@@ -57,7 +55,6 @@ abstract class BaseExpandedCandidateWindow<T : BaseExpandedCandidateWindow<T>> :
5755

5856
protected val disableAnimation by AppPrefs.getInstance().advanced.disableAnimation
5957

60-
private lateinit var lifecycleCoroutineScope: LifecycleCoroutineScope
6158
private lateinit var candidateLayout: ExpandedCandidateLayout
6259

6360
protected val dividerDrawable by lazy {
@@ -98,13 +95,19 @@ abstract class BaseExpandedCandidateWindow<T : BaseExpandedCandidateWindow<T>> :
9895
private var offsetJob: Job? = null
9996

10097
private val candidatesPager by lazy {
101-
Pager(PagingConfig(pageSize = 48)) {
102-
CandidatesPagingSource(
103-
fcitx,
104-
total = horizontalCandidate.adapter.total,
105-
offset = adapter.offset
106-
)
107-
}
98+
Pager(
99+
config = PagingConfig(
100+
pageSize = 48,
101+
enablePlaceholders = false
102+
),
103+
pagingSourceFactory = {
104+
CandidatesPagingSource(
105+
fcitx,
106+
total = horizontalCandidate.adapter.total,
107+
offset = adapter.offset
108+
)
109+
}
110+
)
108111
}
109112
private var candidatesSubmitJob: Job? = null
110113

@@ -113,19 +116,23 @@ abstract class BaseExpandedCandidateWindow<T : BaseExpandedCandidateWindow<T>> :
113116
abstract fun nextPage()
114117

115118
override fun onAttached() {
116-
lifecycleCoroutineScope = candidateLayout.findViewTreeLifecycleOwner()!!.lifecycleScope
117119
bar.expandButtonStateMachine.push(ExpandedCandidatesAttached)
118120
candidateLayout.embeddedKeyboard.also {
119121
it.onReturnDrawableUpdate(returnKeyDrawable.resourceId)
120122
it.keyActionListener = keyActionListener
121123
}
122-
offsetJob = lifecycleCoroutineScope.launch {
124+
offsetJob = service.lifecycleScope.launch {
123125
horizontalCandidate.expandedCandidateOffset.collect {
124-
updateCandidatesWithOffset(it)
126+
if (it <= 0) {
127+
windowManager.attachWindow(KeyboardWindow)
128+
} else {
129+
candidateLayout.resetPosition()
130+
adapter.refreshWithOffset(it)
131+
}
125132
}
126133
}
127-
candidatesSubmitJob = lifecycleCoroutineScope.launch {
128-
candidatesPager.flow.collect {
134+
candidatesSubmitJob = service.lifecycleScope.launch {
135+
candidatesPager.flow.collectLatest {
129136
adapter.submitData(it)
130137
}
131138
}
@@ -141,18 +148,6 @@ abstract class BaseExpandedCandidateWindow<T : BaseExpandedCandidateWindow<T>> :
141148
}
142149
}
143150

144-
private fun updateCandidatesWithOffset(offset: Int) {
145-
val candidates = horizontalCandidate.adapter.candidates
146-
if (candidates.isEmpty()) {
147-
windowManager.attachWindow(KeyboardWindow)
148-
} else {
149-
adapter.refreshWithOffset(offset)
150-
lifecycleCoroutineScope.launch(Dispatchers.Main) {
151-
candidateLayout.resetPosition()
152-
}
153-
}
154-
}
155-
156151
override fun onDetached() {
157152
bar.expandButtonStateMachine.push(
158153
ExpandedCandidatesDetached,

app/src/main/java/org/fcitx/fcitx5/android/input/candidates/expanded/window/FlexboxExpandedCandidateWindow.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* SPDX-License-Identifier: LGPL-2.1-or-later
3-
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
3+
* SPDX-FileCopyrightText: Copyright 2021-2024 Fcitx5 for Android Contributors
44
*/
55

66
package org.fcitx.fcitx5.android.input.candidates.expanded.window
@@ -59,9 +59,9 @@ class FlexboxExpandedCandidateWindow :
5959
addOnScrollListener(object : RecyclerView.OnScrollListener() {
6060
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
6161
this@FlexboxExpandedCandidateWindow.layoutManager.apply {
62-
pageUpBtn.isEnabled = findFirstCompletelyVisibleItemPosition() != 0
62+
pageUpBtn.isEnabled = findFirstCompletelyVisibleItemPosition() > 0
6363
pageDnBtn.isEnabled =
64-
findLastCompletelyVisibleItemPosition() != itemCount - 1
64+
findLastCompletelyVisibleItemPosition() < itemCount - 1
6565
}
6666
}
6767
})

app/src/main/java/org/fcitx/fcitx5/android/input/candidates/expanded/window/GridExpandedCandidateWindow.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* SPDX-License-Identifier: LGPL-2.1-or-later
3-
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
3+
* SPDX-FileCopyrightText: Copyright 2021-2024 Fcitx5 for Android Contributors
44
*/
55

66
package org.fcitx.fcitx5.android.input.candidates.expanded.window
@@ -53,9 +53,9 @@ class GridExpandedCandidateWindow :
5353
addOnScrollListener(object : RecyclerView.OnScrollListener() {
5454
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
5555
(recyclerView.layoutManager as GridLayoutManager).apply {
56-
pageUpBtn.isEnabled = findFirstCompletelyVisibleItemPosition() != 0
56+
pageUpBtn.isEnabled = findFirstCompletelyVisibleItemPosition() > 0
5757
pageDnBtn.isEnabled =
58-
findLastCompletelyVisibleItemPosition() != itemCount - 1
58+
findLastCompletelyVisibleItemPosition() < itemCount - 1
5959
}
6060
}
6161
})

app/src/main/java/org/fcitx/fcitx5/android/input/candidates/horizontal/HorizontalCandidateComponent.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import kotlinx.coroutines.channels.BufferOverflow
2020
import kotlinx.coroutines.flow.MutableSharedFlow
2121
import kotlinx.coroutines.flow.asSharedFlow
2222
import kotlinx.coroutines.launch
23-
import kotlinx.coroutines.runBlocking
2423
import org.fcitx.fcitx5.android.R
2524
import org.fcitx.fcitx5.android.core.FcitxEvent
2625
import org.fcitx.fcitx5.android.daemon.launchOnReady
@@ -32,10 +31,10 @@ import org.fcitx.fcitx5.android.input.bar.KawaiiBarComponent
3231
import org.fcitx.fcitx5.android.input.broadcast.InputBroadcastReceiver
3332
import org.fcitx.fcitx5.android.input.candidates.CandidateItemUi
3433
import org.fcitx.fcitx5.android.input.candidates.CandidateViewHolder
34+
import org.fcitx.fcitx5.android.input.candidates.expanded.decoration.FlexboxVerticalDecoration
3535
import org.fcitx.fcitx5.android.input.candidates.horizontal.HorizontalCandidateMode.AlwaysFillWidth
3636
import org.fcitx.fcitx5.android.input.candidates.horizontal.HorizontalCandidateMode.AutoFillWidth
3737
import org.fcitx.fcitx5.android.input.candidates.horizontal.HorizontalCandidateMode.NeverFillWidth
38-
import org.fcitx.fcitx5.android.input.candidates.expanded.decoration.FlexboxVerticalDecoration
3938
import org.fcitx.fcitx5.android.input.dependency.UniqueViewComponent
4039
import org.fcitx.fcitx5.android.input.dependency.context
4140
import org.fcitx.fcitx5.android.input.dependency.fcitx
@@ -88,9 +87,7 @@ class HorizontalCandidateComponent :
8887
val expandedCandidateOffset = _expandedCandidateOffset.asSharedFlow()
8988

9089
private fun refreshExpanded() {
91-
runBlocking {
92-
_expandedCandidateOffset.emit(view.childCount)
93-
}
90+
_expandedCandidateOffset.tryEmit(view.childCount)
9491
bar.expandButtonStateMachine.push(
9592
ExpandedCandidatesUpdated,
9693
ExpandedCandidatesEmpty to (adapter.total == layoutManager.childCount)

0 commit comments

Comments
 (0)