mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-10 15:11:58 +01:00
polish stream quality settings
- label the rows 'Stream quality: Wi-Fi' / 'Stream quality: Mobile' - default mobile to 192kbps/mp3 while Wi-Fi stays unlimited/server default - apply the selection only when Done is pressed, cancelling discards the draft - fade the bottom of the dialog list so the remaining options are visible as scrollable
This commit is contained in:
@@ -56,7 +56,9 @@ class UserPreferences(
|
||||
|
||||
fun streamQuality(mode: NetworkMode): Flow<StreamQuality> =
|
||||
store.data.map { prefs ->
|
||||
prefs[streamQualityKey(mode)]?.let(::decodeStreamQuality) ?: legacyStreamQuality(prefs)
|
||||
prefs[streamQualityKey(mode)]?.let(::decodeStreamQuality)
|
||||
?: legacyStreamQuality(prefs)
|
||||
?: defaultStreamQuality(mode)
|
||||
}
|
||||
|
||||
suspend fun setStreamQuality(
|
||||
@@ -82,11 +84,21 @@ class UserPreferences(
|
||||
)
|
||||
}
|
||||
|
||||
private fun legacyStreamQuality(prefs: Preferences): StreamQuality =
|
||||
StreamQuality(
|
||||
maxBitrate = prefs[LEGACY_BITRATE] ?: 0,
|
||||
format = prefs[LEGACY_FORMAT]?.takeIf { it.isNotEmpty() },
|
||||
private fun legacyStreamQuality(prefs: Preferences): StreamQuality? {
|
||||
val bitrate = prefs[LEGACY_BITRATE]
|
||||
val format = prefs[LEGACY_FORMAT]
|
||||
if (bitrate == null && format == null) return null
|
||||
return StreamQuality(
|
||||
maxBitrate = bitrate ?: 0,
|
||||
format = format?.takeIf { it.isNotEmpty() },
|
||||
)
|
||||
}
|
||||
|
||||
private fun defaultStreamQuality(mode: NetworkMode): StreamQuality =
|
||||
when (mode) {
|
||||
NetworkMode.Wifi -> StreamQuality()
|
||||
NetworkMode.Mobile -> StreamQuality(maxBitrate = 192, format = "mp3")
|
||||
}
|
||||
|
||||
private fun decode(
|
||||
stored: String?,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.subtracks.ui.settings
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -39,6 +41,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -150,7 +153,7 @@ fun SettingsScreen(
|
||||
item { SectionHeader("Network") }
|
||||
item {
|
||||
ListItem(
|
||||
headlineContent = { Text("Wi-Fi") },
|
||||
headlineContent = { Text("Stream quality: Wi-Fi") },
|
||||
supportingContent = { Text(qualityLabel(wifiQuality)) },
|
||||
modifier = Modifier.clickable { dialog = SettingsDialog.WifiQuality },
|
||||
colors = ListItemDefaults.colors(containerColor = Color.Transparent),
|
||||
@@ -158,7 +161,7 @@ fun SettingsScreen(
|
||||
}
|
||||
item {
|
||||
ListItem(
|
||||
headlineContent = { Text("Mobile data") },
|
||||
headlineContent = { Text("Stream quality: Mobile") },
|
||||
supportingContent = { Text(qualityLabel(mobileQuality)) },
|
||||
modifier = Modifier.clickable { dialog = SettingsDialog.MobileQuality },
|
||||
colors = ListItemDefaults.colors(containerColor = Color.Transparent),
|
||||
@@ -171,7 +174,7 @@ fun SettingsScreen(
|
||||
when (dialog) {
|
||||
SettingsDialog.WifiQuality -> {
|
||||
QualityDialog(
|
||||
title = "Wi-Fi",
|
||||
title = "Stream quality: Wi-Fi",
|
||||
quality = wifiQuality,
|
||||
onSelect = onWifiQualityChange,
|
||||
onDismiss = { dialog = null },
|
||||
@@ -180,7 +183,7 @@ fun SettingsScreen(
|
||||
|
||||
SettingsDialog.MobileQuality -> {
|
||||
QualityDialog(
|
||||
title = "Mobile data",
|
||||
title = "Stream quality: Mobile",
|
||||
quality = mobileQuality,
|
||||
onSelect = onMobileQualityChange,
|
||||
onDismiss = { dialog = null },
|
||||
@@ -205,34 +208,53 @@ private fun QualityDialog(
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
var draft by remember(quality) { mutableStateOf(quality) }
|
||||
val scrollState = rememberScrollState()
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(title) },
|
||||
text = {
|
||||
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
|
||||
ChoiceGroup(
|
||||
header = "Maximum bitrate",
|
||||
options = bitrateOptions.map { it to bitrateLabel(it) },
|
||||
selected = draft.maxBitrate,
|
||||
onSelect = {
|
||||
draft = draft.copy(maxBitrate = it)
|
||||
onSelect(draft)
|
||||
},
|
||||
)
|
||||
Spacer(Modifier.height(16.dp))
|
||||
ChoiceGroup(
|
||||
header = "Preferred format",
|
||||
options = streamFormats.map { it to (it ?: "Use server default") },
|
||||
selected = draft.format,
|
||||
onSelect = {
|
||||
draft = draft.copy(format = it)
|
||||
onSelect(draft)
|
||||
},
|
||||
)
|
||||
Box {
|
||||
Column(modifier = Modifier.verticalScroll(scrollState)) {
|
||||
ChoiceGroup(
|
||||
header = "Maximum bitrate",
|
||||
options = bitrateOptions.map { it to bitrateLabel(it) },
|
||||
selected = draft.maxBitrate,
|
||||
onSelect = { draft = draft.copy(maxBitrate = it) },
|
||||
)
|
||||
Spacer(Modifier.height(16.dp))
|
||||
ChoiceGroup(
|
||||
header = "Preferred format",
|
||||
options = streamFormats.map { it to (it ?: "Use server default") },
|
||||
selected = draft.format,
|
||||
onSelect = { draft = draft.copy(format = it) },
|
||||
)
|
||||
}
|
||||
if (scrollState.canScrollForward) {
|
||||
Box(
|
||||
modifier =
|
||||
Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.fillMaxWidth()
|
||||
.height(32.dp)
|
||||
.background(
|
||||
Brush.verticalGradient(
|
||||
listOf(Color.Transparent, MaterialTheme.colorScheme.surfaceContainerHigh),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = onDismiss) { Text("Done") }
|
||||
TextButton(
|
||||
onClick = {
|
||||
onSelect(draft)
|
||||
onDismiss()
|
||||
},
|
||||
) { Text("Done") }
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) { Text("Cancel") }
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ class UserPreferencesTest {
|
||||
val prefs = UserPreferences(store)
|
||||
|
||||
assertEquals(StreamQuality(), prefs.streamQuality(NetworkMode.Wifi).first())
|
||||
assertEquals(StreamQuality(), prefs.streamQuality(NetworkMode.Mobile).first())
|
||||
assertEquals(StreamQuality(192, "mp3"), prefs.streamQuality(NetworkMode.Mobile).first())
|
||||
|
||||
prefs.setStreamQuality(NetworkMode.Wifi, StreamQuality(320, null))
|
||||
prefs.setStreamQuality(NetworkMode.Mobile, StreamQuality(96, "opus"))
|
||||
|
||||
Reference in New Issue
Block a user