mirror of
https://github.com/fcitx5-android/fcitx5-android.git
synced 2026-08-02 04:44:35 +08:00
Make CandidatesView support candidate action menu
This commit is contained in:
parent
630f9258dc
commit
3f312292de
@ -5,19 +5,27 @@
|
||||
|
||||
package org.fcitx.fcitx5.android.input
|
||||
|
||||
import android.view.View
|
||||
import android.view.WindowInsets
|
||||
import android.widget.PopupMenu
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.text.bold
|
||||
import androidx.core.text.buildSpannedString
|
||||
import androidx.core.text.color
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import org.fcitx.fcitx5.android.core.FcitxEvent
|
||||
import org.fcitx.fcitx5.android.daemon.FcitxConnection
|
||||
import org.fcitx.fcitx5.android.data.InputFeedbacks
|
||||
import org.fcitx.fcitx5.android.data.prefs.AppPrefs
|
||||
import org.fcitx.fcitx5.android.data.theme.Theme
|
||||
import org.fcitx.fcitx5.android.data.theme.ThemeManager
|
||||
import org.fcitx.fcitx5.android.data.theme.ThemePrefs
|
||||
import org.fcitx.fcitx5.android.utils.item
|
||||
import org.fcitx.fcitx5.android.utils.navbarFrameHeight
|
||||
import splitties.resources.styledColor
|
||||
import kotlin.math.max
|
||||
|
||||
abstract class BaseInputView(
|
||||
@ -57,6 +65,42 @@ abstract class BaseInputView(
|
||||
}
|
||||
}
|
||||
|
||||
private fun triggerCandidateAction(idx: Int, actionIdx: Int) {
|
||||
fcitx.runIfReady { triggerCandidateAction(idx, actionIdx) }
|
||||
}
|
||||
|
||||
private var candidateActionMenu: PopupMenu? = null
|
||||
|
||||
fun showCandidateActionMenu(idx: Int, text: String, view: View) {
|
||||
candidateActionMenu?.dismiss()
|
||||
candidateActionMenu = null
|
||||
service.lifecycleScope.launch {
|
||||
val actions = fcitx.runOnReady { getCandidateActions(idx) }
|
||||
if (actions.isEmpty()) return@launch
|
||||
InputFeedbacks.hapticFeedback(view, longPress = true)
|
||||
candidateActionMenu = PopupMenu(context, view).apply {
|
||||
menu.add(buildSpannedString {
|
||||
bold {
|
||||
color(context.styledColor(android.R.attr.colorAccent)) {
|
||||
append(text)
|
||||
}
|
||||
}
|
||||
}).apply {
|
||||
isEnabled = false
|
||||
}
|
||||
actions.forEach { action ->
|
||||
menu.item(action.text) {
|
||||
triggerCandidateAction(idx, action.id)
|
||||
}
|
||||
}
|
||||
setOnDismissListener {
|
||||
candidateActionMenu = null
|
||||
}
|
||||
show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val navbarBackground by ThemeManager.prefs.navbarBackground
|
||||
|
||||
protected fun getNavBarBottomInset(windowInsets: WindowInsets): Int {
|
||||
|
||||
@ -100,6 +100,7 @@ class CandidatesView(
|
||||
private val candidatesUi = PagedCandidatesUi(
|
||||
ctx, theme, setupTextView,
|
||||
onCandidateClick = { index -> fcitx.launchOnReady { it.select(index) } },
|
||||
onCandidateAction = { index, text, view -> showCandidateActionMenu(index, text, view) },
|
||||
onPrevPage = { fcitx.launchOnReady { it.offsetCandidatePage(-1) } },
|
||||
onNextPage = { fcitx.launchOnReady { it.offsetCandidatePage(1) } }
|
||||
)
|
||||
|
||||
@ -32,7 +32,7 @@ class CandidateItemUi(override val ctx: Context, theme: Theme) : Ui {
|
||||
background = pressHighlightDrawable(theme.keyPressHighlightColor)
|
||||
|
||||
/**
|
||||
* candidate long press feedback is handled by [org.fcitx.fcitx5.android.input.candidates.horizontal.HorizontalCandidateComponent.showCandidateActionMenu]
|
||||
* candidate long press feedback is handled by [org.fcitx.fcitx5.android.input.BaseInputView.showCandidateActionMenu]
|
||||
*/
|
||||
longPressFeedbackEnabled = false
|
||||
|
||||
|
||||
@ -30,6 +30,7 @@ import org.fcitx.fcitx5.android.input.candidates.expanded.PagingCandidateViewAda
|
||||
import org.fcitx.fcitx5.android.input.candidates.horizontal.HorizontalCandidateComponent
|
||||
import org.fcitx.fcitx5.android.input.dependency.fcitx
|
||||
import org.fcitx.fcitx5.android.input.dependency.inputMethodService
|
||||
import org.fcitx.fcitx5.android.input.dependency.inputView
|
||||
import org.fcitx.fcitx5.android.input.dependency.theme
|
||||
import org.fcitx.fcitx5.android.input.keyboard.CommonKeyActionListener
|
||||
import org.fcitx.fcitx5.android.input.keyboard.KeyAction
|
||||
@ -47,6 +48,7 @@ abstract class BaseExpandedCandidateWindow<T : BaseExpandedCandidateWindow<T>> :
|
||||
protected val service by manager.inputMethodService()
|
||||
protected val theme by manager.theme()
|
||||
protected val fcitx by manager.fcitx()
|
||||
protected val inputView by manager.inputView()
|
||||
private val commonKeyActionListener: CommonKeyActionListener by manager.must()
|
||||
private val bar: KawaiiBarComponent by manager.must()
|
||||
private val horizontalCandidate: HorizontalCandidateComponent by manager.must()
|
||||
@ -143,7 +145,7 @@ abstract class BaseExpandedCandidateWindow<T : BaseExpandedCandidateWindow<T>> :
|
||||
fcitx.launchOnReady { it.select(holder.idx) }
|
||||
}
|
||||
holder.itemView.setOnLongClickListener {
|
||||
horizontalCandidate.showCandidateActionMenu(holder)
|
||||
inputView.showCandidateActionMenu(holder.idx, holder.text, holder.ui.root)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ class PagedCandidatesUi(
|
||||
val theme: Theme,
|
||||
private val setupTextView: TextView.() -> Unit,
|
||||
private val onCandidateClick: (Int) -> Unit,
|
||||
private val onCandidateAction: (Int, String, View) -> Unit,
|
||||
private val onPrevPage: () -> Unit,
|
||||
private val onNextPage: () -> Unit
|
||||
) : Ui {
|
||||
@ -80,6 +81,10 @@ class PagedCandidatesUi(
|
||||
holder.ui.root.setOnClickListener {
|
||||
onCandidateClick.invoke(position)
|
||||
}
|
||||
holder.ui.root.setOnLongClickListener { v ->
|
||||
onCandidateAction.invoke(position, candidate.text, v)
|
||||
true
|
||||
}
|
||||
holder.ui.root.updateLayoutParams<FlexboxLayoutManager.LayoutParams> {
|
||||
width = if (isVertical) MATCH_PARENT else WRAP_CONTENT
|
||||
}
|
||||
|
||||
@ -8,22 +8,15 @@ package org.fcitx.fcitx5.android.input.candidates.horizontal
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.drawable.ShapeDrawable
|
||||
import android.graphics.drawable.shapes.RectShape
|
||||
import android.widget.PopupMenu
|
||||
import androidx.core.text.bold
|
||||
import androidx.core.text.buildSpannedString
|
||||
import androidx.core.text.color
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.flexbox.FlexboxLayoutManager
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import org.fcitx.fcitx5.android.R
|
||||
import org.fcitx.fcitx5.android.core.FcitxEvent
|
||||
import org.fcitx.fcitx5.android.daemon.launchOnReady
|
||||
import org.fcitx.fcitx5.android.data.InputFeedbacks
|
||||
import org.fcitx.fcitx5.android.data.prefs.AppPrefs
|
||||
import org.fcitx.fcitx5.android.input.bar.ExpandButtonStateMachine.BooleanKey.ExpandedCandidatesEmpty
|
||||
import org.fcitx.fcitx5.android.input.bar.ExpandButtonStateMachine.TransitionEvent.ExpandedCandidatesUpdated
|
||||
@ -38,11 +31,10 @@ import org.fcitx.fcitx5.android.input.dependency.UniqueViewComponent
|
||||
import org.fcitx.fcitx5.android.input.dependency.context
|
||||
import org.fcitx.fcitx5.android.input.dependency.fcitx
|
||||
import org.fcitx.fcitx5.android.input.dependency.inputMethodService
|
||||
import org.fcitx.fcitx5.android.input.dependency.inputView
|
||||
import org.fcitx.fcitx5.android.input.dependency.theme
|
||||
import org.fcitx.fcitx5.android.utils.item
|
||||
import org.mechdancer.dependency.manager.must
|
||||
import splitties.dimensions.dp
|
||||
import splitties.resources.styledColor
|
||||
import kotlin.math.max
|
||||
|
||||
class HorizontalCandidateComponent :
|
||||
@ -52,6 +44,7 @@ class HorizontalCandidateComponent :
|
||||
private val context by manager.context()
|
||||
private val fcitx by manager.fcitx()
|
||||
private val theme by manager.theme()
|
||||
private val inputView by manager.inputView()
|
||||
private val bar: KawaiiBarComponent by manager.must()
|
||||
|
||||
private val fillStyle by AppPrefs.getInstance().keyboard.horizontalCandidateStyle
|
||||
@ -105,7 +98,7 @@ class HorizontalCandidateComponent :
|
||||
fcitx.launchOnReady { it.select(holder.idx) }
|
||||
}
|
||||
holder.itemView.setOnLongClickListener {
|
||||
showCandidateActionMenu(holder)
|
||||
inputView.showCandidateActionMenu(holder.idx, holder.text, holder.ui.root)
|
||||
true
|
||||
}
|
||||
}
|
||||
@ -204,43 +197,4 @@ class HorizontalCandidateComponent :
|
||||
refreshExpanded(0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun triggerCandidateAction(idx: Int, actionIdx: Int) {
|
||||
fcitx.runIfReady { triggerCandidateAction(idx, actionIdx) }
|
||||
}
|
||||
|
||||
private var candidateActionMenu: PopupMenu? = null
|
||||
|
||||
fun showCandidateActionMenu(holder: CandidateViewHolder) {
|
||||
val idx = holder.idx
|
||||
val text = holder.text
|
||||
val view = holder.ui.root
|
||||
candidateActionMenu?.dismiss()
|
||||
candidateActionMenu = null
|
||||
service.lifecycleScope.launch {
|
||||
val actions = fcitx.runOnReady { getCandidateActions(idx) }
|
||||
if (actions.isEmpty()) return@launch
|
||||
InputFeedbacks.hapticFeedback(view, longPress = true)
|
||||
candidateActionMenu = PopupMenu(context, view).apply {
|
||||
menu.add(buildSpannedString {
|
||||
bold {
|
||||
color(context.styledColor(android.R.attr.colorAccent)) {
|
||||
append(text)
|
||||
}
|
||||
}
|
||||
}).apply {
|
||||
isEnabled = false
|
||||
}
|
||||
actions.forEach { action ->
|
||||
menu.item(action.text) {
|
||||
triggerCandidateAction(idx, action.id)
|
||||
}
|
||||
}
|
||||
setOnDismissListener {
|
||||
candidateActionMenu = null
|
||||
}
|
||||
show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user