fix: scroll of terminal page

This commit is contained in:
Miuzarte
2026-04-24 17:48:06 +08:00
parent b46c6ff338
commit d60badb320
6 changed files with 158 additions and 128 deletions

View File

@@ -7,6 +7,7 @@ import android.view.WindowManager
import androidx.activity.compose.setContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
@@ -21,7 +22,6 @@ import androidx.compose.material.icons.automirrored.rounded.ArrowBack
import androidx.compose.material.icons.rounded.Block
import androidx.compose.material.icons.rounded.DeleteOutline
import androidx.compose.material.icons.rounded.Edit
import androidx.compose.material.icons.rounded.MoreVert
import androidx.compose.material.icons.rounded.Password
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
@@ -42,7 +42,6 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.fragment.app.FragmentActivity
import io.github.miuzarte.scrcpyforandroid.constants.ThemeModes
import io.github.miuzarte.scrcpyforandroid.constants.UiSpacing
import io.github.miuzarte.scrcpyforandroid.password.BiometricGate
import io.github.miuzarte.scrcpyforandroid.password.PasswordCreatedState
@@ -84,6 +83,7 @@ import top.yukonga.miuix.kmp.basic.TopAppBar
import top.yukonga.miuix.kmp.blur.layerBackdrop
import top.yukonga.miuix.kmp.icon.MiuixIcons
import top.yukonga.miuix.kmp.icon.extended.Close
import top.yukonga.miuix.kmp.icon.extended.More
import top.yukonga.miuix.kmp.icon.extended.Ok
import top.yukonga.miuix.kmp.overlay.OverlayBottomSheet
import top.yukonga.miuix.kmp.overlay.OverlayDialog
@@ -234,17 +234,37 @@ private fun LockscreenPasswordScreen(
}
},
actions = {
IconButton(onClick = { showMenu = true }) {
Icon(Icons.Rounded.MoreVert, contentDescription = "更多")
Box {
IconButton(
onClick = { showMenu = true },
) {
Icon(
imageVector = MiuixIcons.More,
contentDescription = "更多",
)
}
PasswordMenuPopup(
OverlayListPopup(
show = showMenu,
popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider,
alignment = PopupPositionProvider.Align.TopEnd,
onDismissRequest = { showMenu = false },
onCreate = {
) {
ListPopupColumn {
SpinnerItemImpl(
entry = SpinnerEntry(title = "创建新密码"),
entryCount = 1,
isSelected = false,
index = 0,
spinnerColors = SpinnerDefaults.spinnerColors(),
dialogMode = false,
onSelectedIndexChange = {
showMenu = false
pendingCreate = true
},
)
}
}
}
},
scrollBehavior = scrollBehavior,
)
@@ -549,32 +569,6 @@ private fun LockscreenPasswordPage(
}
}
@Composable
private fun PasswordMenuPopup(
show: Boolean,
onDismissRequest: () -> Unit,
onCreate: (Int) -> Unit,
) {
OverlayListPopup(
show = show,
popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider,
alignment = PopupPositionProvider.Align.TopEnd,
onDismissRequest = onDismissRequest,
) {
ListPopupColumn {
SpinnerItemImpl(
entry = SpinnerEntry(title = "创建新密码"),
entryCount = 1,
isSelected = false,
index = 0,
spinnerColors = SpinnerDefaults.spinnerColors(),
dialogMode = false,
onSelectedIndexChange = onCreate,
)
}
}
}
@Composable
private fun PasswordEditorSheet(
show: Boolean,

View File

@@ -7,8 +7,6 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.MoreVert
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
@@ -31,7 +29,6 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.compose.LocalLifecycleOwner
import io.github.miuzarte.scrcpyforandroid.StreamActivity
import io.github.miuzarte.scrcpyforandroid.ui.contextClick
import io.github.miuzarte.scrcpyforandroid.models.ConnectionTarget
import io.github.miuzarte.scrcpyforandroid.models.DeviceShortcut
import io.github.miuzarte.scrcpyforandroid.models.DeviceShortcuts
@@ -57,6 +54,7 @@ import io.github.miuzarte.scrcpyforandroid.storage.Storage.scrcpyOptions
import io.github.miuzarte.scrcpyforandroid.storage.Storage.scrcpyProfiles
import io.github.miuzarte.scrcpyforandroid.ui.BlurredBar
import io.github.miuzarte.scrcpyforandroid.ui.LocalEnableBlur
import io.github.miuzarte.scrcpyforandroid.ui.contextClick
import io.github.miuzarte.scrcpyforandroid.ui.rememberBlurBackdrop
import io.github.miuzarte.scrcpyforandroid.widgets.AppListBottomSheet
import io.github.miuzarte.scrcpyforandroid.widgets.AppListEntry
@@ -88,6 +86,8 @@ import top.yukonga.miuix.kmp.basic.ScrollBehavior
import top.yukonga.miuix.kmp.basic.TextField
import top.yukonga.miuix.kmp.basic.TopAppBar
import top.yukonga.miuix.kmp.blur.layerBackdrop
import top.yukonga.miuix.kmp.icon.MiuixIcons
import top.yukonga.miuix.kmp.icon.extended.More
import top.yukonga.miuix.kmp.overlay.OverlayListPopup
import top.yukonga.miuix.kmp.theme.MiuixTheme.colorScheme
@@ -129,32 +129,54 @@ internal fun DeviceTabScreen(
if (blurActive) Color.Transparent
else colorScheme.surface,
actions = {
Box {
IconButton(
onClick = { showThreePointMenu = true },
holdDownState = showThreePointMenu,
) {
Icon(
Icons.Rounded.MoreVert,
imageVector = MiuixIcons.More,
contentDescription = "更多"
)
}
DeviceMenuPopup(
OverlayListPopup(
show = showThreePointMenu,
popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider,
alignment = PopupPositionProvider.Align.TopEnd,
onDismissRequest = { showThreePointMenu = false },
onReorderDevices = {
) {
ListPopupColumn {
PopupMenuItem(
text = "快速设备排序",
optionSize = 3,
index = 0,
onSelectedIndexChange = {
onOpenReorderDevices()
showThreePointMenu = false
},
onOpenVirtualButtonOrder = {
)
PopupMenuItem(
text = "虚拟按钮排序",
optionSize = 3,
index = 1,
onSelectedIndexChange = {
navigator.push(RootScreen.VirtualButtonOrder)
showThreePointMenu = false
},
canClearLogs = EventLogger.hasLogs(),
onClearLogs = {
)
PopupMenuItem(
text = "清空日志",
optionSize = 3,
index = 2,
enabled = EventLogger.hasLogs(),
onSelectedIndexChange = {
EventLogger.clearLogs()
showThreePointMenu = false
},
)
}
}
}
},
scrollBehavior = scrollBehavior,
)
@@ -325,7 +347,8 @@ internal fun DeviceTabPage(
adbSession.connectedScrcpyProfileId
val connectedScrcpyBundle = resolveScrcpyBundle(connectedScrcpyProfileId)
val connectedVideoPlaybackEnabled = connectedScrcpyBundle.video && connectedScrcpyBundle.videoPlayback
val connectedVideoPlaybackEnabled =
connectedScrcpyBundle.video && connectedScrcpyBundle.videoPlayback
val connectedScrcpyProfileName = remember(connectedScrcpyProfileId, scrcpyProfilesState) {
scrcpyProfilesState.profiles
.firstOrNull { it.id == connectedScrcpyProfileId }

View File

@@ -10,11 +10,9 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons
@@ -28,7 +26,6 @@ import androidx.compose.material.icons.rounded.Download
import androidx.compose.material.icons.rounded.Folder
import androidx.compose.material.icons.rounded.Image
import androidx.compose.material.icons.rounded.Link
import androidx.compose.material.icons.rounded.MoreVert
import androidx.compose.material.icons.rounded.Movie
import androidx.compose.material.icons.rounded.RawOff
import androidx.compose.material.icons.rounded.RawOn
@@ -89,6 +86,7 @@ import top.yukonga.miuix.kmp.basic.TextField
import top.yukonga.miuix.kmp.basic.rememberPullToRefreshState
import top.yukonga.miuix.kmp.blur.layerBackdrop
import top.yukonga.miuix.kmp.icon.MiuixIcons
import top.yukonga.miuix.kmp.icon.extended.More
import top.yukonga.miuix.kmp.icon.extended.Tune
import top.yukonga.miuix.kmp.overlay.OverlayBottomSheet
import top.yukonga.miuix.kmp.overlay.OverlayDialog
@@ -447,7 +445,6 @@ fun FileManagerScreen(
contentDescription = "排序",
)
}
OverlayListPopup(
show = showSortMenu,
popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider,
@@ -499,11 +496,10 @@ fun FileManagerScreen(
holdDownState = showMenu,
) {
Icon(
imageVector = Icons.Rounded.MoreVert,
imageVector = MiuixIcons.More,
contentDescription = "更多",
)
}
OverlayListPopup(
show = showMenu,
popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider,

View File

@@ -22,7 +22,6 @@ import androidx.compose.material.icons.rounded.Add
import androidx.compose.material.icons.rounded.Android
import androidx.compose.material.icons.rounded.DeleteOutline
import androidx.compose.material.icons.rounded.Edit
import androidx.compose.material.icons.rounded.MoreVert
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
@@ -101,6 +100,7 @@ import top.yukonga.miuix.kmp.basic.TextField
import top.yukonga.miuix.kmp.basic.TopAppBar
import top.yukonga.miuix.kmp.blur.layerBackdrop
import top.yukonga.miuix.kmp.icon.MiuixIcons
import top.yukonga.miuix.kmp.icon.extended.More
import top.yukonga.miuix.kmp.icon.extended.Store
import top.yukonga.miuix.kmp.overlay.OverlayBottomSheet
import top.yukonga.miuix.kmp.overlay.OverlayDialog
@@ -240,23 +240,35 @@ internal fun ScrcpyAllOptionsScreen(
}
},
actions = {
Box {
IconButton(
onClick = { showProfileMenu = true },
holdDownState = showProfileMenu,
) {
Icon(
Icons.Rounded.MoreVert,
imageVector = MiuixIcons.More,
contentDescription = "配置管理",
)
}
ProfileMenuPopup(
OverlayListPopup(
show = showProfileMenu,
popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider,
alignment = PopupPositionProvider.Align.TopEnd,
onDismissRequest = { showProfileMenu = false },
onManageProfiles = {
) {
ListPopupColumn {
ProfileMenuPopupItem(
text = "管理配置",
optionSize = 1,
index = 0,
onSelectedIndexChange = {
showManageProfilesSheet = true
showProfileMenu = false
},
)
}
}
}
},
scrollBehavior = scrollBehavior,
bottomContent = {
@@ -1891,7 +1903,9 @@ internal fun ScrcpyAllOptionsPage(
}
}
BoxWithConstraints(
modifier = Modifier.fillMaxWidth().padding(horizontal = UiSpacing.Large),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = UiSpacing.Large),
) {
val gap = UiSpacing.ContentHorizontal
val inputWidth = (maxWidth - gap * 2) / 3
@@ -2098,29 +2112,6 @@ private enum class ProfileDialogMode {
Rename,
}
@Composable
private fun ProfileMenuPopup(
show: Boolean,
onDismissRequest: () -> Unit,
onManageProfiles: () -> Unit,
) {
OverlayListPopup(
show = show,
popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider,
alignment = PopupPositionProvider.Align.TopEnd,
onDismissRequest = onDismissRequest,
) {
ListPopupColumn {
ProfileMenuPopupItem(
text = "管理配置",
optionSize = 1,
index = 0,
onSelectedIndexChange = { onManageProfiles() },
)
}
}
}
@Composable
private fun ProfileMenuPopupItem(
text: String,

View File

@@ -5,6 +5,7 @@ import android.graphics.Typeface
import android.util.Log
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.ViewConfiguration
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -20,7 +21,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ContentCopy
import androidx.compose.material.icons.rounded.MoreVert
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
@@ -79,11 +79,14 @@ import top.yukonga.miuix.kmp.basic.SnackbarResult
import top.yukonga.miuix.kmp.basic.Text
import top.yukonga.miuix.kmp.basic.TextField
import top.yukonga.miuix.kmp.blur.layerBackdrop
import top.yukonga.miuix.kmp.icon.MiuixIcons
import top.yukonga.miuix.kmp.icon.extended.More
import top.yukonga.miuix.kmp.overlay.OverlayBottomSheet
import top.yukonga.miuix.kmp.overlay.OverlayListPopup
import top.yukonga.miuix.kmp.theme.MiuixTheme.colorScheme
import java.io.File
import java.nio.charset.StandardCharsets
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.roundToInt
@@ -131,11 +134,10 @@ fun TerminalScreen(
holdDownState = showMenu,
) {
Icon(
imageVector = Icons.Rounded.MoreVert,
imageVector = MiuixIcons.More,
contentDescription = "更多",
)
}
OverlayListPopup(
show = showMenu,
popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider,
@@ -227,6 +229,11 @@ private fun TerminalPage(
var altLatched by rememberSaveable { mutableStateOf(false) }
var pendingLatchedConsume by remember { mutableStateOf(false) }
var pinchGestureLock by remember { mutableStateOf(false) }
var terminalTouchStartX by remember { mutableFloatStateOf(0f) }
var terminalTouchStartY by remember { mutableFloatStateOf(0f) }
val terminalTouchSlop = remember(context) {
ViewConfiguration.get(context).scaledTouchSlop
}
var customTypeface by remember { mutableStateOf(loadTerminalTypeface(context)) }
val sessionHolder = remember { arrayOfNulls<TerminalSession>(1) }
val terminalSurfaceColorArgb = colorScheme.surface.toArgb()
@@ -351,15 +358,33 @@ private fun TerminalPage(
view: TerminalView,
event: MotionEvent,
): Boolean {
val shouldLock =
event.pointerCount > 1 || event.actionMasked == MotionEvent.ACTION_POINTER_DOWN
if (shouldLock) {
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
terminalTouchStartX = event.x
terminalTouchStartY = event.y
}
MotionEvent.ACTION_MOVE -> {
if (!pinchGestureLock && event.pointerCount == 1) {
val dx = abs(event.x - terminalTouchStartX)
val dy = abs(event.y - terminalTouchStartY)
if (dy > terminalTouchSlop && dy > dx) {
view.parent?.requestDisallowInterceptTouchEvent(true)
pinchGestureLock = true
onTerminalGestureLockChanged(true)
}
}
}
MotionEvent.ACTION_POINTER_DOWN -> {
view.parent?.requestDisallowInterceptTouchEvent(true)
if (!pinchGestureLock) {
pinchGestureLock = true
onTerminalGestureLockChanged(true)
}
}
}
val shouldUnlock = event.actionMasked == MotionEvent.ACTION_UP ||
event.actionMasked == MotionEvent.ACTION_CANCEL ||
(event.actionMasked == MotionEvent.ACTION_POINTER_UP && event.pointerCount <= 2)

View File

@@ -29,7 +29,6 @@ import androidx.compose.material.icons.rounded.DashboardCustomize
import androidx.compose.material.icons.rounded.Home
import androidx.compose.material.icons.rounded.Keyboard
import androidx.compose.material.icons.rounded.Menu
import androidx.compose.material.icons.rounded.MoreVert
import androidx.compose.material.icons.rounded.Notifications
import androidx.compose.material.icons.rounded.Password
import androidx.compose.material.icons.rounded.PowerSettingsNew
@@ -56,10 +55,10 @@ import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import io.github.miuzarte.scrcpyforandroid.constants.UiAndroidKeycodes
import io.github.miuzarte.scrcpyforandroid.constants.UiSpacing
import io.github.miuzarte.scrcpyforandroid.ui.confirm
import io.github.miuzarte.scrcpyforandroid.ui.contextClick
import io.github.miuzarte.scrcpyforandroid.storage.AppSettings
import io.github.miuzarte.scrcpyforandroid.storage.Storage.appSettings
import io.github.miuzarte.scrcpyforandroid.ui.confirm
import io.github.miuzarte.scrcpyforandroid.ui.contextClick
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
@@ -74,6 +73,8 @@ import top.yukonga.miuix.kmp.basic.SpinnerDefaults
import top.yukonga.miuix.kmp.basic.SpinnerEntry
import top.yukonga.miuix.kmp.basic.SpinnerItemImpl
import top.yukonga.miuix.kmp.basic.Text
import top.yukonga.miuix.kmp.icon.MiuixIcons
import top.yukonga.miuix.kmp.icon.extended.More
import top.yukonga.miuix.kmp.overlay.OverlayListPopup
import top.yukonga.miuix.kmp.theme.MiuixTheme.colorScheme
@@ -86,7 +87,7 @@ enum class VirtualButtonAction(
MORE(
"more",
"更多",
Icons.Rounded.MoreVert,
MiuixIcons.More,
null
),
HOME(