6
6
package org.fcitx.fcitx5.android.input
7
7
8
8
import android.annotation.SuppressLint
9
+ import android.content.res.ColorStateList
9
10
import android.graphics.Color
10
11
import android.graphics.drawable.GradientDrawable
11
12
import android.view.View
12
13
import android.view.ViewGroup
14
+ import android.widget.ImageView
15
+ import androidx.annotation.DrawableRes
13
16
import androidx.annotation.Size
14
17
import androidx.constraintlayout.widget.ConstraintLayout
15
- import androidx.core.view.isVisible
16
18
import androidx.lifecycle.lifecycleScope
19
+ import com.google.android.flexbox.AlignItems
17
20
import com.google.android.flexbox.FlexDirection
18
21
import com.google.android.flexbox.FlexWrap
19
22
import com.google.android.flexbox.FlexboxLayout
@@ -26,16 +29,24 @@ import org.fcitx.fcitx5.android.data.theme.Theme
26
29
import org.fcitx.fcitx5.android.input.candidates.CandidateItemUi
27
30
import org.fcitx.fcitx5.android.input.preedit.PreeditUi
28
31
import splitties.dimensions.dp
32
+ import splitties.resources.drawable
29
33
import splitties.views.backgroundColor
34
+ import splitties.views.dsl.constraintlayout.before
30
35
import splitties.views.dsl.constraintlayout.below
31
36
import splitties.views.dsl.constraintlayout.bottomOfParent
37
+ import splitties.views.dsl.constraintlayout.centerVertically
38
+ import splitties.views.dsl.constraintlayout.constraintLayout
39
+ import splitties.views.dsl.constraintlayout.endOfParent
32
40
import splitties.views.dsl.constraintlayout.lParams
41
+ import splitties.views.dsl.constraintlayout.matchConstraints
33
42
import splitties.views.dsl.constraintlayout.startOfParent
34
43
import splitties.views.dsl.constraintlayout.topOfParent
35
44
import splitties.views.dsl.core.add
45
+ import splitties.views.dsl.core.imageView
36
46
import splitties.views.dsl.core.withTheme
37
47
import splitties.views.dsl.core.wrapContent
38
48
import splitties.views.horizontalPadding
49
+ import splitties.views.imageDrawable
39
50
import splitties.views.verticalPadding
40
51
41
52
@SuppressLint(" ViewConstructor" )
@@ -70,6 +81,8 @@ class CandidatesView(
70
81
private val anchorPosition = floatArrayOf(0f , 0f , 0f )
71
82
private val parentSize = floatArrayOf(0f , 0f )
72
83
84
+ private var shouldUpdatePosition = false
85
+
73
86
private val preeditUi = object : PreeditUi (ctx, theme) {
74
87
override val bkgColor = Color .TRANSPARENT
75
88
}
@@ -84,6 +97,37 @@ class CandidatesView(
84
97
dividerDrawableVertical = GradientDrawable ().apply {
85
98
setSize(dp(4 ), 0 )
86
99
}
100
+ // update position after layout child views and before drawing to avoid flicker
101
+ viewTreeObserver.addOnPreDrawListener {
102
+ if (shouldUpdatePosition) {
103
+ updatePosition()
104
+ }
105
+ true
106
+ }
107
+ }
108
+
109
+ private fun createIcon (@DrawableRes icon : Int ) = imageView {
110
+ imageTintList = ColorStateList .valueOf(theme.keyTextColor)
111
+ imageDrawable = drawable(icon)
112
+ scaleType = ImageView .ScaleType .CENTER_CROP
113
+ }
114
+
115
+ private val prevIcon = createIcon(R .drawable.ic_baseline_arrow_left_24)
116
+ private val nextIcon = createIcon(R .drawable.ic_baseline_arrow_right_24)
117
+
118
+ private val paginationLayout = constraintLayout {
119
+ add(nextIcon, lParams(dp(10 ), matchConstraints) {
120
+ centerVertically()
121
+ endOfParent()
122
+ })
123
+ add(prevIcon, lParams(dp(10 ), matchConstraints) {
124
+ centerVertically()
125
+ before(nextIcon)
126
+ })
127
+ layoutParams = FlexboxLayout .LayoutParams (wrapContent, wrapContent).apply {
128
+ flexGrow = 1f
129
+ alignSelf = AlignItems .STRETCH
130
+ }
87
131
}
88
132
89
133
private fun handleFcitxEvent (it : FcitxEvent <* >) {
@@ -109,11 +153,10 @@ class CandidatesView(
109
153
110
154
private fun updateUI () {
111
155
if (evaluateVisibility()) {
112
- visibility = View .VISIBLE
113
156
preeditUi.update(inputPanel)
114
- preeditUi.root.isVisible = preeditUi.visible
157
+ preeditUi.root.visibility = if ( preeditUi.visible) View . VISIBLE else View . GONE
115
158
updateCandidates()
116
- updatePosition()
159
+ visibility = View . VISIBLE
117
160
} else {
118
161
visibility = View .GONE
119
162
}
@@ -125,15 +168,24 @@ class CandidatesView(
125
168
FcitxEvent .PagedCandidateEvent .LayoutHint .Vertical -> FlexDirection .COLUMN
126
169
else -> FlexDirection .ROW
127
170
}
128
- paged.candidates.forEach {
171
+ paged.candidates.forEachIndexed { i, it ->
129
172
val item = CandidateItemUi (ctx, theme).apply {
130
173
text.textSize = 16f
131
174
// TODO different font for comment
132
175
text.text = " ${it.label}${it.text} ${it.comment} "
176
+ if (i == paged.cursorIndex) {
177
+ root.backgroundColor = theme.genericActiveBackgroundColor
178
+ text.setTextColor(theme.genericActiveForegroundColor)
179
+ }
133
180
}
134
181
candidatesLayout.addView(item.root, FlexboxLayout .LayoutParams (- 2 , - 2 ))
135
182
}
136
- // TODO paging indicator
183
+ if (paged.hasPrev || paged.hasNext) {
184
+ prevIcon.alpha = if (paged.hasPrev) 1f else 0.4f
185
+ nextIcon.alpha = if (paged.hasNext) 1f else 0.4f
186
+ candidatesLayout.addView(paginationLayout)
187
+ }
188
+ shouldUpdatePosition = true
137
189
}
138
190
139
191
private fun updatePosition () {
@@ -144,6 +196,7 @@ class CandidatesView(
144
196
translationX =
145
197
if (horizontal + selfWidth > parentWidth) parentWidth - selfWidth else horizontal
146
198
translationY = if (bottom + selfHeight > parentHeight) top - selfHeight else bottom
199
+ shouldUpdatePosition = false
147
200
}
148
201
149
202
fun updateCursorAnchor (@Size(4 ) anchor : FloatArray , @Size(2 ) parent : FloatArray ) {
0 commit comments