mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-14 18:26:11 -04:00
feat(settings): Show pro indicators on gated settings rows
Unifies the three inconsistent pro-gating UI patterns (text button header, star-replaces-switch, silent gates) into a single inline star badge next to the title, driven by a new proLocked parameter on SettingsBaseItem that propagates to all wrappers. Switches stay visible so users can see state and disable ex-pro toggles. Hides the Noise Control visibility buttons when non-pro and surfaces a dedicated cycle customization row with the indicator. Deletes two duplicate local ProGated composables.
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
package eu.darken.capod.common.settings
|
||||
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.twotone.Stars
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.darken.capod.R
|
||||
import eu.darken.capod.common.compose.Preview2
|
||||
import eu.darken.capod.common.compose.PreviewWrapper
|
||||
|
||||
@Composable
|
||||
fun ProBadge(modifier: Modifier = Modifier) {
|
||||
Icon(
|
||||
imageVector = Icons.TwoTone.Stars,
|
||||
contentDescription = stringResource(R.string.overview_anc_mode_requires_upgrade),
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
modifier = modifier.size(16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
@Preview2
|
||||
@Composable
|
||||
private fun ProBadgePreview() = PreviewWrapper {
|
||||
ProBadge()
|
||||
}
|
||||
@@ -4,9 +4,11 @@ import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
@@ -36,6 +38,7 @@ fun SettingsBaseItem(
|
||||
iconSize: Dp = 24.dp,
|
||||
subtitle: String? = null,
|
||||
enabled: Boolean = true,
|
||||
proLocked: Boolean = false,
|
||||
onLongClick: (() -> Unit)? = null,
|
||||
trailingContent: @Composable (() -> Unit)? = null,
|
||||
) {
|
||||
@@ -87,12 +90,18 @@ fun SettingsBaseItem(
|
||||
.weight(1f)
|
||||
.padding(start = if (hasIcon) 16.dp else 0.dp)
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = contentAlpha)
|
||||
)
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = contentAlpha)
|
||||
)
|
||||
if (proLocked) {
|
||||
Spacer(modifier = Modifier.width(6.dp))
|
||||
ProBadge()
|
||||
}
|
||||
}
|
||||
if (subtitle != null) {
|
||||
Text(
|
||||
text = subtitle,
|
||||
|
||||
@@ -38,6 +38,7 @@ fun <T> SettingsListPreferenceItem(
|
||||
modifier: Modifier = Modifier,
|
||||
subtitle: String? = null,
|
||||
enabled: Boolean = true,
|
||||
proLocked: Boolean = false,
|
||||
) {
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
|
||||
@@ -48,6 +49,7 @@ fun <T> SettingsListPreferenceItem(
|
||||
onClick = { if (enabled) showDialog = true },
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
proLocked = proLocked,
|
||||
)
|
||||
|
||||
if (showDialog) {
|
||||
|
||||
@@ -17,6 +17,7 @@ fun SettingsPreferenceItem(
|
||||
subtitle: String? = null,
|
||||
value: String? = null,
|
||||
enabled: Boolean = true,
|
||||
proLocked: Boolean = false,
|
||||
) {
|
||||
val contentAlpha = if (enabled) 1f else 0.5f
|
||||
|
||||
@@ -27,6 +28,7 @@ fun SettingsPreferenceItem(
|
||||
modifier = modifier,
|
||||
subtitle = subtitle,
|
||||
enabled = enabled,
|
||||
proLocked = proLocked,
|
||||
trailingContent = if (value != null) {
|
||||
{
|
||||
Text(
|
||||
|
||||
@@ -20,6 +20,7 @@ fun SettingsSwitchItem(
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
proLocked: Boolean = false,
|
||||
) {
|
||||
SettingsBaseItem(
|
||||
icon = icon,
|
||||
@@ -28,6 +29,7 @@ fun SettingsSwitchItem(
|
||||
modifier = modifier,
|
||||
subtitle = subtitle,
|
||||
enabled = enabled,
|
||||
proLocked = proLocked,
|
||||
trailingContent = {
|
||||
Switch(
|
||||
checked = checked,
|
||||
|
||||
@@ -24,10 +24,10 @@ import androidx.compose.material.icons.twotone.Edit
|
||||
import androidx.compose.material.icons.twotone.GraphicEq
|
||||
import androidx.compose.material.icons.twotone.Headphones
|
||||
import androidx.compose.material.icons.twotone.Hearing
|
||||
import androidx.compose.material.icons.twotone.Loop
|
||||
import androidx.compose.material.icons.twotone.Mic
|
||||
import androidx.compose.material.icons.twotone.Nightlight
|
||||
import androidx.compose.material.icons.twotone.Speed
|
||||
import androidx.compose.material.icons.twotone.Stars
|
||||
import androidx.compose.material.icons.twotone.Swipe
|
||||
import androidx.compose.material.icons.twotone.Timer
|
||||
import androidx.compose.material.icons.twotone.TouchApp
|
||||
@@ -147,6 +147,7 @@ fun DeviceSettingsScreenHost(
|
||||
onDeviceNameChange = { vm.setDeviceName(it) },
|
||||
onStemActionsClick = { vm.navToStemConfig() },
|
||||
onForceConnect = { vm.forceConnect() },
|
||||
onUpgrade = { vm.launchUpgrade() },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -175,6 +176,7 @@ fun DeviceSettingsScreen(
|
||||
onDeviceNameChange: (String) -> Unit = {},
|
||||
onStemActionsClick: () -> Unit = {},
|
||||
onForceConnect: () -> Unit = {},
|
||||
onUpgrade: () -> Unit = {},
|
||||
) {
|
||||
val device = state.device
|
||||
val features = device?.model?.features
|
||||
@@ -272,13 +274,25 @@ fun DeviceSettingsScreen(
|
||||
pendingMode = device.pendingAncMode,
|
||||
supportedModes = ancMode.supported,
|
||||
onModeSelected = onAncModeChange,
|
||||
cycleMask = cycleMask,
|
||||
cycleMask = if (isPro) cycleMask else null,
|
||||
onCycleMaskChange = onListeningModeCycleChange,
|
||||
onAllowOffChange = onAllowOffOptionChange,
|
||||
enabled = enabled,
|
||||
)
|
||||
}
|
||||
|
||||
if (!isPro && features.hasListeningModeCycle) {
|
||||
item("noise_control_cycle_pro") {
|
||||
SettingsBaseItem(
|
||||
icon = Icons.TwoTone.Loop,
|
||||
title = stringResource(R.string.device_settings_listening_mode_cycle_label),
|
||||
subtitle = stringResource(R.string.device_settings_listening_mode_cycle_description),
|
||||
onClick = onUpgrade,
|
||||
proLocked = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val convAwareness = device.conversationalAwareness
|
||||
if (features.hasConversationAwareness && convAwareness != null) {
|
||||
item("conversation_awareness") {
|
||||
@@ -466,6 +480,7 @@ fun DeviceSettingsScreen(
|
||||
subtitle = stringResource(R.string.stem_actions_nav_description),
|
||||
onClick = onStemActionsClick,
|
||||
enabled = enabled,
|
||||
proLocked = !isPro,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -494,14 +509,14 @@ fun DeviceSettingsScreen(
|
||||
val sleepDet = device.sleepDetection
|
||||
?: AapSetting.SleepDetection(enabled = true)
|
||||
item("sleep_detection") {
|
||||
ProGatedSwitchItem(
|
||||
SettingsSwitchItem(
|
||||
icon = Icons.TwoTone.Nightlight,
|
||||
title = stringResource(R.string.device_settings_sleep_detection_label),
|
||||
subtitle = stringResource(R.string.device_settings_sleep_detection_description),
|
||||
checked = sleepDet.enabled,
|
||||
onCheckedChange = onSleepDetectionChange,
|
||||
enabled = enabled,
|
||||
isPro = isPro,
|
||||
proLocked = !isPro,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -996,44 +1011,6 @@ private fun ConnectedDevicesList(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ProGatedSwitchItem(
|
||||
icon: ImageVector,
|
||||
title: String,
|
||||
subtitle: String?,
|
||||
checked: Boolean,
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
enabled: Boolean,
|
||||
isPro: Boolean,
|
||||
) {
|
||||
if (isPro) {
|
||||
SettingsSwitchItem(
|
||||
icon = icon,
|
||||
title = title,
|
||||
subtitle = subtitle,
|
||||
checked = checked,
|
||||
onCheckedChange = onCheckedChange,
|
||||
enabled = enabled,
|
||||
)
|
||||
} else {
|
||||
SettingsBaseItem(
|
||||
icon = icon,
|
||||
title = title,
|
||||
subtitle = subtitle,
|
||||
onClick = { onCheckedChange(!checked) },
|
||||
enabled = enabled,
|
||||
trailingContent = {
|
||||
Icon(
|
||||
imageVector = Icons.TwoTone.Stars,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.padding(start = 16.dp),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RenameDialog(
|
||||
currentName: String,
|
||||
@@ -1193,52 +1170,64 @@ private fun AapSetting.AncMode.Value.label(): String = when (this) {
|
||||
AapSetting.AncMode.Value.ADAPTIVE -> stringResource(R.string.device_settings_listening_mode_cycle_adaptive)
|
||||
}
|
||||
|
||||
@Preview2
|
||||
@Composable
|
||||
private fun DeviceSettingsFullPreview() = PreviewWrapper {
|
||||
DeviceSettingsScreen(
|
||||
state = DeviceSettingsViewModel.State(
|
||||
device = PodDevice(
|
||||
profileId = "preview",
|
||||
label = "My AirPods Pro",
|
||||
ble = MockPodDataProvider.airPodsProWithKeys(),
|
||||
aap = AapPodState(
|
||||
connectionState = AapPodState.ConnectionState.READY,
|
||||
deviceInfo = AapDeviceInfo(
|
||||
name = "AirPods Pro",
|
||||
modelNumber = "A2699",
|
||||
manufacturer = "Apple Inc.",
|
||||
serialNumber = "W5J7KV0N04",
|
||||
firmwareVersion = "7A305",
|
||||
),
|
||||
settings = mapOf(
|
||||
AapSetting.AncMode::class to AapSetting.AncMode(
|
||||
current = AapSetting.AncMode.Value.ADAPTIVE,
|
||||
supported = listOf(
|
||||
AapSetting.AncMode.Value.OFF,
|
||||
AapSetting.AncMode.Value.ON,
|
||||
AapSetting.AncMode.Value.TRANSPARENCY,
|
||||
AapSetting.AncMode.Value.ADAPTIVE,
|
||||
),
|
||||
),
|
||||
AapSetting.ConversationalAwareness::class to AapSetting.ConversationalAwareness(enabled = true),
|
||||
AapSetting.NcWithOneAirPod::class to AapSetting.NcWithOneAirPod(enabled = true),
|
||||
AapSetting.PersonalizedVolume::class to AapSetting.PersonalizedVolume(enabled = false),
|
||||
AapSetting.ToneVolume::class to AapSetting.ToneVolume(level = 75),
|
||||
AapSetting.AdaptiveAudioNoise::class to AapSetting.AdaptiveAudioNoise(level = 50),
|
||||
AapSetting.PressSpeed::class to AapSetting.PressSpeed(value = AapSetting.PressSpeed.Value.DEFAULT),
|
||||
AapSetting.PressHoldDuration::class to AapSetting.PressHoldDuration(value = AapSetting.PressHoldDuration.Value.DEFAULT),
|
||||
AapSetting.VolumeSwipe::class to AapSetting.VolumeSwipe(enabled = true),
|
||||
AapSetting.VolumeSwipeLength::class to AapSetting.VolumeSwipeLength(value = AapSetting.VolumeSwipeLength.Value.DEFAULT),
|
||||
AapSetting.EndCallMuteMic::class to AapSetting.EndCallMuteMic(
|
||||
muteMic = AapSetting.EndCallMuteMic.MuteMicMode.DOUBLE_PRESS,
|
||||
endCall = AapSetting.EndCallMuteMic.EndCallMode.SINGLE_PRESS,
|
||||
),
|
||||
private fun previewFullState(isPro: Boolean) = DeviceSettingsViewModel.State(
|
||||
device = PodDevice(
|
||||
profileId = "preview",
|
||||
label = "My AirPods Pro",
|
||||
ble = MockPodDataProvider.airPodsProWithKeys(),
|
||||
aap = AapPodState(
|
||||
connectionState = AapPodState.ConnectionState.READY,
|
||||
deviceInfo = AapDeviceInfo(
|
||||
name = "AirPods Pro",
|
||||
modelNumber = "A2699",
|
||||
manufacturer = "Apple Inc.",
|
||||
serialNumber = "W5J7KV0N04",
|
||||
firmwareVersion = "7A305",
|
||||
),
|
||||
settings = mapOf(
|
||||
AapSetting.AncMode::class to AapSetting.AncMode(
|
||||
current = AapSetting.AncMode.Value.ADAPTIVE,
|
||||
supported = listOf(
|
||||
AapSetting.AncMode.Value.OFF,
|
||||
AapSetting.AncMode.Value.ON,
|
||||
AapSetting.AncMode.Value.TRANSPARENCY,
|
||||
AapSetting.AncMode.Value.ADAPTIVE,
|
||||
),
|
||||
),
|
||||
AapSetting.ConversationalAwareness::class to AapSetting.ConversationalAwareness(enabled = true),
|
||||
AapSetting.NcWithOneAirPod::class to AapSetting.NcWithOneAirPod(enabled = true),
|
||||
AapSetting.PersonalizedVolume::class to AapSetting.PersonalizedVolume(enabled = false),
|
||||
AapSetting.ToneVolume::class to AapSetting.ToneVolume(level = 75),
|
||||
AapSetting.AdaptiveAudioNoise::class to AapSetting.AdaptiveAudioNoise(level = 50),
|
||||
AapSetting.PressSpeed::class to AapSetting.PressSpeed(value = AapSetting.PressSpeed.Value.DEFAULT),
|
||||
AapSetting.PressHoldDuration::class to AapSetting.PressHoldDuration(value = AapSetting.PressHoldDuration.Value.DEFAULT),
|
||||
AapSetting.VolumeSwipe::class to AapSetting.VolumeSwipe(enabled = true),
|
||||
AapSetting.VolumeSwipeLength::class to AapSetting.VolumeSwipeLength(value = AapSetting.VolumeSwipeLength.Value.DEFAULT),
|
||||
AapSetting.EndCallMuteMic::class to AapSetting.EndCallMuteMic(
|
||||
muteMic = AapSetting.EndCallMuteMic.MuteMicMode.DOUBLE_PRESS,
|
||||
endCall = AapSetting.EndCallMuteMic.EndCallMode.SINGLE_PRESS,
|
||||
),
|
||||
),
|
||||
now = MOCK_NOW,
|
||||
),
|
||||
),
|
||||
now = MOCK_NOW,
|
||||
isPro = isPro,
|
||||
)
|
||||
|
||||
@Preview2
|
||||
@Composable
|
||||
private fun DeviceSettingsFullProPreview() = PreviewWrapper {
|
||||
DeviceSettingsScreen(
|
||||
state = previewFullState(isPro = true),
|
||||
onNavigateUp = {},
|
||||
)
|
||||
}
|
||||
|
||||
@Preview2
|
||||
@Composable
|
||||
private fun DeviceSettingsFullNonProPreview() = PreviewWrapper {
|
||||
DeviceSettingsScreen(
|
||||
state = previewFullState(isPro = false),
|
||||
onNavigateUp = {},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -220,6 +220,10 @@ class DeviceSettingsViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun launchUpgrade() {
|
||||
navTo(Nav.Main.Upgrade)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = logTag("DeviceSettings", "VM")
|
||||
}
|
||||
|
||||
+74
-49
@@ -3,7 +3,6 @@ package eu.darken.capod.main.ui.settings.general
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@@ -148,43 +147,47 @@ fun GeneralSettingsScreen(
|
||||
)
|
||||
}
|
||||
item {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
SettingsCategoryHeader(text = stringResource(R.string.settings_category_appearance_label))
|
||||
if (!state.isPro) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
TextButton(
|
||||
onClick = onUpgrade,
|
||||
modifier = Modifier.padding(end = 4.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.common_feature_requires_pro_msg),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
SettingsCategoryHeader(text = stringResource(R.string.settings_category_appearance_label))
|
||||
}
|
||||
item {
|
||||
if (state.isPro) {
|
||||
SettingsListPreferenceItem(
|
||||
icon = Icons.TwoTone.DarkMode,
|
||||
title = stringResource(R.string.ui_theme_mode_label),
|
||||
entries = ThemeMode.entries,
|
||||
selectedEntry = state.themeState.mode,
|
||||
onEntrySelected = onThemeModeSelected,
|
||||
entryLabel = { stringResource(it.labelRes) },
|
||||
)
|
||||
} else {
|
||||
SettingsBaseItem(
|
||||
icon = Icons.TwoTone.DarkMode,
|
||||
title = stringResource(R.string.ui_theme_mode_label),
|
||||
subtitle = stringResource(state.themeState.mode.labelRes),
|
||||
onClick = onUpgrade,
|
||||
proLocked = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
item {
|
||||
SettingsListPreferenceItem(
|
||||
icon = Icons.TwoTone.DarkMode,
|
||||
title = stringResource(R.string.ui_theme_mode_label),
|
||||
entries = ThemeMode.entries,
|
||||
selectedEntry = state.themeState.mode,
|
||||
onEntrySelected = onThemeModeSelected,
|
||||
entryLabel = { stringResource(it.labelRes) },
|
||||
enabled = state.isPro,
|
||||
)
|
||||
}
|
||||
item {
|
||||
SettingsListPreferenceItem(
|
||||
icon = Icons.TwoTone.Contrast,
|
||||
title = stringResource(R.string.ui_theme_style_label),
|
||||
entries = ThemeStyle.entries,
|
||||
selectedEntry = state.themeState.style,
|
||||
onEntrySelected = onThemeStyleSelected,
|
||||
entryLabel = { stringResource(it.labelRes) },
|
||||
enabled = state.isPro,
|
||||
)
|
||||
if (state.isPro) {
|
||||
SettingsListPreferenceItem(
|
||||
icon = Icons.TwoTone.Contrast,
|
||||
title = stringResource(R.string.ui_theme_style_label),
|
||||
entries = ThemeStyle.entries,
|
||||
selectedEntry = state.themeState.style,
|
||||
onEntrySelected = onThemeStyleSelected,
|
||||
entryLabel = { stringResource(it.labelRes) },
|
||||
)
|
||||
} else {
|
||||
SettingsBaseItem(
|
||||
icon = Icons.TwoTone.Contrast,
|
||||
title = stringResource(R.string.ui_theme_style_label),
|
||||
subtitle = stringResource(state.themeState.style.labelRes),
|
||||
onClick = onUpgrade,
|
||||
proLocked = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
item {
|
||||
SettingsBaseItem(
|
||||
@@ -195,8 +198,11 @@ fun GeneralSettingsScreen(
|
||||
stringResource(state.themeState.color.labelRes)
|
||||
},
|
||||
icon = Icons.TwoTone.Palette,
|
||||
onClick = { showColorDialog = true },
|
||||
enabled = state.isPro && !isMaterialYouActive,
|
||||
onClick = {
|
||||
if (!state.isPro) onUpgrade() else showColorDialog = true
|
||||
},
|
||||
enabled = !isMaterialYouActive,
|
||||
proLocked = !state.isPro && !isMaterialYouActive,
|
||||
)
|
||||
}
|
||||
item {
|
||||
@@ -333,21 +339,40 @@ fun GeneralSettingsScreen(
|
||||
}
|
||||
}
|
||||
|
||||
private fun previewGeneralState(isPro: Boolean) = GeneralSettingsViewModel.State(
|
||||
isPro = isPro,
|
||||
monitorMode = MonitorMode.AUTOMATIC,
|
||||
scannerMode = ScannerMode.BALANCED,
|
||||
showConnectedNotification = true,
|
||||
keepNotificationAfterDisconnect = false,
|
||||
isOffloadedFilteringDisabled = false,
|
||||
isOffloadedBatchingDisabled = false,
|
||||
useIndirectScanResultCallback = false,
|
||||
themeState = ThemeState(),
|
||||
)
|
||||
|
||||
@Preview2
|
||||
@Composable
|
||||
private fun GeneralSettingsScreenPreview() = PreviewWrapper {
|
||||
private fun GeneralSettingsScreenProPreview() = PreviewWrapper {
|
||||
GeneralSettingsScreen(
|
||||
state = GeneralSettingsViewModel.State(
|
||||
isPro = true,
|
||||
monitorMode = MonitorMode.AUTOMATIC,
|
||||
scannerMode = ScannerMode.BALANCED,
|
||||
showConnectedNotification = true,
|
||||
keepNotificationAfterDisconnect = false,
|
||||
isOffloadedFilteringDisabled = false,
|
||||
isOffloadedBatchingDisabled = false,
|
||||
useIndirectScanResultCallback = false,
|
||||
themeState = ThemeState(),
|
||||
),
|
||||
state = previewGeneralState(isPro = true),
|
||||
onNavigateUp = {},
|
||||
onMonitorModeSelected = {},
|
||||
onScannerModeSelected = {},
|
||||
onShowConnectedNotificationChanged = {},
|
||||
onKeepNotificationAfterDisconnectChanged = {},
|
||||
onDebugSettings = {},
|
||||
onOffloadedFilteringDisabledChanged = {},
|
||||
onOffloadedBatchingDisabledChanged = {},
|
||||
onUseIndirectScanResultCallbackChanged = {},
|
||||
)
|
||||
}
|
||||
|
||||
@Preview2
|
||||
@Composable
|
||||
private fun GeneralSettingsScreenNonProPreview() = PreviewWrapper {
|
||||
GeneralSettingsScreen(
|
||||
state = previewGeneralState(isPro = false),
|
||||
onNavigateUp = {},
|
||||
onMonitorModeSelected = {},
|
||||
onScannerModeSelected = {},
|
||||
|
||||
@@ -15,8 +15,6 @@ import androidx.compose.material.icons.automirrored.twotone.Message
|
||||
import androidx.compose.material.icons.twotone.PauseCircle
|
||||
import androidx.compose.material.icons.twotone.PlayCircle
|
||||
import androidx.compose.material.icons.twotone.QuestionMark
|
||||
import androidx.compose.material.icons.twotone.Stars
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.twotone.Workspaces
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Icon
|
||||
@@ -47,6 +45,7 @@ import eu.darken.capod.common.error.ErrorEventHandler
|
||||
import eu.darken.capod.common.navigation.NavigationEventHandler
|
||||
import eu.darken.capod.common.settings.SettingsBaseItem
|
||||
import eu.darken.capod.common.settings.SettingsCategoryHeader
|
||||
import eu.darken.capod.common.settings.SettingsSwitchItem
|
||||
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
|
||||
|
||||
@Composable
|
||||
@@ -122,25 +121,23 @@ fun ReactionSettingsScreen(
|
||||
)
|
||||
}
|
||||
item {
|
||||
SettingsBaseItem(
|
||||
SettingsSwitchItem(
|
||||
icon = Icons.TwoTone.PlayCircle,
|
||||
title = stringResource(R.string.settings_autopplay_label),
|
||||
subtitle = stringResource(R.string.settings_autoplay_description),
|
||||
icon = Icons.TwoTone.PlayCircle,
|
||||
onClick = { onAutoPlayChanged(!state.autoPlay) },
|
||||
trailingContent = {
|
||||
ProGatedToggle(isPro = state.isPro, checked = state.autoPlay, onCheckedChange = onAutoPlayChanged)
|
||||
},
|
||||
checked = state.autoPlay,
|
||||
onCheckedChange = onAutoPlayChanged,
|
||||
proLocked = !state.isPro,
|
||||
)
|
||||
}
|
||||
item {
|
||||
SettingsBaseItem(
|
||||
SettingsSwitchItem(
|
||||
icon = Icons.TwoTone.PauseCircle,
|
||||
title = stringResource(R.string.settings_autopause_label),
|
||||
subtitle = stringResource(R.string.settings_autopause_description),
|
||||
icon = Icons.TwoTone.PauseCircle,
|
||||
onClick = { onAutoPauseChanged(!state.autoPause) },
|
||||
trailingContent = {
|
||||
ProGatedToggle(isPro = state.isPro, checked = state.autoPause, onCheckedChange = onAutoPauseChanged)
|
||||
},
|
||||
checked = state.autoPause,
|
||||
onCheckedChange = onAutoPauseChanged,
|
||||
proLocked = !state.isPro,
|
||||
)
|
||||
}
|
||||
item {
|
||||
@@ -156,14 +153,13 @@ fun ReactionSettingsScreen(
|
||||
SettingsCategoryHeader(text = stringResource(R.string.settings_autoconnect_label))
|
||||
}
|
||||
item {
|
||||
SettingsBaseItem(
|
||||
SettingsSwitchItem(
|
||||
icon = Icons.TwoTone.BluetoothConnected,
|
||||
title = stringResource(R.string.settings_autoconnect_label),
|
||||
subtitle = stringResource(R.string.settings_autoconnect_description),
|
||||
icon = Icons.TwoTone.BluetoothConnected,
|
||||
onClick = { onAutoConnectChanged(!state.autoConnect) },
|
||||
trailingContent = {
|
||||
ProGatedToggle(isPro = state.isPro, checked = state.autoConnect, onCheckedChange = onAutoConnectChanged)
|
||||
},
|
||||
checked = state.autoConnect,
|
||||
onCheckedChange = onAutoConnectChanged,
|
||||
proLocked = !state.isPro,
|
||||
)
|
||||
}
|
||||
item {
|
||||
@@ -179,25 +175,23 @@ fun ReactionSettingsScreen(
|
||||
SettingsCategoryHeader(text = stringResource(R.string.settings_category_other_label))
|
||||
}
|
||||
item {
|
||||
SettingsBaseItem(
|
||||
SettingsSwitchItem(
|
||||
icon = Icons.AutoMirrored.TwoTone.Message,
|
||||
title = stringResource(R.string.settings_popup_caseopen_label),
|
||||
subtitle = stringResource(R.string.settings_popup_caseopen_description),
|
||||
icon = Icons.AutoMirrored.TwoTone.Message,
|
||||
onClick = { onShowPopUpOnCaseOpenChanged(!state.showPopUpOnCaseOpen) },
|
||||
trailingContent = {
|
||||
ProGatedToggle(isPro = state.isPro, checked = state.showPopUpOnCaseOpen, onCheckedChange = onShowPopUpOnCaseOpenChanged)
|
||||
},
|
||||
checked = state.showPopUpOnCaseOpen,
|
||||
onCheckedChange = onShowPopUpOnCaseOpenChanged,
|
||||
proLocked = !state.isPro,
|
||||
)
|
||||
}
|
||||
item {
|
||||
SettingsBaseItem(
|
||||
SettingsSwitchItem(
|
||||
icon = Icons.AutoMirrored.TwoTone.Message,
|
||||
title = stringResource(R.string.settings_popup_connected_label),
|
||||
subtitle = stringResource(R.string.settings_popup_connected_description),
|
||||
icon = Icons.AutoMirrored.TwoTone.Message,
|
||||
onClick = { onShowPopUpOnConnectionChanged(!state.showPopUpOnConnection) },
|
||||
trailingContent = {
|
||||
ProGatedToggle(isPro = state.isPro, checked = state.showPopUpOnConnection, onCheckedChange = onShowPopUpOnConnectionChanged)
|
||||
},
|
||||
checked = state.showPopUpOnConnection,
|
||||
onCheckedChange = onShowPopUpOnConnectionChanged,
|
||||
proLocked = !state.isPro,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -247,28 +241,6 @@ fun ReactionSettingsScreen(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ProGatedToggle(
|
||||
isPro: Boolean,
|
||||
checked: Boolean,
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
) {
|
||||
if (isPro) {
|
||||
Switch(
|
||||
checked = checked,
|
||||
onCheckedChange = onCheckedChange,
|
||||
modifier = Modifier.padding(start = 16.dp),
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
imageVector = Icons.TwoTone.Stars,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.padding(start = 16.dp).size(24.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview2
|
||||
@Composable
|
||||
private fun ReactionSettingsScreenPreview() = PreviewWrapper {
|
||||
@@ -293,3 +265,28 @@ private fun ReactionSettingsScreenPreview() = PreviewWrapper {
|
||||
onShowPopUpOnConnectionChanged = {},
|
||||
)
|
||||
}
|
||||
|
||||
@Preview2
|
||||
@Composable
|
||||
private fun ReactionSettingsScreenNonProPreview() = PreviewWrapper {
|
||||
ReactionSettingsScreen(
|
||||
state = ReactionSettingsViewModel.State(
|
||||
isPro = false,
|
||||
onePodMode = false,
|
||||
autoPlay = false,
|
||||
autoPause = false,
|
||||
autoConnect = false,
|
||||
autoConnectCondition = AutoConnectCondition.WHEN_SEEN,
|
||||
showPopUpOnCaseOpen = false,
|
||||
showPopUpOnConnection = false,
|
||||
),
|
||||
onNavigateUp = {},
|
||||
onOnePodModeChanged = {},
|
||||
onAutoPlayChanged = {},
|
||||
onAutoPauseChanged = {},
|
||||
onAutoConnectChanged = {},
|
||||
onAutoConnectConditionSelected = {},
|
||||
onShowPopUpOnCaseOpenChanged = {},
|
||||
onShowPopUpOnConnectionChanged = {},
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user