Skip to content

Commit f6e391f

Browse files
feat: add ASCII mode switch indicator
1 parent 0fb6cb7 commit f6e391f

File tree

8 files changed

+108
-5
lines changed

8 files changed

+108
-5
lines changed

app/src/main/java/com/osfans/trime/data/prefs/AppPrefs.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,13 @@ class AppPrefs(
199199
const val MODE = "show_candidates_window"
200200
const val LAYOUT = "candidates_layout"
201201
const val POSITION = "candidates_window_position"
202+
const val ASCII_INDICATOR = "show_ascii_indicator"
202203
}
203204

204205
val mode = enum(R.string.show_candidates_window, MODE, PopupCandidatesMode.DISABLED)
205206
val layout = enum(R.string.candidates_layout, LAYOUT, PopupCandidatesLayout.AUTOMATIC)
206207
val position = enum(R.string.candidates_window_position, POSITION, PopupPosition.BOTTOM_LEFT)
208+
val asciiIndicator = switch(R.string.show_ascii_indicator, ASCII_INDICATOR, true)
207209
}
208210

209211
/**

app/src/main/java/com/osfans/trime/ime/composition/CandidatesView.kt

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class CandidatesView(
5656

5757
private val layout by AppPrefs.defaultInstance().candidates.layout
5858
private val position by AppPrefs.defaultInstance().candidates.position
59+
private val showAsciiIndicator by AppPrefs.defaultInstance().candidates.asciiIndicator
5960

6061
private val composingTextMode by AppPrefs.defaultInstance().general.composingTextMode
6162

@@ -110,6 +111,8 @@ class CandidatesView(
110111

111112
private var bottomInsets = 0
112113

114+
private var shouldShowAsciiIndicator = false
115+
113116
override fun handleRimeMessage(it: RimeMessage<*>) {
114117
when (it) {
115118
is RimeMessage.CompositionMessage -> {
@@ -124,12 +127,28 @@ class CandidatesView(
124127
menu = it.data
125128
updateUi()
126129
}
130+
is RimeMessage.OptionMessage -> {
131+
if (!showAsciiIndicator || it.data.option != "ascii_mode") return
132+
val text = if (it.data.value) "En" else rime.run { statusCached }.schemaName.take(2)
133+
preeditUi.root.post {
134+
shouldShowAsciiIndicator = true
135+
visibility = VISIBLE
136+
candidatesUi.root.visibility = GONE
137+
preeditUi.show(text) {
138+
shouldShowAsciiIndicator = false
139+
visibility = INVISIBLE
140+
candidatesUi.root.visibility = VISIBLE
141+
}
142+
}
143+
}
144+
127145
else -> {}
128146
}
129147
}
130148

131149
private fun evaluateVisibility(): Boolean = !composition.preedit.isNullOrEmpty() ||
132-
menu.candidates.isNotEmpty()
150+
menu.candidates.isNotEmpty() ||
151+
shouldShowAsciiIndicator
133152

134153
private fun updateUi() {
135154
preeditUi.update(composition)

app/src/main/java/com/osfans/trime/ime/composition/PreeditModule.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@ import android.content.Context
99
import android.graphics.drawable.GradientDrawable
1010
import android.view.View
1111
import android.view.ViewOutlineProvider
12+
import com.osfans.trime.core.RimeMessage
1213
import com.osfans.trime.core.RimeProto
1314
import com.osfans.trime.daemon.RimeSession
1415
import com.osfans.trime.daemon.launchOnReady
16+
import com.osfans.trime.data.prefs.AppPrefs
1517
import com.osfans.trime.data.theme.ColorManager
1618
import com.osfans.trime.data.theme.Theme
1719
import com.osfans.trime.ime.broadcast.InputBroadcastReceiver
20+
import com.osfans.trime.ime.candidates.popup.PopupCandidatesMode
1821
import com.osfans.trime.ime.core.TouchEventReceiverWindow
1922
import com.osfans.trime.ime.dependency.InputScope
2023
import me.tatarka.inject.annotations.Inject
@@ -26,7 +29,7 @@ import splitties.views.horizontalPadding
2629
class PreeditModule(
2730
context: Context,
2831
theme: Theme,
29-
rime: RimeSession,
32+
private val rime: RimeSession,
3033
) : InputBroadcastReceiver {
3134

3235
val ui =
@@ -66,4 +69,13 @@ class PreeditModule(
6669
touchEventReceiverWindow.dismiss()
6770
}
6871
}
72+
73+
private val showAsciiIndicator by AppPrefs.defaultInstance().candidates.asciiIndicator
74+
private val candidatesViewMode by AppPrefs.defaultInstance().candidates.mode
75+
76+
override fun onRimeOptionUpdated(value: RimeMessage.OptionMessage.Data) {
77+
if (!showAsciiIndicator || candidatesViewMode == PopupCandidatesMode.ALWAYS_SHOW || value.option != "ascii_mode") return
78+
val text = if (value.value) "En" else rime.run { statusCached }.schemaName.take(2)
79+
ui.root.post { ui.show(text) }
80+
}
6981
}

app/src/main/java/com/osfans/trime/ime/composition/PreeditUi.kt

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,15 @@ import android.view.View
1414
import android.widget.LinearLayout
1515
import android.widget.TextView
1616
import androidx.core.text.buildSpannedString
17+
import androidx.lifecycle.findViewTreeLifecycleOwner
18+
import androidx.lifecycle.lifecycleScope
1719
import com.osfans.trime.core.RimeProto
1820
import com.osfans.trime.data.theme.ColorManager
1921
import com.osfans.trime.data.theme.FontManager
2022
import com.osfans.trime.data.theme.Theme
23+
import com.osfans.trime.util.CancellableDelay
24+
import kotlinx.coroutines.Job
25+
import kotlinx.coroutines.launch
2126
import splitties.views.dsl.core.Ui
2227
import splitties.views.dsl.core.add
2328
import splitties.views.dsl.core.lParams
@@ -71,15 +76,23 @@ open class PreeditUi(
7176
visibility = if (visible) View.VISIBLE else View.GONE
7277
}
7378

79+
private var autoHideJob: Job? = null
80+
private val delayControl = CancellableDelay()
81+
7482
fun update(inputComposition: RimeProto.Context.Composition) {
7583
val string = inputComposition.toSpannedString()
7684
val cursorPos = inputComposition.cursorPos
7785
val hasPreedit = inputComposition.length > 0
78-
visible = hasPreedit
79-
if (!visible) {
86+
87+
if (!hasPreedit) {
88+
if (autoHideJob?.isActive == true) return
89+
visible = false
8090
updateTextView("", false)
8191
return
8292
}
93+
delayControl.skipDelay()
94+
visible = true
95+
8396
val stringWithCursor =
8497
if (cursorPos == 0 || cursorPos == string.length) {
8598
string
@@ -89,6 +102,24 @@ open class PreeditUi(
89102
append(string, cursorPos, string.length)
90103
}
91104
}
92-
updateTextView(stringWithCursor, hasPreedit)
105+
updateTextView(stringWithCursor, true)
106+
}
107+
108+
fun show(
109+
text: String,
110+
onIndicatorHidden: (() -> Unit)? = null,
111+
) {
112+
autoHideJob?.cancel()
113+
updateTextView(text, true)
114+
root.visibility = View.VISIBLE
115+
visible = true
116+
autoHideJob = root.findViewTreeLifecycleOwner()?.lifecycleScope?.launch {
117+
if (!delayControl.delay(1000)) {
118+
updateTextView("", false)
119+
root.visibility = View.INVISIBLE
120+
visible = false
121+
onIndicatorHidden?.invoke()
122+
}
123+
}
93124
}
94125
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2015 - 2025 Rime community
3+
* SPDX-License-Identifier: GPL-3.0-or-later
4+
*/
5+
6+
package com.osfans.trime.util
7+
8+
import kotlinx.coroutines.CancellationException
9+
import kotlinx.coroutines.CompletableDeferred
10+
import kotlinx.coroutines.TimeoutCancellationException
11+
import kotlinx.coroutines.withTimeout
12+
13+
class CancellableDelay {
14+
private var deferred: CompletableDeferred<Unit>? = null
15+
16+
suspend fun delay(timeMillis: Long): Boolean {
17+
deferred = CompletableDeferred()
18+
19+
return try {
20+
withTimeout(timeMillis) {
21+
deferred?.await()
22+
}
23+
false
24+
} catch (e: TimeoutCancellationException) {
25+
false
26+
} catch (e: CancellationException) {
27+
true
28+
} finally {
29+
deferred = null
30+
}
31+
}
32+
33+
fun skipDelay() {
34+
deferred?.complete(Unit)
35+
}
36+
}

app/src/main/res/values-zh-rCN/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,5 @@ SPDX-License-Identifier: GPL-3.0-or-later
228228
<string name="automatic">自动</string>
229229
<string name="horizontal">横向</string>
230230
<string name="vertical">纵向</string>
231+
<string name="show_ascii_indicator">ASCII 模式切换提示</string>
231232
</resources>

app/src/main/res/values-zh-rTW/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,5 @@ SPDX-License-Identifier: GPL-3.0-or-later
229229
<string name="automatic">自動</string>
230230
<string name="horizontal">橫向</string>
231231
<string name="vertical">"縱向 "</string>
232+
<string name="show_ascii_indicator">ASCII 模式切換提示</string>
232233
</resources>

app/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,5 @@ SPDX-License-Identifier: GPL-3.0-or-later
229229
<string name="automatic">Automatic</string>
230230
<string name="horizontal">Horizontal</string>
231231
<string name="vertical">Vertical</string>
232+
<string name="show_ascii_indicator">ASCII mode switch indicator</string>
232233
</resources>

0 commit comments

Comments
 (0)