diff --git a/CHANGELOG.md b/CHANGELOG.md index e8acd99..e377696 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## 0.3.3 + +- 新增: 语言选择 +- 改进: zh-rCN 重命名至 zh 实现繁中回退简中 +- 依赖: miuix 同步至最新提交 + ## 0.3.2 - 修复: 部分设备 (ColorOS) 在拉起输入法后,返回事件会经由输入法最终被发往受控机 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 75d4fb7..544e6f7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -56,8 +56,8 @@ android { applicationId = "io.github.miuzarte.scrcpyforandroid" minSdk = 26 targetSdk = 37 - versionCode = 28 - versionName = "0.3.2" + versionCode = 29 + versionName = "0.3.3" externalNativeBuild { cmake { 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 f3aba1d..f1720f6 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/LockscreenPasswordActivity.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/LockscreenPasswordActivity.kt @@ -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, diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/MainActivity.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/MainActivity.kt index fd25e64..e2ca937 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/MainActivity.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/MainActivity.kt @@ -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) } } } diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/miuix/OverlaySpinnerPreference.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/miuix/OverlaySpinnerPreference.kt index aecc92c..50aa832 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/miuix/OverlaySpinnerPreference.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/miuix/OverlaySpinnerPreference.kt @@ -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)?, ) { diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/miuix/SpinnerItemImpl.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/miuix/SpinnerItemImpl.kt index b21bf6a..1275996 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/miuix/SpinnerItemImpl.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/miuix/SpinnerItemImpl.kt @@ -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, diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/AboutScreen.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/AboutScreen.kt index 9123664..426bf74 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/AboutScreen.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/AboutScreen.kt @@ -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), 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 d63b3ec..a842367 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 @@ -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( 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 1ab7618..41f3564 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 @@ -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), + ) } }, ) diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/MainScreen.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/MainScreen.kt index 2e586dd..b9e6358 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/MainScreen.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/MainScreen.kt @@ -725,7 +725,6 @@ fun MainScreen() { MiuixTheme( controller = themeController, - smoothRounding = asBundle.smoothCorner, ) { CompositionLocalProvider( LocalEnableBlur provides asBundle.blur, 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 8f558de..64901e2 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 @@ -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, diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/SettingsScreen.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/SettingsScreen.kt index b95d944..f2b3737 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/SettingsScreen.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/SettingsScreen.kt @@ -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), diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/StreamScreen.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/StreamScreen.kt index 0f68802..51c027d 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/StreamScreen.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/pages/StreamScreen.kt @@ -101,7 +101,6 @@ fun StreamScreen(activity: StreamActivity) { MiuixTheme( controller = themeController, - smoothRounding = asBundle.smoothCorner, ) { CompositionLocalProvider( LocalSnackbarController provides snackbarController, 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 6d86da2..e30586d 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 @@ -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) }, diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/password/PasswordPickerPopup.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/password/PasswordPickerPopup.kt index e85468d..943f755 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/password/PasswordPickerPopup.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/password/PasswordPickerPopup.kt @@ -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, ) diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/scaffolds/OverlaySpinnerWithFallback.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/scaffolds/OverlaySpinnerWithFallback.kt index 7369dc5..8e55185 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/scaffolds/OverlaySpinnerWithFallback.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/scaffolds/OverlaySpinnerWithFallback.kt @@ -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, diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/storage/AppSettings.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/storage/AppSettings.kt index 8582caf..99f571b 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/storage/AppSettings.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/storage/AppSettings.kt @@ -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>( // 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), diff --git a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/widgets/AppBottomSheets.kt b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/widgets/AppBottomSheets.kt index a201d73..ecd9e5b 100644 --- a/app/src/main/java/io/github/miuzarte/scrcpyforandroid/widgets/AppBottomSheets.kt +++ b/app/src/main/java/io/github/miuzarte/scrcpyforandroid/widgets/AppBottomSheets.kt @@ -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, 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 2b2fa77..4ceb6a2 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 @@ -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() diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh/strings.xml similarity index 99% rename from app/src/main/res/values-zh-rCN/strings.xml rename to app/src/main/res/values-zh/strings.xml index 69ad3f3..95b991f 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -246,6 +246,8 @@ 双击返回退出应用时清除日志 隐藏设备页日志框 隐藏设备页最下方的日志框 + 语言 + 应用显示语言 终端 @@ -551,4 +553,9 @@ mDNS 发现新端口,已更新快速设备:%1$s:%2$s -> %1$s:%3$s ADB 快速探测连接成功:%1$s:%2$s 当前连接设备已切换为配置:%1$s + + 跟随系统 + 英语 + 中文 + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e00ebf7..8ed3431 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -246,6 +246,8 @@ Clear logs when double-pressing back to exit the app Hide device page log box Hide the log box at the bottom of the device page + Language + App display language Terminal @@ -551,4 +553,9 @@ mDNS discovered new port, updated quick device: %1$s:%2$s -> %1$s:%3$s ADB quick probe connection succeeded: %1$s:%2$s Current connected device switched to profile: %1$s + + Follow system + English + Chinese + diff --git a/submodule/miuix b/submodule/miuix index 81ad71b..127d10c 160000 --- a/submodule/miuix +++ b/submodule/miuix @@ -1 +1 @@ -Subproject commit 81ad71b1c6e56d91313956df384bfd40bbe0f9ce +Subproject commit 127d10c6cb66da13889f55ec85b5abb60a27e38e