Skip to content

Commit

Permalink
feat: allow user to determine the candidates view mode
Browse files Browse the repository at this point in the history
  • Loading branch information
WhiredPlanck committed Nov 19, 2024
1 parent e90d0c5 commit 4e72764
Show file tree
Hide file tree
Showing 20 changed files with 164 additions and 79 deletions.
28 changes: 26 additions & 2 deletions app/src/main/java/com/osfans/trime/data/prefs/AppPrefs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import android.content.SharedPreferences
import androidx.preference.PreferenceManager
import com.osfans.trime.R
import com.osfans.trime.data.base.DataManager
import com.osfans.trime.ime.candidates.popup.PopupCandidatesMode
import com.osfans.trime.ime.enums.FullscreenMode
import com.osfans.trime.ime.enums.InlinePreeditMode
import com.osfans.trime.util.appContext
Expand All @@ -22,13 +23,28 @@ class AppPrefs(
) {
private val applicationContext: WeakReference<Context> = WeakReference(appContext)

private val providers = mutableListOf<PreferenceDelegateProvider>()

fun <T : PreferenceDelegateProvider> registerProvider(providerF: (SharedPreferences) -> T): T {
val provider = providerF(shared)
providers.add(provider)
return provider
}

private fun <T : PreferenceDelegateProvider> T.register() =
this.apply {
registerProvider { this }
}

val internal = Internal(shared)
val keyboard = Keyboard(shared)
val theme = Theme(shared)
val profile = Profile(shared)
val clipboard = Clipboard(shared)
val other = Other(shared)

val candidates = Candidates(shared).register()

companion object {
private var defaultInstance: AppPrefs? = null

Expand Down Expand Up @@ -84,7 +100,6 @@ class AppPrefs(
companion object {
const val INLINE_PREEDIT_MODE = "keyboard__inline_preedit"
const val SOFT_CURSOR_ENABLED = "keyboard__soft_cursor"
const val FLOATING_WINDOW_ENABLED = "keyboard__show_window"
const val POPUP_KEY_PRESS_ENABLED = "keyboard__show_key_popup"
const val SWITCHES_ENABLED = "keyboard__show_switches"
const val LANDSCAPE_MODE = "keyboard__landscape_mode"
Expand Down Expand Up @@ -122,7 +137,6 @@ class AppPrefs(
var inlinePreedit by enum(INLINE_PREEDIT_MODE, InlinePreeditMode.PREVIEW)
var fullscreenMode by enum(FULLSCREEN_MODE, FullscreenMode.AUTO_SHOW)
val softCursorEnabled by bool(SOFT_CURSOR_ENABLED, true)
val popupWindowEnabled by bool(FLOATING_WINDOW_ENABLED, true)
val popupKeyPressEnabled by bool(POPUP_KEY_PRESS_ENABLED, false)
val switchesEnabled by bool(SWITCHES_ENABLED, true)
val switchArrowEnabled by bool(SWITCH_ARROW_ENABLED, true)
Expand Down Expand Up @@ -161,6 +175,16 @@ class AppPrefs(
var isSpeakCommit by bool(SPEAK_COMMIT_ENABLED, false)
}

class Candidates(
shared: SharedPreferences,
) : PreferenceDelegateOwner(shared, R.string.candidates_window) {
companion object {
const val MODE = "candidates__mode"
}

val mode = enum(R.string.candidates_mode, MODE, PopupCandidatesMode.PREEDIT_ONLY)
}

/**
* Wrapper class of theme and color settings.
*/
Expand Down
5 changes: 4 additions & 1 deletion app/src/main/java/com/osfans/trime/ime/bar/QuickBar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import com.osfans.trime.ime.bar.ui.CandidateUi
import com.osfans.trime.ime.bar.ui.TabUi
import com.osfans.trime.ime.broadcast.InputBroadcastReceiver
import com.osfans.trime.ime.candidates.CompactCandidateModule
import com.osfans.trime.ime.candidates.popup.PopupCandidatesMode
import com.osfans.trime.ime.candidates.unrolled.window.FlexboxUnrolledCandidateWindow
import com.osfans.trime.ime.core.TrimeInputMethodService
import com.osfans.trime.ime.dependency.InputScope
Expand Down Expand Up @@ -51,6 +52,7 @@ class QuickBar(
private val prefs = AppPrefs.defaultInstance()

private val showSwitchers get() = prefs.keyboard.switchesEnabled
private val candidatesMode by prefs.candidates.mode

val themedHeight =
theme.generalStyle.candidateViewHeight + theme.generalStyle.commentHeight
Expand Down Expand Up @@ -145,7 +147,8 @@ class QuickBar(
override fun onInputContextUpdate(ctx: RimeProto.Context) {
barStateMachine.push(
QuickBarStateMachine.TransitionEvent.CandidatesUpdated,
QuickBarStateMachine.BooleanKey.CandidateEmpty to ctx.menu.candidates.isEmpty(),
QuickBarStateMachine.BooleanKey.CandidateEmpty to
(ctx.menu.candidates.isEmpty() || candidatesMode == PopupCandidatesMode.CURRENT_PAGE),
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,18 @@ import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import com.google.android.flexbox.FlexboxLayoutManager
import com.osfans.trime.R
import com.osfans.trime.core.CandidateItem
import com.osfans.trime.core.RimeProto
import com.osfans.trime.daemon.RimeSession
import com.osfans.trime.daemon.launchOnReady
import com.osfans.trime.data.prefs.AppPrefs
import com.osfans.trime.data.theme.ColorManager
import com.osfans.trime.data.theme.Theme
import com.osfans.trime.ime.bar.QuickBar
import com.osfans.trime.ime.bar.UnrollButtonStateMachine
import com.osfans.trime.ime.broadcast.InputBroadcastReceiver
import com.osfans.trime.ime.candidates.adapter.CompactCandidateViewAdapter
import com.osfans.trime.ime.candidates.popup.PopupCandidatesMode
import com.osfans.trime.ime.candidates.unrolled.decoration.FlexboxVerticalDecoration
import com.osfans.trime.ime.core.TrimeInputMethodService
import com.osfans.trime.ime.dependency.InputScope
Expand All @@ -48,6 +52,8 @@ class CompactCandidateModule(
val theme: Theme,
val bar: QuickBar,
) : InputBroadcastReceiver {
private val candidatesMode by AppPrefs.defaultInstance().candidates.mode

private val _unrolledCandidateOffset =
MutableSharedFlow<Int>(
replay = 1,
Expand All @@ -58,7 +64,7 @@ class CompactCandidateModule(

fun refreshUnrolled() {
runBlocking {
_unrolledCandidateOffset.emit(adapter.before + view.childCount)
_unrolledCandidateOffset.emit(adapter.previous + view.childCount)
}
bar.unrollButtonStateMachine.push(
UnrollButtonStateMachine.TransitionEvent.UnrolledCandidatesUpdated,
Expand All @@ -70,10 +76,10 @@ class CompactCandidateModule(
val adapter by lazy {
CompactCandidateViewAdapter(theme).apply {
setOnItemClickListener { _, _, position ->
rime.launchOnReady { it.selectCandidate(before + position) }
rime.launchOnReady { it.selectCandidate(previous + position) }
}
setOnItemLongClickListener { _, view, position ->
showCandidateAction(before + position, items[position].text, view)
showCandidateAction(previous + position, items[position].text, view)
true
}
}
Expand Down Expand Up @@ -110,6 +116,18 @@ class CompactCandidateModule(
}
}

override fun onInputContextUpdate(ctx: RimeProto.Context) {
if (candidatesMode != PopupCandidatesMode.PREEDIT_ONLY) return
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
adapter.updateCandidates(candidates, isLastPage, previous, highlightedIdx)
if (candidates.isEmpty()) {
refreshUnrolled()
}
}

private var candidateActionMenu: PopupMenu? = null

fun showCandidateAction(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ import splitties.views.setPaddingDp
open class CompactCandidateViewAdapter(
val theme: Theme,
) : BaseQuickAdapter<CandidateItem, CandidateViewHolder>() {
var sticky: Int = 0
private set

var isLastPage: Boolean = false
private set

Expand All @@ -33,21 +30,16 @@ open class CompactCandidateViewAdapter(
var highlightedIdx: Int = -1
private set

val before: Int
get() = sticky + previous

fun updateCandidates(
list: List<CandidateItem>,
isLastPage: Boolean,
previous: Int,
highlightedIdx: Int,
sticky: Int = 0,
) {
this.isLastPage = isLastPage
this.previous = previous
this.sticky = sticky
this.highlightedIdx = highlightedIdx
super.submitList(list.drop(sticky))
super.submitList(list)
}

override fun onCreateViewHolder(
Expand All @@ -71,15 +63,14 @@ open class CompactCandidateViewAdapter(
item: CandidateItem?,
) {
val (comment, text) = item!!
val idx = sticky + position
holder.ui.run {
label.text = text
altLabel.text = comment
highlight(theme.generalStyle.candidateUseCursor && idx == highlightedIdx)
highlight(theme.generalStyle.candidateUseCursor && position == highlightedIdx)
}
holder.text = text
holder.comment = comment
holder.idx = before + position // unused
holder.idx = previous + position // unused
holder.ui.root.updateLayoutParams<FlexboxLayoutManager.LayoutParams> {
minWidth = 0
flexGrow = 0f
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package com.osfans.trime.ime.candidates.popup

import android.content.Context
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter4.BaseQuickAdapter
Expand Down Expand Up @@ -72,6 +73,8 @@ class PagedCandidatesUi(

override val root =
recyclerView {
visibility = View.GONE

isFocusable = false
adapter = candidatesAdapter
layoutManager = candidatesLayoutManager
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: 2015 - 2024 Rime community
* SPDX-License-Identifier: GPL-3.0-or-later
*/

package com.osfans.trime.ime.candidates.popup

import com.osfans.trime.R
import com.osfans.trime.data.prefs.PreferenceDelegateEnum

enum class PopupCandidatesMode(
override val stringRes: Int,
) : PreferenceDelegateEnum {
CURRENT_PAGE(R.string.current_page_of_candidates),
PREEDIT_ONLY(R.string.preedit_only),
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,7 @@ abstract class BaseUnrolledCandidateWindow(

private fun updateCandidatesWithOffset(offset: Int) {
val candidates = compactCandidate.adapter.items
val sticky = compactCandidate.adapter.sticky
if (candidates.isEmpty() && sticky == 0) {
if (candidates.isEmpty()) {
windowManager.attachWindow(KeyboardWindow)
} else {
adapter.refreshWithOffset(offset)
Expand All @@ -139,7 +138,7 @@ abstract class BaseUnrolledCandidateWindow(
bar.unrollButtonStateMachine.push(
UnrollButtonStateMachine.TransitionEvent.UnrolledCandidatesDetached,
UnrollButtonStateMachine.BooleanKey.UnrolledCandidatesEmpty to
(compactCandidate.adapter.run { isLastPage && (before + itemCount) == adapter.offset }),
(compactCandidate.adapter.run { isLastPage && (previous + itemCount) == adapter.offset }),
)
offsetJob?.cancel()
candidatesSubmitJob?.cancel()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@ import android.content.Context
import android.view.View
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.postDelayed
import com.osfans.trime.core.RimeProto
import com.osfans.trime.daemon.RimeSession
import com.osfans.trime.daemon.launchOnReady
import com.osfans.trime.data.prefs.AppPrefs
import com.osfans.trime.data.theme.Theme
import com.osfans.trime.ime.candidates.popup.PagedCandidatesUi
import com.osfans.trime.ime.candidates.popup.PopupCandidatesMode
import splitties.dimensions.dp
import splitties.views.dsl.constraintlayout.below
import splitties.views.dsl.constraintlayout.bottomOfParent
Expand All @@ -32,6 +35,8 @@ class CandidatesView(
val rime: RimeSession,
val theme: Theme,
) : ConstraintLayout(ctx) {
private val candidatesMode by AppPrefs.defaultInstance().candidates.mode

private var menu = RimeProto.Context.Menu()
private var inputComposition = RimeProto.Context.Composition()

Expand Down Expand Up @@ -62,18 +67,34 @@ class CandidatesView(
private fun updateUi() {
if (evaluateVisibility()) {
preeditUi.update(inputComposition)
preeditUi.root.visibility = if (preeditUi.visible) View.VISIBLE else View.GONE
candidatesUi.update(menu)
// visibility = View.VISIBLE
} else {
// visibility = View.GONE
when (candidatesMode) {
PopupCandidatesMode.CURRENT_PAGE -> {
candidatesUi.root.let {
postDelayed(200) {
if (it.visibility == View.GONE) {
it.visibility = View.VISIBLE
return@postDelayed
}
}
}
candidatesUi.update(menu)
}

PopupCandidatesMode.PREEDIT_ONLY -> {
candidatesUi.root.let {
postDelayed(200) {
if (it.visibility != View.GONE) {
it.visibility = View.GONE
candidatesUi.update(RimeProto.Context.Menu())
}
}
}
}
}
}
}

init {
// invisible by default
// visibility = GONE

verticalPadding = dp(theme.generalStyle.layout.marginX)
horizontalPadding = dp(theme.generalStyle.layout.marginY)
add(
Expand Down
Loading

0 comments on commit 4e72764

Please sign in to comment.