From bde2c472d74c54a938bbfe1f156169a231cd33bb Mon Sep 17 00:00:00 2001 From: WhiredPlanck Date: Mon, 14 Oct 2024 23:57:13 +0800 Subject: [PATCH] refactor: merge notification flow and response flow as callback flow --- .../main/java/com/osfans/trime/core/Rime.kt | 77 +++++++---------- .../java/com/osfans/trime/core/RimeApi.kt | 4 +- .../com/osfans/trime/core/RimeCallback.kt | 8 ++ .../com/osfans/trime/core/RimeNotification.kt | 2 +- .../com/osfans/trime/core/RimeResponse.kt | 2 +- .../com/osfans/trime/daemon/RimeSession.kt | 2 +- .../com/osfans/trime/ime/core/InputView.kt | 60 ++++++-------- .../trime/ime/core/TrimeInputMethodService.kt | 82 +++++++++---------- 8 files changed, 107 insertions(+), 130 deletions(-) create mode 100644 app/src/main/java/com/osfans/trime/core/RimeCallback.kt diff --git a/app/src/main/java/com/osfans/trime/core/Rime.kt b/app/src/main/java/com/osfans/trime/core/Rime.kt index ed9ec8f4ba..af316c5565 100644 --- a/app/src/main/java/com/osfans/trime/core/Rime.kt +++ b/app/src/main/java/com/osfans/trime/core/Rime.kt @@ -28,8 +28,8 @@ class Rime : private val lifecycleImpl = RimeLifecycleImpl() override val lifecycle get() = lifecycleImpl - override val notificationFlow = notificationFlow_.asSharedFlow() - override val responseFlow = responseFlow_.asSharedFlow() + override val callbackFlow = callbackFlow_.asSharedFlow() + override val stateFlow get() = lifecycle.currentStateFlow override val isReady: Boolean @@ -147,7 +147,7 @@ class Rime : getRimeCandidates(startIndex, limit) ?: emptyArray() } - private fun handleRimeNotification(it: RimeNotification<*>) { + private fun handleRimeCallback(it: RimeCallback) { when (it) { is RimeNotification.SchemaNotification -> { schemaItemCached = it.value @@ -165,22 +165,21 @@ class Rime : "start" -> OpenCCDictManager.buildOpenCCDict() } } - else -> {} - } - } - - private fun handleRimeResponse(response: RimeResponse) { - response.status?.let { - val status = InputStatus.fromStatus(it) - inputStatusCached = status - inputStatus = it // for compatibility + is RimeResponse -> { + it.status?.let { + val status = InputStatus.fromStatus(it) + inputStatusCached = status + inputStatus = it // for compatibility - val item = SchemaItem.fromStatus(it) - if (item != schemaItemCached) { - schemaItemCached = item + val item = SchemaItem.fromStatus(it) + if (item != schemaItemCached) { + schemaItemCached = item + } + } + it.context?.let { inputContext = it } // for compatibility } + else -> {} } - response.context?.let { inputContext = it } // for compatibility } fun startup(fullCheck: Boolean) { @@ -189,8 +188,7 @@ class Rime : return } if (appContext.isStorageAvailable()) { - registerRimeNotificationHandler(::handleRimeNotification) - registerRimeResponseHandler(::handleRimeResponse) + registerRimeCallbackHandler(::handleRimeCallback) lifecycleImpl.emitState(RimeLifecycle.State.STARTING) dispatcher.start(fullCheck) } @@ -209,28 +207,19 @@ class Rime : } } lifecycleImpl.emitState(RimeLifecycle.State.STOPPED) - unregisterRimeNotificationHandler(::handleRimeNotification) - unregisterRimeResponseHandler(::handleRimeResponse) + unregisterRimeCallbackHandler(::handleRimeCallback) } companion object { private var inputContext: RimeProto.Context? = null private var inputStatus: RimeProto.Status? = null - private val notificationFlow_ = - MutableSharedFlow>( + private val callbackFlow_ = + MutableSharedFlow( extraBufferCapacity = 15, onBufferOverflow = BufferOverflow.DROP_OLDEST, ) - private val responseFlow_ = - MutableSharedFlow( - extraBufferCapacity = 15, - onBufferOverflow = BufferOverflow.DROP_LATEST, - ) - - private val notificationHandlers = ArrayList<(RimeNotification<*>) -> Unit>() - - private val responseHandlers = ArrayList<(RimeResponse) -> Unit>() + private val callbackHandlers = ArrayList<(RimeCallback) -> Unit>() init { System.loadLibrary("rime_jni") @@ -489,33 +478,23 @@ class Rime : ) { val notification = RimeNotification.create(messageType, messageValue) Timber.d("Handling Rime notification: $notification") - notificationHandlers.forEach { it.invoke(notification) } - notificationFlow_.tryEmit(notification) + callbackHandlers.forEach { it.invoke(notification) } + callbackFlow_.tryEmit(notification) } - private fun registerRimeNotificationHandler(handler: (RimeNotification<*>) -> Unit) { - if (notificationHandlers.contains(handler)) return - notificationHandlers.add(handler) + private fun registerRimeCallbackHandler(handler: (RimeCallback) -> Unit) { + if (callbackHandlers.contains(handler)) return + callbackHandlers.add(handler) } - private fun unregisterRimeNotificationHandler(handler: (RimeNotification<*>) -> Unit) { - notificationHandlers.remove(handler) + private fun unregisterRimeCallbackHandler(handler: (RimeCallback) -> Unit) { + callbackHandlers.remove(handler) } fun requestRimeResponse() { val response = RimeResponse(getRimeCommit(), getRimeContext(), getRimeStatus()) Timber.d("Got Rime response: $response") - responseHandlers.forEach { it.invoke(response) } - responseFlow_.tryEmit(response) - } - - private fun registerRimeResponseHandler(handler: (RimeResponse) -> Unit) { - if (responseHandlers.contains(handler)) return - responseHandlers.add(handler) - } - - private fun unregisterRimeResponseHandler(handler: (RimeResponse) -> Unit) { - responseHandlers.remove(handler) + callbackFlow_.tryEmit(response) } } } diff --git a/app/src/main/java/com/osfans/trime/core/RimeApi.kt b/app/src/main/java/com/osfans/trime/core/RimeApi.kt index dbb493ea96..3383550f7c 100644 --- a/app/src/main/java/com/osfans/trime/core/RimeApi.kt +++ b/app/src/main/java/com/osfans/trime/core/RimeApi.kt @@ -7,9 +7,7 @@ package com.osfans.trime.core import kotlinx.coroutines.flow.SharedFlow interface RimeApi { - val notificationFlow: SharedFlow> - - val responseFlow: SharedFlow + val callbackFlow: SharedFlow val stateFlow: SharedFlow diff --git a/app/src/main/java/com/osfans/trime/core/RimeCallback.kt b/app/src/main/java/com/osfans/trime/core/RimeCallback.kt new file mode 100644 index 0000000000..11be1d0657 --- /dev/null +++ b/app/src/main/java/com/osfans/trime/core/RimeCallback.kt @@ -0,0 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2015 - 2024 Rime community + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package com.osfans.trime.core + +sealed interface RimeCallback diff --git a/app/src/main/java/com/osfans/trime/core/RimeNotification.kt b/app/src/main/java/com/osfans/trime/core/RimeNotification.kt index ece47116ce..4fd8fae91d 100644 --- a/app/src/main/java/com/osfans/trime/core/RimeNotification.kt +++ b/app/src/main/java/com/osfans/trime/core/RimeNotification.kt @@ -6,7 +6,7 @@ package com.osfans.trime.core sealed class RimeNotification( open val value: T, -) { +) : RimeCallback { abstract val messageType: MessageType data class SchemaNotification( diff --git a/app/src/main/java/com/osfans/trime/core/RimeResponse.kt b/app/src/main/java/com/osfans/trime/core/RimeResponse.kt index ceba1d2185..18a145645b 100644 --- a/app/src/main/java/com/osfans/trime/core/RimeResponse.kt +++ b/app/src/main/java/com/osfans/trime/core/RimeResponse.kt @@ -8,4 +8,4 @@ data class RimeResponse( val commit: RimeProto.Commit?, val context: RimeProto.Context?, val status: RimeProto.Status?, -) +) : RimeCallback diff --git a/app/src/main/java/com/osfans/trime/daemon/RimeSession.kt b/app/src/main/java/com/osfans/trime/daemon/RimeSession.kt index d46530fd71..0d29e865c8 100644 --- a/app/src/main/java/com/osfans/trime/daemon/RimeSession.kt +++ b/app/src/main/java/com/osfans/trime/daemon/RimeSession.kt @@ -15,7 +15,7 @@ interface RimeSession { * Run an operation immediately * The suspended [block] will be executed in caller's thread. * Use this function only for non-blocking operations like - * accessing [RimeApi.notificationFlow]. + * accessing [RimeApi.callbackFlow]. */ fun run(block: suspend RimeApi.() -> T): T diff --git a/app/src/main/java/com/osfans/trime/ime/core/InputView.kt b/app/src/main/java/com/osfans/trime/ime/core/InputView.kt index 60d729a25f..b1fa39e9fd 100644 --- a/app/src/main/java/com/osfans/trime/ime/core/InputView.kt +++ b/app/src/main/java/com/osfans/trime/ime/core/InputView.kt @@ -23,6 +23,7 @@ import androidx.core.view.WindowInsetsCompat import androidx.core.view.updateLayoutParams import androidx.lifecycle.lifecycleScope import com.osfans.trime.core.CandidateItem +import com.osfans.trime.core.RimeCallback import com.osfans.trime.core.RimeNotification import com.osfans.trime.core.RimeResponse import com.osfans.trime.daemon.RimeSession @@ -97,8 +98,7 @@ class InputView( setOnClickListener(placeholderListener) } - private val notificationHandlerJob: Job - private val responseHandlerJob: Job + private val callbackHandlerJob: Job private val themedContext = context.withTheme(android.R.style.Theme_DeviceDefault_Settings) private val inputComponent = InputComponent::class.create(this, themedContext, theme, service, rime) @@ -144,17 +144,10 @@ class InputView( init { addBroadcastReceivers() - notificationHandlerJob = + callbackHandlerJob = service.lifecycleScope.launch { - rime.run { notificationFlow }.collect { - handleRimeNotification(it) - } - } - - responseHandlerJob = - service.lifecycleScope.launch { - rime.run { responseFlow }.collect { - handleRimeResponse(it) + rime.run { callbackFlow }.collect { + handleRimeCallback(it) } } @@ -324,7 +317,7 @@ class InputView( } } - private fun handleRimeNotification(it: RimeNotification<*>) { + private fun handleRimeCallback(it: RimeCallback) { when (it) { is RimeNotification.SchemaNotification -> { broadcaster.onRimeSchemaUpdated(it.value) @@ -341,27 +334,26 @@ class InputView( } } } - else -> {} - } - } - - private fun handleRimeResponse(response: RimeResponse) { - val ctx = response.context - if (ctx != null) { - broadcaster.onInputContextUpdate(ctx) - val candidates = ctx.menu.candidates.map { CandidateItem(it.comment ?: "", it.text) } - val isLastPage = ctx.menu.isLastPage - val previous = ctx.menu.run { pageSize * pageNumber } - val highlightedIdx = ctx.menu.highlightedCandidateIndex - if (composition.isPopupWindowEnabled) { - val sticky = composition.composition.update(ctx) - compactCandidate.adapter.updateCandidates(candidates, isLastPage, previous, highlightedIdx, sticky) - } else { - compactCandidate.adapter.updateCandidates(candidates, isLastPage, previous, highlightedIdx) - } - if (candidates.isEmpty()) { - compactCandidate.refreshUnrolled() + is RimeResponse -> { + val ctx = it.context + if (ctx != null) { + broadcaster.onInputContextUpdate(ctx) + val candidates = ctx.menu.candidates.map { CandidateItem(it.comment ?: "", it.text) } + val isLastPage = ctx.menu.isLastPage + val previous = ctx.menu.run { pageSize * pageNumber } + val highlightedIdx = ctx.menu.highlightedCandidateIndex + if (composition.isPopupWindowEnabled) { + val sticky = composition.composition.update(ctx) + compactCandidate.adapter.updateCandidates(candidates, isLastPage, previous, highlightedIdx, sticky) + } else { + compactCandidate.adapter.updateCandidates(candidates, isLastPage, previous, highlightedIdx) + } + if (candidates.isEmpty()) { + compactCandidate.refreshUnrolled() + } + } } + else -> {} } } @@ -420,7 +412,7 @@ class InputView( composition.hideCompositionView() // cancel the notification job and clear all broadcast receivers, // implies that InputView should not be attached again after detached. - notificationHandlerJob.cancel() + callbackHandlerJob.cancel() broadcaster.clear() super.onDetachedFromWindow() } diff --git a/app/src/main/java/com/osfans/trime/ime/core/TrimeInputMethodService.kt b/app/src/main/java/com/osfans/trime/ime/core/TrimeInputMethodService.kt index cfdcd5ca25..b4c7b232fe 100644 --- a/app/src/main/java/com/osfans/trime/ime/core/TrimeInputMethodService.kt +++ b/app/src/main/java/com/osfans/trime/ime/core/TrimeInputMethodService.kt @@ -37,6 +37,7 @@ import com.osfans.trime.core.KeyModifiers import com.osfans.trime.core.KeyValue import com.osfans.trime.core.Rime import com.osfans.trime.core.RimeApi +import com.osfans.trime.core.RimeCallback import com.osfans.trime.core.RimeKeyMapping import com.osfans.trime.core.RimeNotification import com.osfans.trime.core.RimeProto @@ -206,13 +207,8 @@ open class TrimeInputMethodService : LifecycleInputMethodService() { jobs.consumeEach { it.join() } } lifecycleScope.launch { - rime.run { notificationFlow }.collect { - handleRimeNotification(it) - } - } - lifecycleScope.launch { - rime.run { responseFlow }.collect { - handleRimeResponse(it) + rime.run { callbackFlow }.collect { + handleRimeCallback(it) } } ThemeManager.addOnChangedListener(onThemeChangeListener) @@ -258,46 +254,50 @@ open class TrimeInputMethodService : LifecycleInputMethodService() { } } - private fun handleRimeNotification(notification: RimeNotification<*>) { - if (notification is RimeNotification.SchemaNotification) { - recreateInputView(ThemeManager.activeTheme) - } else if (notification is RimeNotification.OptionNotification) { - val value = notification.value.value - when (val option = notification.value.option) { - "ascii_mode" -> { - InputFeedbackManager.ttsLanguage = - locales[if (value) 1 else 0] + private fun handleRimeCallback(it: RimeCallback) { + when (it) { + is RimeNotification.SchemaNotification -> { + recreateInputView(ThemeManager.activeTheme) + } + + is RimeNotification.OptionNotification -> { + val value = it.value.value + when (val option = it.value.option) { + "ascii_mode" -> { + InputFeedbackManager.ttsLanguage = + locales[if (value) 1 else 0] + } + "_hide_bar", + "_hide_candidate", + -> { + setCandidatesViewShown(isComposable && !value) + } + else -> + if (option.startsWith("_key_") && option.length > 5 && value) { + shouldUpdateRimeOption = false // 防止在 handleRimeNotification 中 setOption + val key = option.substring(5) + inputView + ?.commonKeyboardActionListener + ?.listener + ?.onEvent(EventManager.getEvent(key)) + shouldUpdateRimeOption = true + } } - "_hide_bar", - "_hide_candidate", - -> { - setCandidatesViewShown(isComposable && !value) + } + is RimeResponse -> { + val (commit, ctx) = it + if (commit?.text?.isNotEmpty() == true) { + commitText(commit.text) } - else -> - if (option.startsWith("_key_") && option.length > 5 && value) { - shouldUpdateRimeOption = false // 防止在 handleRimeNotification 中 setOption - val key = option.substring(5) - inputView - ?.commonKeyboardActionListener - ?.listener - ?.onEvent(EventManager.getEvent(key)) - shouldUpdateRimeOption = true - } + if (ctx != null) { + updateComposingText(ctx) + } + updateComposing() } + else -> {} } } - private fun handleRimeResponse(response: RimeResponse) { - val (commit, ctx, _) = response - if (commit != null && !commit.text.isNullOrEmpty()) { - commitText(commit.text) - } - if (ctx != null) { - updateComposingText(ctx) - } - updateComposing() - } - fun pasteByChar() { commitTextByChar(checkNotNull(ShortcutUtils.pasteFromClipboard(this)).toString()) }