feat: language select manually
This commit is contained in:
@@ -7,7 +7,6 @@ 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
|
||||
@@ -37,13 +36,14 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.res.stringResource
|
||||
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 androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import io.github.miuzarte.scrcpyforandroid.constants.UiSpacing
|
||||
import io.github.miuzarte.scrcpyforandroid.password.BiometricGate
|
||||
import io.github.miuzarte.scrcpyforandroid.password.PasswordCreatedState
|
||||
@@ -66,19 +66,15 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import top.yukonga.miuix.kmp.basic.ButtonDefaults
|
||||
import top.yukonga.miuix.kmp.basic.Card
|
||||
import top.yukonga.miuix.kmp.basic.DropdownEntry
|
||||
import top.yukonga.miuix.kmp.basic.DropdownItem
|
||||
import top.yukonga.miuix.kmp.basic.Icon
|
||||
import top.yukonga.miuix.kmp.basic.IconButton
|
||||
import top.yukonga.miuix.kmp.basic.ListPopupColumn
|
||||
import top.yukonga.miuix.kmp.basic.ListPopupDefaults
|
||||
import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior
|
||||
import top.yukonga.miuix.kmp.basic.PopupPositionProvider
|
||||
import top.yukonga.miuix.kmp.basic.Scaffold
|
||||
import top.yukonga.miuix.kmp.basic.ScrollBehavior
|
||||
import top.yukonga.miuix.kmp.basic.SnackbarHost
|
||||
import top.yukonga.miuix.kmp.basic.SnackbarHostState
|
||||
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.basic.TextButton
|
||||
import top.yukonga.miuix.kmp.basic.TextField
|
||||
@@ -88,9 +84,9 @@ 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.menu.OverlayIconDropdownMenu
|
||||
import top.yukonga.miuix.kmp.overlay.OverlayBottomSheet
|
||||
import top.yukonga.miuix.kmp.overlay.OverlayDialog
|
||||
import top.yukonga.miuix.kmp.overlay.OverlayListPopup
|
||||
import top.yukonga.miuix.kmp.preference.ArrowPreference
|
||||
import top.yukonga.miuix.kmp.preference.SwitchPreference
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme
|
||||
@@ -124,7 +120,6 @@ class LockscreenPasswordActivity : FragmentActivity() {
|
||||
}
|
||||
MiuixTheme(
|
||||
controller = themeController,
|
||||
smoothRounding = asBundle.smoothCorner,
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalSnackbarController provides snackbarController,
|
||||
@@ -181,7 +176,6 @@ private fun LockscreenPasswordScreen(
|
||||
}
|
||||
|
||||
val entries by PasswordRepository.entriesState.collectAsState()
|
||||
var showMenu by rememberSaveable { mutableStateOf(false) }
|
||||
var pendingCreate by rememberSaveable { mutableStateOf(false) }
|
||||
var showRiskDialog by rememberSaveable { mutableStateOf(!BiometricGate.isDeviceSecure()) }
|
||||
var showDisableDialog by rememberSaveable { mutableStateOf(false) }
|
||||
@@ -191,10 +185,10 @@ private fun LockscreenPasswordScreen(
|
||||
var editorInitialName by rememberSaveable { mutableStateOf("") }
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
val observer = androidx.lifecycle.LifecycleEventObserver { _, event ->
|
||||
val observer = LifecycleEventObserver { _, event ->
|
||||
if (
|
||||
event == androidx.lifecycle.Lifecycle.Event.ON_PAUSE ||
|
||||
event == androidx.lifecycle.Lifecycle.Event.ON_STOP
|
||||
event == Lifecycle.Event.ON_PAUSE ||
|
||||
event == Lifecycle.Event.ON_STOP
|
||||
) {
|
||||
editorInitialName = ""
|
||||
}
|
||||
@@ -205,8 +199,8 @@ private fun LockscreenPasswordScreen(
|
||||
|
||||
val textCreate = stringResource(R.string.password_authenticate_create)
|
||||
val textSubtitle = stringResource(R.string.password_authenticate_subtitle)
|
||||
LaunchedEffect(pendingCreate, showMenu) {
|
||||
if (!pendingCreate || showMenu) return@LaunchedEffect
|
||||
LaunchedEffect(pendingCreate) {
|
||||
if (!pendingCreate) return@LaunchedEffect
|
||||
if (asBundle.passwordRequireAuth) {
|
||||
val ok = BiometricGate.authenticate(
|
||||
activity = activity,
|
||||
@@ -246,37 +240,23 @@ private fun LockscreenPasswordScreen(
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
Box {
|
||||
IconButton(
|
||||
onClick = { showMenu = true },
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.More,
|
||||
contentDescription = stringResource(R.string.cd_more),
|
||||
)
|
||||
}
|
||||
val textCreateNew = stringResource(R.string.password_create_new)
|
||||
OverlayListPopup(
|
||||
show = showMenu,
|
||||
popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider,
|
||||
alignment = PopupPositionProvider.Align.TopEnd,
|
||||
onDismissRequest = { showMenu = false },
|
||||
) {
|
||||
ListPopupColumn {
|
||||
SpinnerItemImpl(
|
||||
entry = SpinnerEntry(title = textCreateNew),
|
||||
entryCount = 1,
|
||||
isSelected = false,
|
||||
index = 0,
|
||||
spinnerColors = SpinnerDefaults.spinnerColors(),
|
||||
dialogMode = false,
|
||||
onSelectedIndexChange = {
|
||||
showMenu = false
|
||||
val textCreateNew = stringResource(R.string.password_create_new)
|
||||
OverlayIconDropdownMenu(
|
||||
entry = DropdownEntry(
|
||||
items = listOf(
|
||||
DropdownItem(
|
||||
text = textCreateNew,
|
||||
onClick = {
|
||||
pendingCreate = true
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.More,
|
||||
contentDescription = stringResource(R.string.cd_more),
|
||||
)
|
||||
}
|
||||
},
|
||||
scrollBehavior = scrollBehavior,
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package io.github.miuzarte.scrcpyforandroid
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Rect
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.core.content.edit
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import io.github.miuzarte.scrcpyforandroid.pages.MainScreen
|
||||
import io.github.miuzarte.scrcpyforandroid.password.BiometricGate
|
||||
@@ -13,10 +16,26 @@ import io.github.miuzarte.scrcpyforandroid.password.PasswordRepository
|
||||
import io.github.miuzarte.scrcpyforandroid.password.hasAuthenticatedOrigin
|
||||
import io.github.miuzarte.scrcpyforandroid.services.AppRuntime
|
||||
import io.github.miuzarte.scrcpyforandroid.services.AppScreenOn
|
||||
import io.github.miuzarte.scrcpyforandroid.storage.Storage.appSettings
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.Locale
|
||||
|
||||
// 生物认证需要 FragmentActivity
|
||||
class MainActivity : FragmentActivity() {
|
||||
|
||||
override fun attachBaseContext(newBase: Context) {
|
||||
val languageTag = getAppLanguageTag(newBase)
|
||||
val wrappedContext =
|
||||
if (languageTag.isNotEmpty()) {
|
||||
val config = Configuration(newBase.resources.configuration)
|
||||
config.setLocale(Locale.forLanguageTag(languageTag))
|
||||
newBase.createConfigurationContext(config)
|
||||
} else {
|
||||
newBase
|
||||
}
|
||||
super.attachBaseContext(wrappedContext)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
applyMainOrientationPolicy()
|
||||
@@ -27,6 +46,13 @@ class MainActivity : FragmentActivity() {
|
||||
|
||||
runBlocking {
|
||||
PasswordRepository.refresh()
|
||||
val cached = getAppLanguageTag(applicationContext)
|
||||
if (cached.isNotEmpty()) {
|
||||
val bundle = appSettings.loadBundle()
|
||||
if (bundle.languageTag != cached) {
|
||||
appSettings.updateBundle { it.copy(languageTag = cached) }
|
||||
}
|
||||
}
|
||||
// 认证不可用时, 清除经认证创建的密码
|
||||
if (!BiometricGate.canAuthenticate()) {
|
||||
PasswordRepository.getAll()
|
||||
@@ -75,7 +101,18 @@ class MainActivity : FragmentActivity() {
|
||||
return maxOf(width, height).toFloat() / minOf(width, height).toFloat()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
internal companion object {
|
||||
private const val PHONE_LANDSCAPE_LOCK_ASPECT_RATIO = 16f / 9f
|
||||
|
||||
private const val LOCALE_PREFS = "locale_cache"
|
||||
private const val KEY_LANGUAGE_TAG = "language_tag"
|
||||
|
||||
fun getAppLanguageTag(context: Context) =
|
||||
context.getSharedPreferences(LOCALE_PREFS, MODE_PRIVATE)
|
||||
.getString(KEY_LANGUAGE_TAG, "") ?: ""
|
||||
|
||||
fun setAppLanguageTag(context: Context, languageTag: String) =
|
||||
context.getSharedPreferences(LOCALE_PREFS, MODE_PRIVATE)
|
||||
.edit { putString(KEY_LANGUAGE_TAG, languageTag) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,10 @@ import top.yukonga.miuix.kmp.basic.BasicComponent
|
||||
import top.yukonga.miuix.kmp.basic.BasicComponentColors
|
||||
import top.yukonga.miuix.kmp.basic.BasicComponentDefaults
|
||||
import top.yukonga.miuix.kmp.basic.DropdownArrowEndAction
|
||||
import top.yukonga.miuix.kmp.basic.DropdownColors
|
||||
import top.yukonga.miuix.kmp.basic.DropdownDefaults
|
||||
import top.yukonga.miuix.kmp.basic.ListPopupColumn
|
||||
import top.yukonga.miuix.kmp.basic.PopupPositionProvider
|
||||
import top.yukonga.miuix.kmp.basic.SpinnerColors
|
||||
import top.yukonga.miuix.kmp.basic.SpinnerDefaults
|
||||
import top.yukonga.miuix.kmp.basic.Text
|
||||
import top.yukonga.miuix.kmp.overlay.OverlayListPopup
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme
|
||||
@@ -44,7 +44,7 @@ fun OverlaySpinnerPreference(
|
||||
titleColor: BasicComponentColors = BasicComponentDefaults.titleColor(),
|
||||
summary: String? = null,
|
||||
summaryColor: BasicComponentColors = BasicComponentDefaults.summaryColor(),
|
||||
spinnerColors: SpinnerColors = SpinnerDefaults.spinnerColors(),
|
||||
spinnerColors: DropdownColors = DropdownDefaults.dropdownColors(),
|
||||
startAction: @Composable (() -> Unit)? = null,
|
||||
bottomAction: (@Composable () -> Unit)? = null,
|
||||
insideMargin: PaddingValues = BasicComponentDefaults.InsideMargin,
|
||||
@@ -145,7 +145,7 @@ private fun OverlaySpinnerPopup(
|
||||
onDismissFinished: () -> Unit,
|
||||
maxHeight: Dp?,
|
||||
hapticFeedback: HapticFeedback,
|
||||
spinnerColors: SpinnerColors,
|
||||
spinnerColors: DropdownColors,
|
||||
renderInRootScaffold: Boolean,
|
||||
onSelectedIndexChange: ((Int) -> Unit)?,
|
||||
) {
|
||||
|
||||
@@ -22,7 +22,7 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import top.yukonga.miuix.kmp.basic.SpinnerColors
|
||||
import top.yukonga.miuix.kmp.basic.DropdownColors
|
||||
import top.yukonga.miuix.kmp.basic.Text
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme
|
||||
|
||||
@@ -32,7 +32,7 @@ fun SpinnerItemImpl(
|
||||
entryCount: Int,
|
||||
isSelected: Boolean,
|
||||
index: Int,
|
||||
spinnerColors: SpinnerColors,
|
||||
spinnerColors: DropdownColors,
|
||||
dialogMode: Boolean = false,
|
||||
enabled: Boolean = true,
|
||||
onSelectedIndexChange: (Int) -> Unit,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.github.miuzarte.scrcpyforandroid.pages
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@@ -15,6 +14,7 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -72,7 +72,6 @@ import top.yukonga.miuix.kmp.blur.layerBackdrop
|
||||
import top.yukonga.miuix.kmp.blur.rememberLayerBackdrop
|
||||
import top.yukonga.miuix.kmp.blur.textureBlur
|
||||
import top.yukonga.miuix.kmp.preference.ArrowPreference
|
||||
import top.yukonga.miuix.kmp.shapes.SmoothRoundedCornerShape
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme.colorScheme
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme.textStyles
|
||||
import java.util.Locale.getDefault
|
||||
@@ -208,7 +207,7 @@ private fun AboutContent(
|
||||
Card(
|
||||
modifier = modifier.textureBlur(
|
||||
backdrop = backdrop,
|
||||
shape = SmoothRoundedCornerShape(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
blurRadius = 60f,
|
||||
noiseCoefficient = BlurDefaults.NoiseCoefficient,
|
||||
colors = BlurColors(blendColors = cardBlendColors),
|
||||
@@ -285,7 +284,7 @@ private fun AboutContent(
|
||||
}
|
||||
.textureBlur(
|
||||
backdrop = backdrop,
|
||||
shape = SmoothRoundedCornerShape(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
blurRadius = 150f,
|
||||
noiseCoefficient = BlurDefaults.NoiseCoefficient,
|
||||
colors = BlurColors(blendColors = heroBlendColors),
|
||||
|
||||
@@ -58,7 +58,6 @@ import io.github.miuzarte.scrcpyforandroid.services.ConnectionStateStore
|
||||
import io.github.miuzarte.scrcpyforandroid.services.DeviceAdbAutoReconnectManager
|
||||
import io.github.miuzarte.scrcpyforandroid.services.DeviceAdbConnectionCoordinator
|
||||
import io.github.miuzarte.scrcpyforandroid.services.EventLogger
|
||||
import io.github.miuzarte.scrcpyforandroid.services.LocalSnackbarController
|
||||
import io.github.miuzarte.scrcpyforandroid.ui.BlurredBar
|
||||
import io.github.miuzarte.scrcpyforandroid.ui.LocalEnableBlur
|
||||
import io.github.miuzarte.scrcpyforandroid.ui.contextClick
|
||||
@@ -77,12 +76,10 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import top.yukonga.miuix.kmp.basic.Card
|
||||
import top.yukonga.miuix.kmp.basic.DropdownImpl
|
||||
import top.yukonga.miuix.kmp.basic.DropdownEntry
|
||||
import top.yukonga.miuix.kmp.basic.DropdownItem
|
||||
import top.yukonga.miuix.kmp.basic.Icon
|
||||
import top.yukonga.miuix.kmp.basic.IconButton
|
||||
import top.yukonga.miuix.kmp.basic.ListPopupColumn
|
||||
import top.yukonga.miuix.kmp.basic.ListPopupDefaults
|
||||
import top.yukonga.miuix.kmp.basic.PopupPositionProvider
|
||||
import top.yukonga.miuix.kmp.basic.Scaffold
|
||||
import top.yukonga.miuix.kmp.basic.ScrollBehavior
|
||||
import top.yukonga.miuix.kmp.basic.SmallTopAppBar
|
||||
@@ -91,7 +88,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.More
|
||||
import top.yukonga.miuix.kmp.overlay.OverlayListPopup
|
||||
import top.yukonga.miuix.kmp.menu.OverlayIconDropdownMenu
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme.colorScheme
|
||||
|
||||
private const val PREVIEW_CARD_ITEM_KEY = "preview_card"
|
||||
@@ -117,7 +114,6 @@ internal fun DeviceTabScreen(
|
||||
val viewModel: DeviceTabViewModel = viewModel(factory = viewModelFactory)
|
||||
|
||||
val navigator = LocalRootNavigator.current
|
||||
var showThreePointMenu by rememberSaveable { mutableStateOf(false) }
|
||||
var useCompactTopAppBar by remember { mutableStateOf(false) }
|
||||
var showTwoPaneSideAction by remember { mutableStateOf(false) }
|
||||
var configPanelOnLeft by remember { mutableStateOf(true) }
|
||||
@@ -145,56 +141,35 @@ internal fun DeviceTabScreen(
|
||||
)
|
||||
}
|
||||
}
|
||||
Box {
|
||||
IconButton(
|
||||
onClick = { showThreePointMenu = true },
|
||||
holdDownState = showThreePointMenu,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.More,
|
||||
contentDescription = stringResource(R.string.cd_more),
|
||||
)
|
||||
}
|
||||
OverlayListPopup(
|
||||
show = showThreePointMenu,
|
||||
popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider,
|
||||
alignment = PopupPositionProvider.Align.TopEnd,
|
||||
onDismissRequest = { showThreePointMenu = false },
|
||||
) {
|
||||
ListPopupColumn {
|
||||
DropdownImpl(
|
||||
OverlayIconDropdownMenu(
|
||||
entry = DropdownEntry(
|
||||
items = listOf(
|
||||
DropdownItem(
|
||||
text = stringResource(R.string.device_menu_quick_sort),
|
||||
optionSize = 3,
|
||||
isSelected = false,
|
||||
index = 0,
|
||||
onSelectedIndexChange = {
|
||||
onClick = {
|
||||
onOpenReorderDevices()
|
||||
showThreePointMenu = false
|
||||
},
|
||||
)
|
||||
DropdownImpl(
|
||||
),
|
||||
DropdownItem(
|
||||
text = stringResource(R.string.device_menu_virtual_button_sort),
|
||||
optionSize = 3,
|
||||
isSelected = false,
|
||||
index = 1,
|
||||
onSelectedIndexChange = {
|
||||
onClick = {
|
||||
navigator.push(RootScreen.VirtualButtonOrder)
|
||||
showThreePointMenu = false
|
||||
},
|
||||
)
|
||||
DropdownImpl(
|
||||
),
|
||||
DropdownItem(
|
||||
text = stringResource(R.string.device_menu_clear_logs),
|
||||
optionSize = 3,
|
||||
isSelected = false,
|
||||
index = 2,
|
||||
enabled = EventLogger.hasLogs(),
|
||||
onSelectedIndexChange = {
|
||||
onClick = {
|
||||
EventLogger.clearLogs()
|
||||
showThreePointMenu = false
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.More,
|
||||
contentDescription = stringResource(R.string.cd_more),
|
||||
)
|
||||
}
|
||||
}
|
||||
if (useCompactTopAppBar) SmallTopAppBar(
|
||||
|
||||
@@ -53,7 +53,6 @@ import io.github.miuzarte.scrcpyforandroid.scaffolds.LazyColumn
|
||||
import io.github.miuzarte.scrcpyforandroid.services.AppRuntime
|
||||
import io.github.miuzarte.scrcpyforandroid.services.DirectoryDownloadSnapshot
|
||||
import io.github.miuzarte.scrcpyforandroid.services.FileManagerService
|
||||
import io.github.miuzarte.scrcpyforandroid.services.LocalSnackbarController
|
||||
import io.github.miuzarte.scrcpyforandroid.services.RemoteFileEntry
|
||||
import io.github.miuzarte.scrcpyforandroid.services.RemoteFileKind
|
||||
import io.github.miuzarte.scrcpyforandroid.services.RemoteFileStat
|
||||
@@ -61,12 +60,10 @@ import io.github.miuzarte.scrcpyforandroid.ui.BlurredBar
|
||||
import io.github.miuzarte.scrcpyforandroid.ui.LocalEnableBlur
|
||||
import io.github.miuzarte.scrcpyforandroid.ui.rememberBlurBackdrop
|
||||
import top.yukonga.miuix.kmp.basic.Card
|
||||
import top.yukonga.miuix.kmp.basic.DropdownImpl
|
||||
import top.yukonga.miuix.kmp.basic.HorizontalDivider
|
||||
import top.yukonga.miuix.kmp.basic.DropdownEntry
|
||||
import top.yukonga.miuix.kmp.basic.DropdownItem
|
||||
import top.yukonga.miuix.kmp.basic.Icon
|
||||
import top.yukonga.miuix.kmp.basic.IconButton
|
||||
import top.yukonga.miuix.kmp.basic.ListPopupColumn
|
||||
import top.yukonga.miuix.kmp.basic.ListPopupDefaults
|
||||
import top.yukonga.miuix.kmp.basic.PullToRefresh
|
||||
import top.yukonga.miuix.kmp.basic.PullToRefreshState
|
||||
import top.yukonga.miuix.kmp.basic.Scaffold
|
||||
@@ -79,9 +76,9 @@ 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.menu.OverlayIconDropdownMenu
|
||||
import top.yukonga.miuix.kmp.overlay.OverlayBottomSheet
|
||||
import top.yukonga.miuix.kmp.overlay.OverlayDialog
|
||||
import top.yukonga.miuix.kmp.overlay.OverlayListPopup
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme.colorScheme
|
||||
|
||||
private const val INITIAL_REMOTE_PATH = "/storage/emulated/0"
|
||||
@@ -216,43 +213,33 @@ fun FileManagerScreen(
|
||||
)
|
||||
},
|
||||
actions = {
|
||||
Box {
|
||||
IconButton(
|
||||
onClick = { showSortMenu = true },
|
||||
holdDownState = showSortMenu
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.Tune,
|
||||
contentDescription = stringResource(R.string.fm_cd_sort),
|
||||
)
|
||||
}
|
||||
OverlayListPopup(
|
||||
show = showSortMenu,
|
||||
popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider,
|
||||
onDismissRequest = { showSortMenu = false },
|
||||
) {
|
||||
ListPopupColumn {
|
||||
val sortOptions = listOf(
|
||||
stringResource(R.string.fm_sort_name),
|
||||
stringResource(R.string.fm_sort_size),
|
||||
stringResource(R.string.fm_sort_time),
|
||||
stringResource(R.string.fm_sort_extension),
|
||||
)
|
||||
val sortFieldIdx = when (sortField) {
|
||||
FileManagerSortField.NAME -> 0
|
||||
FileManagerSortField.SIZE -> 1
|
||||
FileManagerSortField.TIME -> 2
|
||||
FileManagerSortField.EXTENSION -> 3
|
||||
}
|
||||
sortOptions.forEachIndexed { i, option ->
|
||||
DropdownImpl(
|
||||
val sortOptions = listOf(
|
||||
stringResource(R.string.fm_sort_name),
|
||||
stringResource(R.string.fm_sort_size),
|
||||
stringResource(R.string.fm_sort_time),
|
||||
stringResource(R.string.fm_sort_extension),
|
||||
)
|
||||
val sortFieldIdx = when (sortField) {
|
||||
FileManagerSortField.NAME -> 0
|
||||
FileManagerSortField.SIZE -> 1
|
||||
FileManagerSortField.TIME -> 2
|
||||
FileManagerSortField.EXTENSION -> 3
|
||||
}
|
||||
val dirOptions = listOf(
|
||||
stringResource(R.string.fm_sort_asc),
|
||||
stringResource(R.string.fm_sort_desc),
|
||||
)
|
||||
val dirIdx = if (sortDescending) 1 else 0
|
||||
OverlayIconDropdownMenu(
|
||||
entries = listOf(
|
||||
DropdownEntry(
|
||||
items = sortOptions.mapIndexed { i, option ->
|
||||
DropdownItem(
|
||||
text = option,
|
||||
optionSize = sortOptions.size,
|
||||
isSelected = i == sortFieldIdx,
|
||||
index = i,
|
||||
onSelectedIndexChange = { index ->
|
||||
selected = i == sortFieldIdx,
|
||||
onClick = {
|
||||
viewModel.updateSort(
|
||||
sortBy = when (index) {
|
||||
sortBy = when (i) {
|
||||
1 -> FileManagerSortField.SIZE
|
||||
2 -> FileManagerSortField.TIME
|
||||
3 -> FileManagerSortField.EXTENSION
|
||||
@@ -262,67 +249,51 @@ fun FileManagerScreen(
|
||||
},
|
||||
)
|
||||
}
|
||||
HorizontalDivider(modifier = Modifier.padding(horizontal = 20.dp))
|
||||
val dirOptions = listOf(
|
||||
stringResource(R.string.fm_sort_asc),
|
||||
stringResource(R.string.fm_sort_desc),
|
||||
)
|
||||
val dirIdx = if (sortDescending) 1 else 0
|
||||
dirOptions.forEachIndexed { i, option ->
|
||||
DropdownImpl(
|
||||
),
|
||||
DropdownEntry(
|
||||
items = dirOptions.mapIndexed { i, option ->
|
||||
DropdownItem(
|
||||
text = option,
|
||||
optionSize = dirOptions.size,
|
||||
isSelected = i == dirIdx,
|
||||
index = i,
|
||||
onSelectedIndexChange = { index ->
|
||||
selected = i == dirIdx,
|
||||
onClick = {
|
||||
viewModel.updateSort(
|
||||
descending = index == 1
|
||||
descending = i == 1
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
),
|
||||
)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.Tune,
|
||||
contentDescription = stringResource(R.string.fm_cd_sort),
|
||||
)
|
||||
}
|
||||
Box {
|
||||
IconButton(
|
||||
onClick = { showMenu = true },
|
||||
holdDownState = showMenu,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.More,
|
||||
contentDescription = stringResource(R.string.cd_more),
|
||||
)
|
||||
}
|
||||
OverlayListPopup(
|
||||
show = showMenu,
|
||||
popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider,
|
||||
onDismissRequest = { showMenu = false },
|
||||
) {
|
||||
ListPopupColumn {
|
||||
DropdownImpl(
|
||||
|
||||
OverlayIconDropdownMenu(
|
||||
entry = DropdownEntry(
|
||||
items = listOf(
|
||||
DropdownItem(
|
||||
text = stringResource(R.string.fm_menu_create_folder),
|
||||
optionSize = 2,
|
||||
isSelected = false,
|
||||
index = 0,
|
||||
onSelectedIndexChange = {
|
||||
showMenu = false
|
||||
onClick = {
|
||||
newFolderName = ""
|
||||
showCreateFolderDialog = true
|
||||
},
|
||||
)
|
||||
DropdownImpl(
|
||||
),
|
||||
DropdownItem(
|
||||
text = stringResource(R.string.fm_menu_upload),
|
||||
optionSize = 2,
|
||||
isSelected = false,
|
||||
index = 1,
|
||||
onSelectedIndexChange = {
|
||||
showMenu = false
|
||||
onClick = {
|
||||
uploadLauncher.launch(arrayOf("*/*"))
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.More,
|
||||
contentDescription = stringResource(R.string.cd_more),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@@ -725,7 +725,6 @@ fun MainScreen() {
|
||||
|
||||
MiuixTheme(
|
||||
controller = themeController,
|
||||
smoothRounding = asBundle.smoothCorner,
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalEnableBlur provides asBundle.blur,
|
||||
|
||||
@@ -84,12 +84,10 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import top.yukonga.miuix.kmp.basic.ButtonDefaults
|
||||
import top.yukonga.miuix.kmp.basic.Card
|
||||
import top.yukonga.miuix.kmp.basic.DropdownImpl
|
||||
import top.yukonga.miuix.kmp.basic.DropdownEntry
|
||||
import top.yukonga.miuix.kmp.basic.DropdownItem
|
||||
import top.yukonga.miuix.kmp.basic.Icon
|
||||
import top.yukonga.miuix.kmp.basic.IconButton
|
||||
import top.yukonga.miuix.kmp.basic.ListPopupColumn
|
||||
import top.yukonga.miuix.kmp.basic.ListPopupDefaults
|
||||
import top.yukonga.miuix.kmp.basic.PopupPositionProvider
|
||||
import top.yukonga.miuix.kmp.basic.Scaffold
|
||||
import top.yukonga.miuix.kmp.basic.ScrollBehavior
|
||||
import top.yukonga.miuix.kmp.basic.SnackbarHost
|
||||
@@ -102,9 +100,9 @@ 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.menu.OverlayIconDropdownMenu
|
||||
import top.yukonga.miuix.kmp.overlay.OverlayBottomSheet
|
||||
import top.yukonga.miuix.kmp.overlay.OverlayDialog
|
||||
import top.yukonga.miuix.kmp.overlay.OverlayListPopup
|
||||
import top.yukonga.miuix.kmp.preference.OverlayDropdownPreference
|
||||
import top.yukonga.miuix.kmp.preference.SwitchPreference
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme.colorScheme
|
||||
@@ -230,35 +228,23 @@ internal fun ScrcpyAllOptionsScreen(
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
Box {
|
||||
IconButton(
|
||||
onClick = { showProfileMenu = true },
|
||||
holdDownState = showProfileMenu,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.More,
|
||||
contentDescription = stringResource(R.string.scrcpyopt_cd_profile_manage),
|
||||
)
|
||||
}
|
||||
OverlayListPopup(
|
||||
show = showProfileMenu,
|
||||
popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider,
|
||||
alignment = PopupPositionProvider.Align.TopEnd,
|
||||
onDismissRequest = { showProfileMenu = false },
|
||||
) {
|
||||
ListPopupColumn {
|
||||
DropdownImpl(
|
||||
OverlayIconDropdownMenu(
|
||||
entry = DropdownEntry(
|
||||
items = listOf(
|
||||
DropdownItem(
|
||||
text = stringResource(R.string.scrcpyopt_manage_profiles),
|
||||
optionSize = 1,
|
||||
isSelected = false,
|
||||
index = 0,
|
||||
onSelectedIndexChange = {
|
||||
onClick = {
|
||||
showManageProfilesSheet = true
|
||||
showProfileMenu = false
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.More,
|
||||
contentDescription = stringResource(R.string.scrcpyopt_cd_profile_manage),
|
||||
)
|
||||
}
|
||||
},
|
||||
scrollBehavior = scrollBehavior,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package io.github.miuzarte.scrcpyforandroid.pages
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.provider.OpenableColumns
|
||||
import androidx.activity.compose.LocalActivity
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
@@ -41,6 +41,7 @@ import androidx.compose.ui.unit.Dp
|
||||
import androidx.core.net.toUri
|
||||
import io.github.miuzarte.scrcpyforandroid.BuildConfig
|
||||
import io.github.miuzarte.scrcpyforandroid.LockscreenPasswordActivity
|
||||
import io.github.miuzarte.scrcpyforandroid.MainActivity
|
||||
import io.github.miuzarte.scrcpyforandroid.R
|
||||
import io.github.miuzarte.scrcpyforandroid.constants.UiSpacing
|
||||
import io.github.miuzarte.scrcpyforandroid.nativecore.DirectAdbTransport
|
||||
@@ -87,6 +88,11 @@ import java.io.File
|
||||
import kotlin.math.roundToInt
|
||||
import android.provider.Settings as AndroidSettings
|
||||
|
||||
private val languages = listOf(
|
||||
R.string.language_follow_system to "",
|
||||
R.string.language_english to "en",
|
||||
R.string.language_chinese to "zh",
|
||||
)
|
||||
private const val TERMINAL_FONT_RELATIVE_PATH = "terminal/font.ttf"
|
||||
private val monetPaletteStyleOptions = ThemePaletteStyle.entries.map { it.name }
|
||||
private val monetColorSpecOptions = ThemeColorSpec.entries.map { it.name }
|
||||
@@ -159,6 +165,7 @@ fun SettingsPage(
|
||||
bottomInnerPadding: Dp,
|
||||
onOpenReorderDevices: () -> Unit,
|
||||
) {
|
||||
val activity = LocalActivity.current
|
||||
val context = LocalContext.current
|
||||
val updateState by AppUpdateChecker.state.collectAsState()
|
||||
|
||||
@@ -292,6 +299,27 @@ fun SettingsPage(
|
||||
item {
|
||||
SectionSmallTitle(stringResource(R.string.section_theme))
|
||||
Card {
|
||||
OverlayDropdownPreference(
|
||||
title = stringResource(R.string.pref_title_language),
|
||||
summary = stringResource(R.string.pref_summary_language),
|
||||
entries = listOf(
|
||||
DropdownEntry(
|
||||
items = languages.map { lang ->
|
||||
DropdownItem(
|
||||
text = stringResource(lang.first),
|
||||
selected = lang.second == asBundle.languageTag,
|
||||
onClick = {
|
||||
asBundle = asBundle.copy(
|
||||
languageTag = lang.second
|
||||
)
|
||||
MainActivity.setAppLanguageTag(context, lang.second)
|
||||
activity?.recreate()
|
||||
},
|
||||
)
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
OverlayDropdownPreference(
|
||||
title = stringResource(R.string.pref_title_appearance_mode),
|
||||
summary = stringResource(R.string.pref_summary_appearance_mode),
|
||||
@@ -393,16 +421,6 @@ fun SettingsPage(
|
||||
)
|
||||
}
|
||||
}
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.pref_title_smooth_corners),
|
||||
summary = stringResource(R.string.pref_summary_smooth_corners),
|
||||
checked = asBundle.smoothCorner,
|
||||
onCheckedChange = {
|
||||
asBundle = asBundle.copy(
|
||||
smoothCorner = it
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,33 +553,41 @@ fun SettingsPage(
|
||||
entries = listOf(
|
||||
DropdownEntry(
|
||||
items = FullscreenVirtualButtonDock
|
||||
.modeItemsResIds.map { DropdownItem(stringResource(it)) },
|
||||
selectedIndex = fullscreenVirtualButtonDock.modeIndex,
|
||||
onSelectedIndexChange = { modeIndex ->
|
||||
asBundle = asBundle.copy(
|
||||
fullscreenVirtualButtonDock = FullscreenVirtualButtonDock
|
||||
.fromModeAndDirection(
|
||||
modeIndex = modeIndex,
|
||||
directionIndex = fullscreenVirtualButtonDock.directionIndex,
|
||||
)
|
||||
.toStoredValue()
|
||||
)
|
||||
},
|
||||
.modeItemsResIds.mapIndexed { index, id ->
|
||||
DropdownItem(
|
||||
text = stringResource(id),
|
||||
selected = index == fullscreenVirtualButtonDock.modeIndex,
|
||||
onClick = {
|
||||
asBundle = asBundle.copy(
|
||||
fullscreenVirtualButtonDock = FullscreenVirtualButtonDock
|
||||
.fromModeAndDirection(
|
||||
modeIndex = index,
|
||||
directionIndex = fullscreenVirtualButtonDock.directionIndex,
|
||||
)
|
||||
.toStoredValue()
|
||||
)
|
||||
},
|
||||
)
|
||||
},
|
||||
),
|
||||
DropdownEntry(
|
||||
items = FullscreenVirtualButtonDock
|
||||
.directionItemsResIds.map { DropdownItem(stringResource(it)) },
|
||||
selectedIndex = fullscreenVirtualButtonDock.directionIndex,
|
||||
onSelectedIndexChange = { directionIndex ->
|
||||
asBundle = asBundle.copy(
|
||||
fullscreenVirtualButtonDock = FullscreenVirtualButtonDock
|
||||
.fromModeAndDirection(
|
||||
modeIndex = fullscreenVirtualButtonDock.modeIndex,
|
||||
directionIndex = directionIndex,
|
||||
)
|
||||
.toStoredValue()
|
||||
)
|
||||
},
|
||||
.directionItemsResIds.mapIndexed { index, id ->
|
||||
DropdownItem(
|
||||
text = stringResource(id),
|
||||
selected = index == fullscreenVirtualButtonDock.directionIndex,
|
||||
onClick = {
|
||||
asBundle = asBundle.copy(
|
||||
fullscreenVirtualButtonDock = FullscreenVirtualButtonDock
|
||||
.fromModeAndDirection(
|
||||
modeIndex = fullscreenVirtualButtonDock.modeIndex,
|
||||
directionIndex = index,
|
||||
)
|
||||
.toStoredValue()
|
||||
)
|
||||
},
|
||||
)
|
||||
},
|
||||
),
|
||||
),
|
||||
title = stringResource(R.string.pref_title_virtual_button_direction),
|
||||
|
||||
@@ -101,7 +101,6 @@ fun StreamScreen(activity: StreamActivity) {
|
||||
|
||||
MiuixTheme(
|
||||
controller = themeController,
|
||||
smoothRounding = asBundle.smoothCorner,
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalSnackbarController provides snackbarController,
|
||||
|
||||
@@ -38,8 +38,8 @@ import androidx.compose.ui.graphics.luminance
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
@@ -52,16 +52,14 @@ import io.github.miuzarte.scrcpyforandroid.R
|
||||
import io.github.miuzarte.scrcpyforandroid.constants.UiSpacing
|
||||
import io.github.miuzarte.scrcpyforandroid.services.AppRuntime
|
||||
import io.github.miuzarte.scrcpyforandroid.services.LocalInputService
|
||||
import io.github.miuzarte.scrcpyforandroid.services.LocalSnackbarController
|
||||
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 top.yukonga.miuix.kmp.basic.DropdownImpl
|
||||
import top.yukonga.miuix.kmp.basic.DropdownEntry
|
||||
import top.yukonga.miuix.kmp.basic.DropdownItem
|
||||
import top.yukonga.miuix.kmp.basic.Icon
|
||||
import top.yukonga.miuix.kmp.basic.IconButton
|
||||
import top.yukonga.miuix.kmp.basic.ListPopupColumn
|
||||
import top.yukonga.miuix.kmp.basic.ListPopupDefaults
|
||||
import top.yukonga.miuix.kmp.basic.Scaffold
|
||||
import top.yukonga.miuix.kmp.basic.SmallTopAppBar
|
||||
import top.yukonga.miuix.kmp.basic.Text
|
||||
@@ -69,8 +67,8 @@ 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.menu.OverlayIconDropdownMenu
|
||||
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 kotlin.math.abs
|
||||
@@ -98,7 +96,6 @@ fun TerminalScreen(
|
||||
val context = LocalContext.current
|
||||
val blurBackdrop = rememberBlurBackdrop(LocalEnableBlur.current)
|
||||
val blurActive = blurBackdrop != null
|
||||
var showMenu by rememberSaveable { mutableStateOf(false) }
|
||||
var showOutputSheet by rememberSaveable { mutableStateOf(false) }
|
||||
var output by rememberSaveable { mutableStateOf("") }
|
||||
|
||||
@@ -111,45 +108,29 @@ fun TerminalScreen(
|
||||
if (blurActive) Color.Transparent
|
||||
else colorScheme.surface,
|
||||
actions = {
|
||||
Box {
|
||||
IconButton(
|
||||
onClick = { showMenu = true },
|
||||
holdDownState = showMenu,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.More,
|
||||
contentDescription = stringResource(R.string.cd_more),
|
||||
)
|
||||
}
|
||||
OverlayListPopup(
|
||||
show = showMenu,
|
||||
popupPositionProvider = ListPopupDefaults.ContextMenuPositionProvider,
|
||||
onDismissRequest = { showMenu = false },
|
||||
) {
|
||||
ListPopupColumn {
|
||||
DropdownImpl(
|
||||
OverlayIconDropdownMenu(
|
||||
entry = DropdownEntry(
|
||||
items = listOf(
|
||||
DropdownItem(
|
||||
text = stringResource(R.string.terminal_menu_free_copy),
|
||||
optionSize = 2,
|
||||
isSelected = false,
|
||||
index = 0,
|
||||
enabled = output.isNotBlank(),
|
||||
onSelectedIndexChange = {
|
||||
showMenu = false
|
||||
onClick = {
|
||||
showOutputSheet = true
|
||||
},
|
||||
)
|
||||
DropdownImpl(
|
||||
),
|
||||
DropdownItem(
|
||||
text = stringResource(R.string.terminal_menu_clear_screen),
|
||||
optionSize = 2,
|
||||
isSelected = false,
|
||||
index = 1,
|
||||
onSelectedIndexChange = {
|
||||
showMenu = false
|
||||
onClick = {
|
||||
output = ""
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.More,
|
||||
contentDescription = stringResource(R.string.cd_more),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -175,7 +156,6 @@ fun TerminalScreen(
|
||||
output = output,
|
||||
onDismissRequest = { showOutputSheet = false },
|
||||
onCopyAll = {
|
||||
showMenu = false
|
||||
LocalInputService.setClipboardText(context, output)
|
||||
AppRuntime.snackbar(R.string.terminal_copied_all)
|
||||
},
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.github.miuzarte.scrcpyforandroid.password
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.activity.compose.LocalActivity
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@@ -13,23 +12,18 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import io.github.miuzarte.scrcpyforandroid.R
|
||||
import io.github.miuzarte.scrcpyforandroid.constants.UiSpacing
|
||||
import io.github.miuzarte.scrcpyforandroid.services.AppRuntime
|
||||
import io.github.miuzarte.scrcpyforandroid.services.LocalSnackbarController
|
||||
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 top.yukonga.miuix.kmp.basic.DropdownDefaults
|
||||
import top.yukonga.miuix.kmp.basic.DropdownItem
|
||||
import top.yukonga.miuix.kmp.basic.Icon
|
||||
import top.yukonga.miuix.kmp.basic.ListPopupColumn
|
||||
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.theme.MiuixTheme.colorScheme
|
||||
@@ -37,7 +31,6 @@ import top.yukonga.miuix.kmp.theme.MiuixTheme.colorScheme
|
||||
@Composable
|
||||
fun PasswordPickerPopupContent(onDismissRequest: () -> Unit) {
|
||||
val fragActivity = LocalActivity.current as? FragmentActivity
|
||||
val taskScope = remember { CoroutineScope(SupervisorJob() + Dispatchers.IO) }
|
||||
val scope = rememberCoroutineScope()
|
||||
val passwordUseCase = remember { PasswordUseCase() }
|
||||
val entries by PasswordRepository.entriesState.collectAsState()
|
||||
@@ -49,7 +42,7 @@ fun PasswordPickerPopupContent(onDismissRequest: () -> Unit) {
|
||||
val textBurned = stringResource(R.string.password_status_burned)
|
||||
val spinnerEntries = remember(entries) {
|
||||
entries.map { entry ->
|
||||
SpinnerEntry(
|
||||
DropdownItem(
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector =
|
||||
@@ -123,7 +116,7 @@ fun PasswordPickerPopupContent(onDismissRequest: () -> Unit) {
|
||||
entryCount = spinnerEntries.size,
|
||||
isSelected = false,
|
||||
index = index,
|
||||
spinnerColors = SpinnerDefaults.spinnerColors(),
|
||||
spinnerColors = DropdownDefaults.dropdownColors(),
|
||||
dialogMode = false,
|
||||
onSelectedIndexChange = ::fillPassword,
|
||||
)
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
package io.github.miuzarte.scrcpyforandroid.scaffolds
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import io.github.miuzarte.scrcpyforandroid.R
|
||||
import io.github.miuzarte.scrcpyforandroid.miuix.OverlaySpinnerPreference
|
||||
import io.github.miuzarte.scrcpyforandroid.miuix.SpinnerEntry
|
||||
import top.yukonga.miuix.kmp.basic.BasicComponentColors
|
||||
import top.yukonga.miuix.kmp.basic.BasicComponentDefaults
|
||||
import top.yukonga.miuix.kmp.basic.DropdownColors
|
||||
import top.yukonga.miuix.kmp.basic.DropdownDefaults
|
||||
import top.yukonga.miuix.kmp.basic.InfiniteProgressIndicator
|
||||
import top.yukonga.miuix.kmp.basic.SpinnerColors
|
||||
import top.yukonga.miuix.kmp.basic.SpinnerDefaults
|
||||
|
||||
/**
|
||||
* [OverlaySpinnerPreference] wrapper with fallback value display and loading state.
|
||||
@@ -34,7 +32,7 @@ fun OverlaySpinnerWithFallback(
|
||||
titleColor: BasicComponentColors = BasicComponentDefaults.titleColor(),
|
||||
summary: String? = null,
|
||||
summaryColor: BasicComponentColors = BasicComponentDefaults.summaryColor(),
|
||||
spinnerColors: SpinnerColors = SpinnerDefaults.spinnerColors(),
|
||||
spinnerColors: DropdownColors = DropdownDefaults.dropdownColors(),
|
||||
startAction: @Composable (() -> Unit)? = null,
|
||||
bottomAction: (@Composable () -> Unit)? = null,
|
||||
insideMargin: PaddingValues = BasicComponentDefaults.InsideMargin,
|
||||
|
||||
@@ -88,6 +88,10 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
|
||||
}
|
||||
|
||||
companion object {
|
||||
val LANGUAGE_TAG = Pair(
|
||||
stringPreferencesKey("language_tag"),
|
||||
"",
|
||||
)
|
||||
// Theme
|
||||
val THEME_BASE_INDEX = Pair(
|
||||
intPreferencesKey("theme_base_index"),
|
||||
@@ -121,10 +125,6 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
|
||||
booleanPreferencesKey("floating_bottom_bar_blur"),
|
||||
false,
|
||||
)
|
||||
val SMOOTH_CORNER = Pair(
|
||||
booleanPreferencesKey("smooth_corner"),
|
||||
false,
|
||||
)
|
||||
|
||||
// Scrcpy
|
||||
val LOW_LATENCY = Pair(
|
||||
@@ -302,6 +302,7 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
|
||||
@Parcelize
|
||||
data class Bundle(
|
||||
// Theme
|
||||
val languageTag: String,
|
||||
val themeBaseIndex: Int,
|
||||
val monet: Boolean,
|
||||
val monetSeedIndex: Int,
|
||||
@@ -310,7 +311,6 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
|
||||
val blur: Boolean,
|
||||
val floatingBottomBar: Boolean,
|
||||
val floatingBottomBarBlur: Boolean,
|
||||
val smoothCorner: Boolean,
|
||||
|
||||
// Scrcpy
|
||||
val lowLatency: Boolean,
|
||||
@@ -365,6 +365,7 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
|
||||
|
||||
private val bundleFields = arrayOf<BundleField<Bundle>>(
|
||||
// Theme
|
||||
bundleField(LANGUAGE_TAG) { it.languageTag },
|
||||
bundleField(THEME_BASE_INDEX) { it.themeBaseIndex },
|
||||
bundleField(MONET) { it.monet },
|
||||
bundleField(MONET_SEED_INDEX) { it.monetSeedIndex },
|
||||
@@ -373,7 +374,6 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
|
||||
bundleField(BLUR) { it.blur },
|
||||
bundleField(FLOATING_BOTTOM_BAR) { it.floatingBottomBar },
|
||||
bundleField(FLOATING_BOTTOM_BAR_BLUR) { it.floatingBottomBarBlur },
|
||||
bundleField(SMOOTH_CORNER) { it.smoothCorner },
|
||||
|
||||
// Scrcpy
|
||||
bundleField(LOW_LATENCY) { it.lowLatency },
|
||||
@@ -429,6 +429,7 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
|
||||
|
||||
private fun bundleFromPreferences(preferences: Preferences) = Bundle(
|
||||
// Theme
|
||||
languageTag = preferences.read(LANGUAGE_TAG),
|
||||
themeBaseIndex = preferences.read(THEME_BASE_INDEX),
|
||||
monet = preferences.read(MONET),
|
||||
monetSeedIndex = preferences.read(MONET_SEED_INDEX),
|
||||
@@ -437,7 +438,6 @@ class AppSettings(context: Context) : Settings(context, "AppSettings") {
|
||||
blur = preferences.read(BLUR),
|
||||
floatingBottomBar = preferences.read(FLOATING_BOTTOM_BAR),
|
||||
floatingBottomBarBlur = preferences.read(FLOATING_BOTTOM_BAR_BLUR),
|
||||
smoothCorner = preferences.read(SMOOTH_CORNER),
|
||||
|
||||
// Scrcpy
|
||||
lowLatency = preferences.read(LOW_LATENCY),
|
||||
|
||||
@@ -17,15 +17,15 @@ import androidx.compose.material.icons.rounded.Refresh
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import io.github.miuzarte.scrcpyforandroid.R
|
||||
import io.github.miuzarte.scrcpyforandroid.constants.UiSpacing
|
||||
import top.yukonga.miuix.kmp.basic.DropdownColors
|
||||
import top.yukonga.miuix.kmp.basic.DropdownDefaults
|
||||
import top.yukonga.miuix.kmp.basic.Icon
|
||||
import top.yukonga.miuix.kmp.basic.IconButton
|
||||
import top.yukonga.miuix.kmp.basic.SpinnerColors
|
||||
import top.yukonga.miuix.kmp.basic.SpinnerDefaults
|
||||
import top.yukonga.miuix.kmp.basic.Text
|
||||
import top.yukonga.miuix.kmp.icon.MiuixIcons
|
||||
import top.yukonga.miuix.kmp.icon.extended.Store
|
||||
@@ -51,7 +51,6 @@ fun AppListBottomSheet(
|
||||
onDismissRequest: () -> Unit,
|
||||
onRefresh: () -> Unit,
|
||||
) {
|
||||
val spinnerColors = SpinnerDefaults.spinnerColors()
|
||||
OverlayBottomSheet(
|
||||
show = show,
|
||||
title = title,
|
||||
@@ -98,7 +97,7 @@ fun AppListBottomSheet(
|
||||
items(items = entries, key = { it.key }) { entry ->
|
||||
AppListBottomSheetItem(
|
||||
entry = entry,
|
||||
spinnerColors = spinnerColors,
|
||||
spinnerColors = DropdownDefaults.dropdownColors(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -110,7 +109,7 @@ fun AppListBottomSheet(
|
||||
@Composable
|
||||
private fun AppListBottomSheetItem(
|
||||
entry: AppListEntry,
|
||||
spinnerColors: SpinnerColors,
|
||||
spinnerColors: DropdownColors,
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
|
||||
@@ -71,12 +71,12 @@ import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import top.yukonga.miuix.kmp.basic.Button
|
||||
import top.yukonga.miuix.kmp.basic.ButtonDefaults
|
||||
import top.yukonga.miuix.kmp.basic.DropdownDefaults
|
||||
import top.yukonga.miuix.kmp.basic.DropdownItem
|
||||
import top.yukonga.miuix.kmp.basic.Icon
|
||||
import top.yukonga.miuix.kmp.basic.ListPopupColumn
|
||||
import top.yukonga.miuix.kmp.basic.ListPopupDefaults
|
||||
import top.yukonga.miuix.kmp.basic.PopupPositionProvider
|
||||
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
|
||||
@@ -690,7 +690,7 @@ class VirtualButtonBar(
|
||||
val haptic = LocalHapticFeedback.current
|
||||
val spinnerItems = actions.map { action ->
|
||||
val title = stringResource(action.titleResId)
|
||||
SpinnerEntry(
|
||||
DropdownItem(
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = action.icon,
|
||||
@@ -719,7 +719,7 @@ class VirtualButtonBar(
|
||||
entryCount = spinnerItems.size,
|
||||
isSelected = false,
|
||||
index = index,
|
||||
spinnerColors = SpinnerDefaults.spinnerColors(),
|
||||
spinnerColors = DropdownDefaults.dropdownColors(),
|
||||
dialogMode = false,
|
||||
onSelectedIndexChange = { selectedIdx ->
|
||||
haptic.confirm()
|
||||
|
||||
@@ -246,6 +246,8 @@
|
||||
<string name="pref_summary_clear_logs_on_exit">双击返回退出应用时清除日志</string>
|
||||
<string name="pref_title_hide_log_box">隐藏设备页日志框</string>
|
||||
<string name="pref_summary_hide_log_box">隐藏设备页最下方的日志框</string>
|
||||
<string name="pref_title_language">语言</string>
|
||||
<string name="pref_summary_language">应用显示语言</string>
|
||||
|
||||
<!-- Terminal -->
|
||||
<string name="terminal_title">终端</string>
|
||||
@@ -551,4 +553,9 @@
|
||||
<string name="vm_mdns_updated">mDNS 发现新端口,已更新快速设备:%1$s:%2$s -> %1$s:%3$s</string>
|
||||
<string name="vm_quick_probe_success">ADB 快速探测连接成功:%1$s:%2$s</string>
|
||||
<string name="vm_device_switched_profile">当前连接设备已切换为配置:%1$s</string>
|
||||
|
||||
<string name="language_follow_system">跟随系统</string>
|
||||
<string name="language_english">英语</string>
|
||||
<string name="language_chinese">中文</string>
|
||||
|
||||
</resources>
|
||||
@@ -246,6 +246,8 @@
|
||||
<string name="pref_summary_clear_logs_on_exit">Clear logs when double-pressing back to exit the app</string>
|
||||
<string name="pref_title_hide_log_box">Hide device page log box</string>
|
||||
<string name="pref_summary_hide_log_box">Hide the log box at the bottom of the device page</string>
|
||||
<string name="pref_title_language">Language</string>
|
||||
<string name="pref_summary_language">App display language</string>
|
||||
|
||||
<!-- Terminal -->
|
||||
<string name="terminal_title">Terminal</string>
|
||||
@@ -551,4 +553,9 @@
|
||||
<string name="vm_mdns_updated">mDNS discovered new port, updated quick device: %1$s:%2$s -> %1$s:%3$s</string>
|
||||
<string name="vm_quick_probe_success">ADB quick probe connection succeeded: %1$s:%2$s</string>
|
||||
<string name="vm_device_switched_profile">Current connected device switched to profile: %1$s</string>
|
||||
|
||||
<string name="language_follow_system">Follow system</string>
|
||||
<string name="language_english">English</string>
|
||||
<string name="language_chinese">Chinese</string>
|
||||
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user