From d60badb3205bd7d84ab16bdaa5c4983a4e98a3b0 Mon Sep 17 00:00:00 2001 From: Miuzarte <982809597@qq.com> Date: Fri, 24 Apr 2026 17:48:06 +0800 Subject: [PATCH] fix: scroll of terminal page --- .../LockscreenPasswordActivity.kt | 70 ++++++++-------- .../scrcpyforandroid/pages/DeviceTabScreen.kt | 81 ++++++++++++------- .../pages/FileManagerScreen.kt | 8 +- .../pages/ScrcpyAllOptionsScreen.kt | 73 ++++++++--------- .../scrcpyforandroid/pages/TerminalScreen.kt | 45 ++++++++--- .../widgets/VirtualButtons.kt | 9 ++- 6 files changed, 158 insertions(+), 128 deletions(-) diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/LockscreenPasswordActivity.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/LockscreenPasswordActivity.kt index be67d6a..248c0b3 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/LockscreenPasswordActivity.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/LockscreenPasswordActivity.kt @@ -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 = "更多", + ) + } + OverlayListPopup( + show = showMenu, + popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider, + alignment = PopupPositionProvider.Align.TopEnd, + onDismissRequest = { showMenu = false }, + ) { + ListPopupColumn { + SpinnerItemImpl( + entry = SpinnerEntry(title = "创建新密码"), + entryCount = 1, + isSelected = false, + index = 0, + spinnerColors = SpinnerDefaults.spinnerColors(), + dialogMode = false, + onSelectedIndexChange = { + showMenu = false + pendingCreate = true + }, + ) + } + } } - PasswordMenuPopup( - show = showMenu, - onDismissRequest = { showMenu = false }, - onCreate = { - 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, diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/DeviceTabScreen.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/DeviceTabScreen.kt index 6f766be..8092a3b 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/DeviceTabScreen.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/DeviceTabScreen.kt @@ -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 = { - IconButton( - onClick = { showThreePointMenu = true }, - holdDownState = showThreePointMenu, - ) { - Icon( - Icons.Rounded.MoreVert, - contentDescription = "更多" - ) + Box { + IconButton( + onClick = { showThreePointMenu = true }, + holdDownState = showThreePointMenu, + ) { + Icon( + imageVector = MiuixIcons.More, + contentDescription = "更多" + ) + } + OverlayListPopup( + show = showThreePointMenu, + popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider, + alignment = PopupPositionProvider.Align.TopEnd, + onDismissRequest = { showThreePointMenu = false }, + ) { + ListPopupColumn { + PopupMenuItem( + text = "快速设备排序", + optionSize = 3, + index = 0, + onSelectedIndexChange = { + onOpenReorderDevices() + showThreePointMenu = false + }, + ) + PopupMenuItem( + text = "虚拟按钮排序", + optionSize = 3, + index = 1, + onSelectedIndexChange = { + navigator.push(RootScreen.VirtualButtonOrder) + showThreePointMenu = false + }, + ) + PopupMenuItem( + text = "清空日志", + optionSize = 3, + index = 2, + enabled = EventLogger.hasLogs(), + onSelectedIndexChange = { + EventLogger.clearLogs() + showThreePointMenu = false + }, + ) + } + } } - DeviceMenuPopup( - show = showThreePointMenu, - onDismissRequest = { showThreePointMenu = false }, - onReorderDevices = { - onOpenReorderDevices() - showThreePointMenu = false - }, - onOpenVirtualButtonOrder = { - navigator.push(RootScreen.VirtualButtonOrder) - showThreePointMenu = false - }, - canClearLogs = EventLogger.hasLogs(), - onClearLogs = { - 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 } diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/FileManagerScreen.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/FileManagerScreen.kt index c035e81..eaeb10d 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/FileManagerScreen.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/FileManagerScreen.kt @@ -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, diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/ScrcpyAllOptionsScreen.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/ScrcpyAllOptionsScreen.kt index 7d28db6..9cdb893 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/ScrcpyAllOptionsScreen.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/ScrcpyAllOptionsScreen.kt @@ -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 = { - IconButton( - onClick = { showProfileMenu = true }, - holdDownState = showProfileMenu, - ) { - Icon( - Icons.Rounded.MoreVert, - contentDescription = "配置管理", - ) + Box { + IconButton( + onClick = { showProfileMenu = true }, + holdDownState = showProfileMenu, + ) { + Icon( + imageVector = MiuixIcons.More, + contentDescription = "配置管理", + ) + } + OverlayListPopup( + show = showProfileMenu, + popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider, + alignment = PopupPositionProvider.Align.TopEnd, + onDismissRequest = { showProfileMenu = false }, + ) { + ListPopupColumn { + ProfileMenuPopupItem( + text = "管理配置", + optionSize = 1, + index = 0, + onSelectedIndexChange = { + showManageProfilesSheet = true + showProfileMenu = false + }, + ) + } + } } - ProfileMenuPopup( - show = showProfileMenu, - onDismissRequest = { showProfileMenu = false }, - onManageProfiles = { - 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, diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/TerminalScreen.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/TerminalScreen.kt index a2c4031..e62c2ec 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/TerminalScreen.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/TerminalScreen.kt @@ -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(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) { - view.parent?.requestDisallowInterceptTouchEvent(true) - if (!pinchGestureLock) { - pinchGestureLock = true - onTerminalGestureLockChanged(true) + 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) diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/widgets/VirtualButtons.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/widgets/VirtualButtons.kt index f074c45..01bd235 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/widgets/VirtualButtons.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/widgets/VirtualButtons.kt @@ -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(