feat: floating "quick ball" in fullscreen
This commit is contained in:
@@ -86,8 +86,12 @@ fun FullscreenControlScreen(
|
|||||||
VirtualButtonActions.parseStoredLayout(asBundle.virtualButtonsLayout)
|
VirtualButtonActions.parseStoredLayout(asBundle.virtualButtonsLayout)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
val floatingActions = remember(buttonItems) {
|
||||||
|
(buttonItems.first + buttonItems.second).filter { it != io.github.miuzarte.scrcpyforandroid.widgets.VirtualButtonAction.MORE }
|
||||||
|
}
|
||||||
val fullscreenDebugInfo = asBundle.fullscreenDebugInfo
|
val fullscreenDebugInfo = asBundle.fullscreenDebugInfo
|
||||||
val showFullscreenVirtualButtons = asBundle.showFullscreenVirtualButtons
|
val showFullscreenVirtualButtons = asBundle.showFullscreenVirtualButtons
|
||||||
|
val showFullscreenFloatingButton = asBundle.showFullscreenFloatingButton
|
||||||
|
|
||||||
val bar = remember(buttonItems) {
|
val bar = remember(buttonItems) {
|
||||||
VirtualButtonBar(
|
VirtualButtonBar(
|
||||||
@@ -185,6 +189,18 @@ fun FullscreenControlScreen(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (showFullscreenFloatingButton) {
|
||||||
|
bar.FloatingBall(
|
||||||
|
actions = floatingActions,
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
onAction = { action ->
|
||||||
|
action.keycode?.let {
|
||||||
|
sendKeycode(it)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,6 +259,14 @@ fun SettingsPage(
|
|||||||
asBundle = asBundle.copy(showFullscreenVirtualButtons = it)
|
asBundle = asBundle.copy(showFullscreenVirtualButtons = it)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
SwitchPreference(
|
||||||
|
title = "全屏显示悬浮球",
|
||||||
|
summary = "在全屏控制页显示可拖动的悬浮球,点击后弹出完整虚拟按键菜单",
|
||||||
|
checked = asBundle.showFullscreenFloatingButton,
|
||||||
|
onCheckedChange = {
|
||||||
|
asBundle = asBundle.copy(showFullscreenFloatingButton = it)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.content.Context
|
|||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.datastore.preferences.core.Preferences
|
import androidx.datastore.preferences.core.Preferences
|
||||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||||
|
import androidx.datastore.preferences.core.floatPreferencesKey
|
||||||
import androidx.datastore.preferences.core.intPreferencesKey
|
import androidx.datastore.preferences.core.intPreferencesKey
|
||||||
import androidx.datastore.preferences.core.longPreferencesKey
|
import androidx.datastore.preferences.core.longPreferencesKey
|
||||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||||
@@ -27,8 +28,20 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
|
|||||||
)
|
)
|
||||||
val SHOW_FULLSCREEN_VIRTUAL_BUTTONS = Pair(
|
val SHOW_FULLSCREEN_VIRTUAL_BUTTONS = Pair(
|
||||||
booleanPreferencesKey("show_fullscreen_virtual_buttons"),
|
booleanPreferencesKey("show_fullscreen_virtual_buttons"),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
val SHOW_FULLSCREEN_FLOATING_BUTTON = Pair(
|
||||||
|
booleanPreferencesKey("show_fullscreen_floating_button"),
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
val FULLSCREEN_FLOATING_BUTTON_X_FRACTION = Pair(
|
||||||
|
floatPreferencesKey("fullscreen_floating_button_x_fraction"),
|
||||||
|
0.84f
|
||||||
|
)
|
||||||
|
val FULLSCREEN_FLOATING_BUTTON_Y_FRACTION = Pair(
|
||||||
|
floatPreferencesKey("fullscreen_floating_button_y_fraction"),
|
||||||
|
0.72f
|
||||||
|
)
|
||||||
val DEVICE_PREVIEW_CARD_HEIGHT_DP = Pair(
|
val DEVICE_PREVIEW_CARD_HEIGHT_DP = Pair(
|
||||||
intPreferencesKey("device_preview_card_height_dp"),
|
intPreferencesKey("device_preview_card_height_dp"),
|
||||||
320
|
320
|
||||||
@@ -82,6 +95,9 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
|
|||||||
// Scrcpy Settings
|
// Scrcpy Settings
|
||||||
val fullscreenDebugInfo by setting(FULLSCREEN_DEBUG_INFO)
|
val fullscreenDebugInfo by setting(FULLSCREEN_DEBUG_INFO)
|
||||||
val showFullscreenVirtualButtons by setting(SHOW_FULLSCREEN_VIRTUAL_BUTTONS)
|
val showFullscreenVirtualButtons by setting(SHOW_FULLSCREEN_VIRTUAL_BUTTONS)
|
||||||
|
val showFullscreenFloatingButton by setting(SHOW_FULLSCREEN_FLOATING_BUTTON)
|
||||||
|
val fullscreenFloatingButtonXFraction by setting(FULLSCREEN_FLOATING_BUTTON_X_FRACTION)
|
||||||
|
val fullscreenFloatingButtonYFraction by setting(FULLSCREEN_FLOATING_BUTTON_Y_FRACTION)
|
||||||
val devicePreviewCardHeightDp by setting(DEVICE_PREVIEW_CARD_HEIGHT_DP)
|
val devicePreviewCardHeightDp by setting(DEVICE_PREVIEW_CARD_HEIGHT_DP)
|
||||||
val previewVirtualButtonShowText by setting(PREVIEW_VIRTUAL_BUTTON_SHOW_TEXT)
|
val previewVirtualButtonShowText by setting(PREVIEW_VIRTUAL_BUTTON_SHOW_TEXT)
|
||||||
val virtualButtonsLayout by setting(VIRTUAL_BUTTONS_LAYOUT)
|
val virtualButtonsLayout by setting(VIRTUAL_BUTTONS_LAYOUT)
|
||||||
@@ -104,6 +120,9 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
|
|||||||
val monet: Boolean,
|
val monet: Boolean,
|
||||||
val fullscreenDebugInfo: Boolean,
|
val fullscreenDebugInfo: Boolean,
|
||||||
val showFullscreenVirtualButtons: Boolean,
|
val showFullscreenVirtualButtons: Boolean,
|
||||||
|
val showFullscreenFloatingButton: Boolean,
|
||||||
|
val fullscreenFloatingButtonXFraction: Float,
|
||||||
|
val fullscreenFloatingButtonYFraction: Float,
|
||||||
val devicePreviewCardHeightDp: Int,
|
val devicePreviewCardHeightDp: Int,
|
||||||
val previewVirtualButtonShowText: Boolean,
|
val previewVirtualButtonShowText: Boolean,
|
||||||
val virtualButtonsLayout: String,
|
val virtualButtonsLayout: String,
|
||||||
@@ -123,6 +142,9 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
|
|||||||
bundleField(MONET) { bundle: Bundle -> bundle.monet },
|
bundleField(MONET) { bundle: Bundle -> bundle.monet },
|
||||||
bundleField(FULLSCREEN_DEBUG_INFO) { bundle: Bundle -> bundle.fullscreenDebugInfo },
|
bundleField(FULLSCREEN_DEBUG_INFO) { bundle: Bundle -> bundle.fullscreenDebugInfo },
|
||||||
bundleField(SHOW_FULLSCREEN_VIRTUAL_BUTTONS) { bundle: Bundle -> bundle.showFullscreenVirtualButtons },
|
bundleField(SHOW_FULLSCREEN_VIRTUAL_BUTTONS) { bundle: Bundle -> bundle.showFullscreenVirtualButtons },
|
||||||
|
bundleField(SHOW_FULLSCREEN_FLOATING_BUTTON) { bundle: Bundle -> bundle.showFullscreenFloatingButton },
|
||||||
|
bundleField(FULLSCREEN_FLOATING_BUTTON_X_FRACTION) { bundle: Bundle -> bundle.fullscreenFloatingButtonXFraction },
|
||||||
|
bundleField(FULLSCREEN_FLOATING_BUTTON_Y_FRACTION) { bundle: Bundle -> bundle.fullscreenFloatingButtonYFraction },
|
||||||
bundleField(DEVICE_PREVIEW_CARD_HEIGHT_DP) { bundle: Bundle -> bundle.devicePreviewCardHeightDp },
|
bundleField(DEVICE_PREVIEW_CARD_HEIGHT_DP) { bundle: Bundle -> bundle.devicePreviewCardHeightDp },
|
||||||
bundleField(PREVIEW_VIRTUAL_BUTTON_SHOW_TEXT) { bundle: Bundle -> bundle.previewVirtualButtonShowText },
|
bundleField(PREVIEW_VIRTUAL_BUTTON_SHOW_TEXT) { bundle: Bundle -> bundle.previewVirtualButtonShowText },
|
||||||
bundleField(VIRTUAL_BUTTONS_LAYOUT) { bundle: Bundle -> bundle.virtualButtonsLayout },
|
bundleField(VIRTUAL_BUTTONS_LAYOUT) { bundle: Bundle -> bundle.virtualButtonsLayout },
|
||||||
@@ -143,6 +165,9 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
|
|||||||
monet = preferences.read(MONET),
|
monet = preferences.read(MONET),
|
||||||
fullscreenDebugInfo = preferences.read(FULLSCREEN_DEBUG_INFO),
|
fullscreenDebugInfo = preferences.read(FULLSCREEN_DEBUG_INFO),
|
||||||
showFullscreenVirtualButtons = preferences.read(SHOW_FULLSCREEN_VIRTUAL_BUTTONS),
|
showFullscreenVirtualButtons = preferences.read(SHOW_FULLSCREEN_VIRTUAL_BUTTONS),
|
||||||
|
showFullscreenFloatingButton = preferences.read(SHOW_FULLSCREEN_FLOATING_BUTTON),
|
||||||
|
fullscreenFloatingButtonXFraction = preferences.read(FULLSCREEN_FLOATING_BUTTON_X_FRACTION),
|
||||||
|
fullscreenFloatingButtonYFraction = preferences.read(FULLSCREEN_FLOATING_BUTTON_Y_FRACTION),
|
||||||
devicePreviewCardHeightDp = preferences.read(DEVICE_PREVIEW_CARD_HEIGHT_DP),
|
devicePreviewCardHeightDp = preferences.read(DEVICE_PREVIEW_CARD_HEIGHT_DP),
|
||||||
previewVirtualButtonShowText = preferences.read(PREVIEW_VIRTUAL_BUTTON_SHOW_TEXT),
|
previewVirtualButtonShowText = preferences.read(PREVIEW_VIRTUAL_BUTTON_SHOW_TEXT),
|
||||||
virtualButtonsLayout = preferences.read(VIRTUAL_BUTTONS_LAYOUT),
|
virtualButtonsLayout = preferences.read(VIRTUAL_BUTTONS_LAYOUT),
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
package io.github.miuzarte.scrcpyforandroid.widgets
|
package io.github.miuzarte.scrcpyforandroid.widgets
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.gestures.detectDragGestures
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
|
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
|
||||||
import androidx.compose.material.icons.automirrored.rounded.VolumeDown
|
import androidx.compose.material.icons.automirrored.rounded.VolumeDown
|
||||||
@@ -22,19 +29,31 @@ import androidx.compose.material.icons.rounded.Notifications
|
|||||||
import androidx.compose.material.icons.rounded.PowerSettingsNew
|
import androidx.compose.material.icons.rounded.PowerSettingsNew
|
||||||
import androidx.compose.material.icons.rounded.Screenshot
|
import androidx.compose.material.icons.rounded.Screenshot
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.rememberUpdatedState
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import io.github.miuzarte.scrcpyforandroid.constants.UiAndroidKeycodes
|
import io.github.miuzarte.scrcpyforandroid.constants.UiAndroidKeycodes
|
||||||
import io.github.miuzarte.scrcpyforandroid.constants.UiSpacing
|
import io.github.miuzarte.scrcpyforandroid.constants.UiSpacing
|
||||||
import io.github.miuzarte.scrcpyforandroid.haptics.LocalAppHaptics
|
import io.github.miuzarte.scrcpyforandroid.haptics.LocalAppHaptics
|
||||||
import io.github.miuzarte.scrcpyforandroid.storage.AppSettings
|
import io.github.miuzarte.scrcpyforandroid.storage.AppSettings
|
||||||
|
import io.github.miuzarte.scrcpyforandroid.storage.Storage.appSettings
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import top.yukonga.miuix.kmp.basic.Button
|
import top.yukonga.miuix.kmp.basic.Button
|
||||||
import top.yukonga.miuix.kmp.basic.ButtonDefaults
|
import top.yukonga.miuix.kmp.basic.ButtonDefaults
|
||||||
@@ -214,9 +233,9 @@ class VirtualButtonBar(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (action == VirtualButtonAction.MORE) {
|
if (action == VirtualButtonAction.MORE) {
|
||||||
MorePopup(
|
ActionPopup(
|
||||||
show = showMorePopup,
|
show = showMorePopup,
|
||||||
moreActions = moreActions,
|
actions = moreActions,
|
||||||
onDismiss = { showMorePopup = false },
|
onDismiss = { showMorePopup = false },
|
||||||
onAction = {
|
onAction = {
|
||||||
onAction(it)
|
onAction(it)
|
||||||
@@ -268,9 +287,9 @@ class VirtualButtonBar(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action == VirtualButtonAction.MORE) {
|
if (action == VirtualButtonAction.MORE) {
|
||||||
MorePopup(
|
ActionPopup(
|
||||||
show = showMorePopup,
|
show = showMorePopup,
|
||||||
moreActions = moreActions,
|
actions = moreActions,
|
||||||
onDismiss = { showMorePopup = false },
|
onDismiss = { showMorePopup = false },
|
||||||
onAction = {
|
onAction = {
|
||||||
onAction(it)
|
onAction(it)
|
||||||
@@ -285,17 +304,142 @@ class VirtualButtonBar(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun MorePopup(
|
fun FloatingBall(
|
||||||
|
actions: List<VirtualButtonAction>,
|
||||||
|
onAction: suspend (VirtualButtonAction) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val taskScope = remember { CoroutineScope(SupervisorJob() + Dispatchers.IO) }
|
||||||
|
val haptics = LocalAppHaptics.current
|
||||||
|
var showActions by remember { mutableStateOf(false) }
|
||||||
|
val asBundleShared by appSettings.bundleState.collectAsState()
|
||||||
|
val asBundleSharedLatest by rememberUpdatedState(asBundleShared)
|
||||||
|
var offsetXFraction by rememberSaveable(asBundleShared.fullscreenFloatingButtonXFraction) {
|
||||||
|
mutableFloatStateOf(asBundleShared.fullscreenFloatingButtonXFraction)
|
||||||
|
}
|
||||||
|
var offsetYFraction by rememberSaveable(asBundleShared.fullscreenFloatingButtonYFraction) {
|
||||||
|
mutableFloatStateOf(asBundleShared.fullscreenFloatingButtonYFraction)
|
||||||
|
}
|
||||||
|
DisposableEffect(Unit) {
|
||||||
|
onDispose {
|
||||||
|
taskScope.launch {
|
||||||
|
val latest = asBundleSharedLatest
|
||||||
|
if (
|
||||||
|
offsetXFraction != latest.fullscreenFloatingButtonXFraction ||
|
||||||
|
offsetYFraction != latest.fullscreenFloatingButtonYFraction
|
||||||
|
) {
|
||||||
|
appSettings.saveBundle(
|
||||||
|
latest.copy(
|
||||||
|
fullscreenFloatingButtonXFraction = offsetXFraction,
|
||||||
|
fullscreenFloatingButtonYFraction = offsetYFraction,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BoxWithConstraints(
|
||||||
|
modifier = modifier.fillMaxSize(),
|
||||||
|
) {
|
||||||
|
val ballSize = 48.dp
|
||||||
|
val ringSize = 24.dp
|
||||||
|
val ringWidth = 2.dp
|
||||||
|
val maxX = (maxWidth - ballSize).coerceAtLeast(0.dp)
|
||||||
|
val maxY = (maxHeight - ballSize).coerceAtLeast(0.dp)
|
||||||
|
val currentX =
|
||||||
|
maxX * offsetXFraction.coerceIn(0f, 1f)
|
||||||
|
val currentY =
|
||||||
|
maxY * offsetYFraction.coerceIn(0f, 1f)
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.offset {
|
||||||
|
IntOffset(
|
||||||
|
currentX.roundToPx(),
|
||||||
|
currentY.roundToPx(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.size(ballSize)
|
||||||
|
.pointerInput(maxX, maxY) {
|
||||||
|
var dragStartXFraction = offsetXFraction
|
||||||
|
var dragStartYFraction = offsetYFraction
|
||||||
|
detectDragGestures(
|
||||||
|
onDragStart = {
|
||||||
|
dragStartXFraction = offsetXFraction
|
||||||
|
dragStartYFraction = offsetYFraction
|
||||||
|
},
|
||||||
|
) { change, dragAmount ->
|
||||||
|
change.consume()
|
||||||
|
val nextX =
|
||||||
|
(maxX.toPx() * dragStartXFraction + dragAmount.x).coerceIn(
|
||||||
|
0f,
|
||||||
|
maxX.toPx()
|
||||||
|
)
|
||||||
|
val nextY =
|
||||||
|
(maxY.toPx() * dragStartYFraction + dragAmount.y).coerceIn(
|
||||||
|
0f,
|
||||||
|
maxY.toPx()
|
||||||
|
)
|
||||||
|
val nextXFraction = if (maxX > 0.dp) nextX / maxX.toPx() else 0f
|
||||||
|
val nextYFraction = if (maxY > 0.dp) nextY / maxY.toPx() else 0f
|
||||||
|
dragStartXFraction = nextXFraction
|
||||||
|
dragStartYFraction = nextYFraction
|
||||||
|
offsetXFraction = nextXFraction
|
||||||
|
offsetYFraction = nextYFraction
|
||||||
|
}
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
onClick = {
|
||||||
|
haptics.contextClick()
|
||||||
|
showActions = true
|
||||||
|
},
|
||||||
|
cornerRadius = ballSize / 2,
|
||||||
|
minHeight = ballSize,
|
||||||
|
insideMargin = PaddingValues(0.dp),
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
color = Color.Black.copy(alpha = 0.24f),
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(ringSize)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.border(ringWidth, Color.White, CircleShape),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionPopup(
|
||||||
|
show = showActions,
|
||||||
|
actions = actions,
|
||||||
|
onDismiss = { showActions = false },
|
||||||
|
onAction = {
|
||||||
|
scope.launch {
|
||||||
|
onAction(it)
|
||||||
|
}
|
||||||
|
showActions = false
|
||||||
|
},
|
||||||
|
renderInRootScaffold = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ActionPopup(
|
||||||
show: Boolean,
|
show: Boolean,
|
||||||
moreActions: List<VirtualButtonAction>,
|
actions: List<VirtualButtonAction>,
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
onAction: suspend (VirtualButtonAction) -> Unit,
|
onAction: suspend (VirtualButtonAction) -> Unit,
|
||||||
renderInRootScaffold: Boolean,
|
renderInRootScaffold: Boolean,
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val haptics = LocalAppHaptics.current
|
val haptics = LocalAppHaptics.current
|
||||||
val spinnerItems = remember(moreActions) {
|
val spinnerItems = remember(actions) {
|
||||||
moreActions.map { action ->
|
actions.map { action ->
|
||||||
SpinnerEntry(
|
SpinnerEntry(
|
||||||
icon = {
|
icon = {
|
||||||
Icon(
|
Icon(
|
||||||
@@ -330,7 +474,7 @@ class VirtualButtonBar(
|
|||||||
onSelectedIndexChange = { selectedIdx ->
|
onSelectedIndexChange = { selectedIdx ->
|
||||||
haptics.confirm()
|
haptics.confirm()
|
||||||
scope.launch {
|
scope.launch {
|
||||||
onAction(moreActions[selectedIdx])
|
onAction(actions[selectedIdx])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user