Skip to content

Commit d3e5cfe

Browse files
committed
refactor: improve the implementation of ascii mode switch indicator
- Rename the preference name and put it in `General` section
1 parent f6e391f commit d3e5cfe

File tree

10 files changed

+70
-115
lines changed

10 files changed

+70
-115
lines changed

app/src/main/java/com/osfans/trime/core/Rime.kt

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
1-
// SPDX-FileCopyrightText: 2015 - 2024 Rime community
2-
//
3-
// SPDX-License-Identifier: GPL-3.0-or-later
1+
/*
2+
* SPDX-FileCopyrightText: 2015 - 2025 Rime community
3+
* SPDX-License-Identifier: GPL-3.0-or-later
4+
*/
45

56
package com.osfans.trime.core
67

78
import com.osfans.trime.BuildConfig
89
import com.osfans.trime.data.base.DataManager
910
import com.osfans.trime.data.opencc.OpenCCDictManager
11+
import com.osfans.trime.data.prefs.AppPrefs
1012
import com.osfans.trime.util.appContext
1113
import com.osfans.trime.util.isStorageAvailable
14+
import kotlinx.coroutines.Job
1215
import kotlinx.coroutines.channels.BufferOverflow
16+
import kotlinx.coroutines.delay
1317
import kotlinx.coroutines.flow.MutableSharedFlow
1418
import kotlinx.coroutines.flow.asSharedFlow
19+
import kotlinx.coroutines.launch
1520
import kotlinx.coroutines.withContext
1621
import timber.log.Timber
1722

@@ -62,6 +67,10 @@ class Rime :
6267
},
6368
)
6469

70+
private val showAsciiSwitchTips by AppPrefs.defaultInstance().general.asciiSwitchTips
71+
private var lastAsciiTipsText = ""
72+
private var asciiSwitchTipsJob: Job? = null
73+
6574
init {
6675
if (lifecycle.currentStateFlow.value != RimeLifecycle.State.STOPPED) {
6776
throw IllegalStateException("Rime has already been created!")
@@ -200,6 +209,7 @@ class Rime :
200209
}
201210

202211
private fun processKeyInner(value: Int, modifiers: Int, isVirtual: Boolean): Boolean {
212+
lastAsciiTipsText = asciiTipsText
203213
val handled = processRimeKey(value, modifiers)
204214
emitResponse()
205215
if (!handled) {
@@ -211,12 +221,29 @@ class Rime :
211221
return handled
212222
}
213223

224+
private val asciiTipsText: String
225+
get() {
226+
val status = getRimeStatus()
227+
return if (status.isAsciiMode) {
228+
"En"
229+
} else if (status.schemaName.isNotEmpty() &&
230+
!status.schemaName.startsWith('.')
231+
) {
232+
status.schemaName.take(2)
233+
} else {
234+
""
235+
}
236+
}
237+
214238
private fun emitResponse(
215239
commit: (() -> RimeProto.Commit) = { getRimeCommit() },
216240
) {
217241
handleRimeMessage(4, arrayOf(commit.invoke()))
218242
val context = getRimeContext()
219243
handleRimeMessage(5, arrayOf(context.composition))
244+
if (context.composition.length <= 0 && lastAsciiTipsText != asciiTipsText) {
245+
showAsciiSwitchTips()
246+
}
220247
if (getRimeOption("paging_mode")) {
221248
handleRimeMessage(6, arrayOf(context.menu))
222249
} else {
@@ -237,8 +264,12 @@ class Rime :
237264
}
238265
is RimeMessage.OptionMessage -> {
239266
// Option change won't trigger response update
240-
statusCached = getRimeStatus()
241-
updateSchemaCached(statusCached)
267+
val status = getRimeStatus()
268+
statusCached = status
269+
updateSchemaCached(status)
270+
if (it.data.option == "ascii_mode") {
271+
showAsciiSwitchTips()
272+
}
242273
}
243274
is RimeMessage.DeployMessage -> {
244275
if (it.data == RimeMessage.DeployMessage.State.Start) {
@@ -272,6 +303,20 @@ class Rime :
272303
}
273304
}
274305

306+
private fun showAsciiSwitchTips() {
307+
if (!showAsciiSwitchTips) return
308+
val tipsText = asciiTipsText
309+
if (tipsText.isEmpty()) return
310+
val tips = RimeProto.Context.Composition(tipsText)
311+
handleRimeMessage(5, arrayOf(tips))
312+
asciiSwitchTipsJob?.cancel()
313+
asciiSwitchTipsJob = lifecycleScope.launch {
314+
delay(1000L)
315+
val ctx = getRimeContext()
316+
handleRimeMessage(5, arrayOf(ctx.composition))
317+
}
318+
}
319+
275320
fun startup() {
276321
if (lifecycle.currentStateFlow.value != RimeLifecycle.State.STOPPED) {
277322
Timber.w("Skip starting rime: not at stopped state!")

app/src/main/java/com/osfans/trime/core/RimeProto.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,15 @@ class RimeProto {
3232
val selEnd: Int = 0,
3333
val preedit: String? = null,
3434
val commitTextPreview: String? = null,
35-
)
35+
) {
36+
constructor(text: String) : this(
37+
text.length,
38+
text.length,
39+
text.length,
40+
text.length,
41+
text,
42+
)
43+
}
3644

3745
data class Menu(
3846
val pageSize: Int = 0,

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,11 @@ class AppPrefs(
107107
) : PreferenceDelegateOwner(shared, R.string.general) {
108108
companion object {
109109
const val COMPOSING_TEXT_MODE = "composing_text_mode"
110+
const val ASCII_SWITCH_TIPS = "ascii_switch_tips"
110111
}
111112

112113
val composingTextMode = enum(R.string.composing_text_mode, COMPOSING_TEXT_MODE, ComposingTextMode.DISABLE)
114+
val asciiSwitchTips = switch(R.string.ascii_switch_tips, ASCII_SWITCH_TIPS, true)
113115
}
114116

115117
/**
@@ -199,13 +201,11 @@ class AppPrefs(
199201
const val MODE = "show_candidates_window"
200202
const val LAYOUT = "candidates_layout"
201203
const val POSITION = "candidates_window_position"
202-
const val ASCII_INDICATOR = "show_ascii_indicator"
203204
}
204205

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

211211
/**

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

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015 - 2024 Rime community
2+
* SPDX-FileCopyrightText: 2015 - 2025 Rime community
33
* SPDX-License-Identifier: GPL-3.0-or-later
44
*/
55

@@ -56,7 +56,6 @@ 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
6059

6160
private val composingTextMode by AppPrefs.defaultInstance().general.composingTextMode
6261

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

112111
private var bottomInsets = 0
113112

114-
private var shouldShowAsciiIndicator = false
115-
116113
override fun handleRimeMessage(it: RimeMessage<*>) {
117114
when (it) {
118115
is RimeMessage.CompositionMessage -> {
@@ -127,28 +124,12 @@ class CandidatesView(
127124
menu = it.data
128125
updateUi()
129126
}
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-
145127
else -> {}
146128
}
147129
}
148130

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

153134
private fun updateUi() {
154135
preeditUi.update(composition)

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

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015 - 2024 Rime community
2+
* SPDX-FileCopyrightText: 2015 - 2025 Rime community
33
* SPDX-License-Identifier: GPL-3.0-or-later
44
*/
55

@@ -9,15 +9,12 @@ 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
1312
import com.osfans.trime.core.RimeProto
1413
import com.osfans.trime.daemon.RimeSession
1514
import com.osfans.trime.daemon.launchOnReady
16-
import com.osfans.trime.data.prefs.AppPrefs
1715
import com.osfans.trime.data.theme.ColorManager
1816
import com.osfans.trime.data.theme.Theme
1917
import com.osfans.trime.ime.broadcast.InputBroadcastReceiver
20-
import com.osfans.trime.ime.candidates.popup.PopupCandidatesMode
2118
import com.osfans.trime.ime.core.TouchEventReceiverWindow
2219
import com.osfans.trime.ime.dependency.InputScope
2320
import me.tatarka.inject.annotations.Inject
@@ -69,13 +66,4 @@ class PreeditModule(
6966
touchEventReceiverWindow.dismiss()
7067
}
7168
}
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-
}
8169
}

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

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015 - 2024 Rime community
2+
* SPDX-FileCopyrightText: 2015 - 2025 Rime community
33
* SPDX-License-Identifier: GPL-3.0-or-later
44
*/
55

@@ -14,15 +14,10 @@ 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
1917
import com.osfans.trime.core.RimeProto
2018
import com.osfans.trime.data.theme.ColorManager
2119
import com.osfans.trime.data.theme.FontManager
2220
import com.osfans.trime.data.theme.Theme
23-
import com.osfans.trime.util.CancellableDelay
24-
import kotlinx.coroutines.Job
25-
import kotlinx.coroutines.launch
2621
import splitties.views.dsl.core.Ui
2722
import splitties.views.dsl.core.add
2823
import splitties.views.dsl.core.lParams
@@ -76,23 +71,15 @@ open class PreeditUi(
7671
visibility = if (visible) View.VISIBLE else View.GONE
7772
}
7873

79-
private var autoHideJob: Job? = null
80-
private val delayControl = CancellableDelay()
81-
8274
fun update(inputComposition: RimeProto.Context.Composition) {
8375
val string = inputComposition.toSpannedString()
8476
val cursorPos = inputComposition.cursorPos
8577
val hasPreedit = inputComposition.length > 0
86-
87-
if (!hasPreedit) {
88-
if (autoHideJob?.isActive == true) return
89-
visible = false
78+
visible = hasPreedit
79+
if (!visible) {
9080
updateTextView("", false)
9181
return
9282
}
93-
delayControl.skipDelay()
94-
visible = true
95-
9683
val stringWithCursor =
9784
if (cursorPos == 0 || cursorPos == string.length) {
9885
string
@@ -104,22 +91,4 @@ open class PreeditUi(
10491
}
10592
updateTextView(stringWithCursor, true)
10693
}
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-
}
124-
}
12594
}

app/src/main/java/com/osfans/trime/util/CancellableDelay.kt

Lines changed: 0 additions & 36 deletions
This file was deleted.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,5 +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>
231+
<string name="ascii_switch_tips">切换中英文模式时显示提示</string>
232232
</resources>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,5 +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>
232+
<string name="ascii_switch_tips">切換中英文模式時顯示提示</string>
233233
</resources>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,5 +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>
232+
<string name="ascii_switch_tips">Show tips when switching ASCII mode</string>
233233
</resources>

0 commit comments

Comments
 (0)