feat: a profile selector on top of config panel
合并多个 IP 到一个设备后不能特地为远程设备使用限制码率的配置了,外面再放一个
This commit is contained in:
@@ -136,11 +136,11 @@ class DeviceShortcuts(val devices: List<DeviceShortcut>): List<DeviceShortcut> b
|
||||
val updateById = id != null
|
||||
|
||||
val updatedAddresses = when {
|
||||
updateById -> {
|
||||
val h = host ?: old.host
|
||||
updateById && host != null -> {
|
||||
val p = port ?: old.port
|
||||
listOf("$h:$p")
|
||||
listOf("$host:$p")
|
||||
}
|
||||
updateById -> old.addresses
|
||||
|
||||
newPort != null -> {
|
||||
old.addresses.map { addr ->
|
||||
|
||||
@@ -32,6 +32,7 @@ import io.github.miuzarte.scrcpyforandroid.scaffolds.LazyColumn
|
||||
import io.github.miuzarte.scrcpyforandroid.scaffolds.SectionSmallTitle
|
||||
import io.github.miuzarte.scrcpyforandroid.scrcpy.ClientOptions
|
||||
import io.github.miuzarte.scrcpyforandroid.services.*
|
||||
import io.github.miuzarte.scrcpyforandroid.storage.Storage.scrcpyProfiles
|
||||
import io.github.miuzarte.scrcpyforandroid.ui.BlurredBar
|
||||
import io.github.miuzarte.scrcpyforandroid.ui.LocalEnableBlur
|
||||
import io.github.miuzarte.scrcpyforandroid.ui.contextClick
|
||||
@@ -202,6 +203,7 @@ internal fun DeviceTabPage(
|
||||
val connectedScrcpyProfileId by viewModel.connectedScrcpyProfileId.collectAsState()
|
||||
val connectedScrcpyBundle by viewModel.connectedScrcpyBundle.collectAsState()
|
||||
val connectedScrcpyProfileName by viewModel.connectedScrcpyProfileName.collectAsState()
|
||||
val scrcpyProfilesState by scrcpyProfiles.state.collectAsState()
|
||||
val canShowPreviewControls by viewModel.canShowPreviewControls.collectAsState()
|
||||
val virtualButtonLayout by viewModel.virtualButtonLayout.collectAsState()
|
||||
|
||||
@@ -580,6 +582,45 @@ internal fun DeviceTabPage(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ProfilesTabRow() {
|
||||
val profileTabs = remember(scrcpyProfilesState.profiles) {
|
||||
scrcpyProfilesState.profiles.map { it.name }
|
||||
}
|
||||
val profileIds = remember(scrcpyProfilesState.profiles) {
|
||||
scrcpyProfilesState.profiles.map { it.id }
|
||||
}
|
||||
val selectedProfileIndex = remember(connectedScrcpyProfileId, profileIds) {
|
||||
profileIds.indexOf(connectedScrcpyProfileId).coerceAtLeast(0)
|
||||
}
|
||||
val textGlobal = stringResource(R.string.text_global)
|
||||
|
||||
TabRow(
|
||||
tabs = profileTabs,
|
||||
selectedTabIndex = selectedProfileIndex,
|
||||
onTabSelected = { index ->
|
||||
val newProfileId = profileIds.getOrNull(index) ?: return@TabRow
|
||||
if (newProfileId == connectedScrcpyProfileId) return@TabRow
|
||||
haptic.contextClick()
|
||||
val device = currentTarget?.let { ct ->
|
||||
savedShortcuts.firstOrNull { it.matchesAddress(ct) }
|
||||
}
|
||||
if (device != null) {
|
||||
viewModel.updateShortcut(id = device.id, scrcpyProfileId = newProfileId)
|
||||
}
|
||||
val profileName = profileTabs.getOrElse(index) { textGlobal }
|
||||
AppRuntime.snackbar(R.string.device_switched_profile, device?.name ?: "", profileName)
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(bottom = UiSpacing.Medium),
|
||||
minWidth = 96.dp,
|
||||
maxWidth = 192.dp,
|
||||
height = 48.dp,
|
||||
itemSpacing = UiSpacing.Medium,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
val pageContentPadding = contentPadding
|
||||
val pageBottomInnerPadding = bottomInnerPadding
|
||||
|
||||
@@ -615,12 +656,14 @@ internal fun DeviceTabPage(
|
||||
}
|
||||
item { VirtualButtonsSection() }
|
||||
item {
|
||||
if (sessionInfo == null) ProfilesTabRow()
|
||||
if (useTwoPaneConfigPanel) ScrcpyConfigSectionForTwoPane()
|
||||
else ScrcpyConfigSection()
|
||||
}
|
||||
} else {
|
||||
item {
|
||||
SectionSmallTitle(stringResource(R.string.device_section_scrcpy))
|
||||
if (sessionInfo == null) ProfilesTabRow()
|
||||
if (useTwoPaneConfigPanel) ScrcpyConfigSectionForTwoPane()
|
||||
else ScrcpyConfigSection()
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ internal class DeviceTabViewModel(
|
||||
) { session, shortcuts ->
|
||||
val target = session.currentTarget
|
||||
if (session.isConnected && target != null)
|
||||
shortcuts.get(target.host, target.port)?.scrcpyProfileId
|
||||
shortcuts.firstOrNull { it.matchesAddress(target) }?.scrcpyProfileId
|
||||
?: session.connectedScrcpyProfileId
|
||||
else
|
||||
session.connectedScrcpyProfileId
|
||||
@@ -907,7 +907,7 @@ internal class DeviceTabViewModel(
|
||||
Triple(connected, target, shortcuts)
|
||||
}.collect { (connected, target, shortcuts) ->
|
||||
if (!connected || target == null) return@collect
|
||||
val boundProfileId = shortcuts.get(target.host, target.port)
|
||||
val boundProfileId = shortcuts.firstOrNull { it.matchesAddress(target) }
|
||||
?.scrcpyProfileId ?: ScrcpyOptions.GLOBAL_PROFILE_ID
|
||||
if (boundProfileId != connectionState.value.adbSession.connectedScrcpyProfileId) {
|
||||
connectionController.syncConnectedScrcpyProfileId(boundProfileId)
|
||||
|
||||
@@ -48,6 +48,7 @@ internal fun RecordPreferencesScreen(
|
||||
profileId: String,
|
||||
scrcpy: Scrcpy,
|
||||
) {
|
||||
val haptic = LocalHapticFeedback.current
|
||||
val navigator = LocalRootNavigator.current
|
||||
val blurBackdrop = rememberBlurBackdrop(LocalEnableBlur.current)
|
||||
val blurActive = blurBackdrop != null
|
||||
@@ -63,7 +64,12 @@ internal fun RecordPreferencesScreen(
|
||||
if (blurActive) Color.Transparent
|
||||
else colorScheme.surface,
|
||||
navigationIcon = {
|
||||
IconButton(onClick = navigator.pop) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
haptic.contextClick()
|
||||
navigator.pop()
|
||||
},
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Rounded.ArrowBack,
|
||||
contentDescription = stringResource(R.string.cd_back),
|
||||
|
||||
@@ -63,6 +63,7 @@ internal fun ScrcpyAllOptionsScreen(
|
||||
scrollBehavior: ScrollBehavior,
|
||||
scrcpy: Scrcpy,
|
||||
) {
|
||||
val haptic = LocalHapticFeedback.current
|
||||
val navigator = LocalRootNavigator.current
|
||||
val blurBackdrop = rememberBlurBackdrop(LocalEnableBlur.current)
|
||||
val blurActive = blurBackdrop != null
|
||||
@@ -148,11 +149,11 @@ internal fun ScrcpyAllOptionsScreen(
|
||||
suspend fun bindCurrentConnectedDevice(profileId: String) {
|
||||
val target = AppRuntime.currentConnectionTarget ?: return
|
||||
val shortcuts = DeviceShortcuts.unmarshalFrom(qdBundleShared.quickDevicesList)
|
||||
val updated = shortcuts.update(
|
||||
host = target.host,
|
||||
port = target.port,
|
||||
val device = shortcuts.firstOrNull { it.matchesAddress(target) }
|
||||
val updated = if (device != null) shortcuts.update(
|
||||
id = device.id,
|
||||
scrcpyProfileId = profileId,
|
||||
)
|
||||
) else shortcuts
|
||||
if (updated != shortcuts) {
|
||||
quickDevices.updateBundle { bundle ->
|
||||
bundle.copy(quickDevicesList = updated.marshalToString())
|
||||
@@ -169,7 +170,12 @@ internal fun ScrcpyAllOptionsScreen(
|
||||
if (blurActive) Color.Transparent
|
||||
else colorScheme.surface,
|
||||
navigationIcon = {
|
||||
IconButton(onClick = navigator.pop) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
haptic.contextClick()
|
||||
navigator.pop()
|
||||
},
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Rounded.ArrowBack,
|
||||
contentDescription = stringResource(R.string.cd_back),
|
||||
@@ -205,6 +211,7 @@ internal fun ScrcpyAllOptionsScreen(
|
||||
val nextProfileId = profileIds.getOrNull(index)
|
||||
?: return@TabRow
|
||||
if (nextProfileId == selectedProfileId) return@TabRow
|
||||
haptic.contextClick()
|
||||
scope.launch {
|
||||
saveBundleForProfile(selectedProfileId, soBundleState.value)
|
||||
bindCurrentConnectedDevice(nextProfileId)
|
||||
@@ -220,8 +227,8 @@ internal fun ScrcpyAllOptionsScreen(
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(bottom = UiSpacing.Medium)
|
||||
.padding(horizontal = UiSpacing.Medium),
|
||||
.padding(bottom = UiSpacing.PageHorizontal)
|
||||
.padding(horizontal = UiSpacing.PageVertical),
|
||||
minWidth = 96.dp,
|
||||
maxWidth = 192.dp,
|
||||
height = 48.dp,
|
||||
|
||||
Reference in New Issue
Block a user