mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-12 15:46:34 +01:00
playback: make the song tap shuffle behaviour a preference
This commit is contained in:
@@ -59,6 +59,8 @@ const val MAX_REPLAY_GAIN_PREAMP_DB = 15f
|
||||
|
||||
enum class SyncMode { Off, WifiOnly, Always }
|
||||
|
||||
enum class SongTapBehavior { InOrder, KeepShuffle, Shuffle }
|
||||
|
||||
enum class ReplayGainMode { Off, Track, Album, Auto }
|
||||
|
||||
data class ArtworkSeedValue(
|
||||
@@ -129,6 +131,19 @@ class UserPreferences(
|
||||
|
||||
private val syncModeKey = stringPreferencesKey("sync_mode")
|
||||
|
||||
fun songTapBehavior(): Flow<SongTapBehavior> =
|
||||
store.data.map { prefs ->
|
||||
prefs[songTapBehaviorKey]?.let { stored ->
|
||||
SongTapBehavior.entries.firstOrNull { it.name == stored }
|
||||
} ?: SongTapBehavior.InOrder
|
||||
}
|
||||
|
||||
suspend fun setSongTapBehavior(behavior: SongTapBehavior) {
|
||||
store.edit { prefs -> prefs[songTapBehaviorKey] = behavior.name }
|
||||
}
|
||||
|
||||
private val songTapBehaviorKey = stringPreferencesKey("song_tap_behavior")
|
||||
|
||||
fun lastSyncAt(): Flow<Long> = store.data.map { prefs -> prefs[lastSyncAtKey] ?: 0L }
|
||||
|
||||
suspend fun setLastSyncAt(value: Long) {
|
||||
|
||||
@@ -128,7 +128,7 @@ fun appModule(
|
||||
single(createdAtStart = true) { DownloadNotifier(context.applicationContext, get(), scope = get()).also { it.start() } }
|
||||
single(createdAtStart = true) { SyncNotifier(context.applicationContext, get<SyncManager>().status, scope = get()).also { it.start() } }
|
||||
single<PlayerConnection> { MediaSessionConnection(context.applicationContext, get(), get()) }
|
||||
single { PlaybackController(get(), get(), get(), get(), showMessage = toast, scope = get(named("playback"))) }
|
||||
single { PlaybackController(get(), get(), get(), get(), get(), showMessage = toast, scope = get(named("playback"))) }
|
||||
single(createdAtStart = true) {
|
||||
val playback = get<PlaybackController>()
|
||||
Scrobbler(
|
||||
|
||||
@@ -6,6 +6,8 @@ import com.subtracks.data.model.AudioEncoding
|
||||
import com.subtracks.data.model.CoverArtRef
|
||||
import com.subtracks.data.model.QueueEntry
|
||||
import com.subtracks.data.model.QueueKind
|
||||
import com.subtracks.data.prefs.SongTapBehavior
|
||||
import com.subtracks.data.prefs.UserPreferences
|
||||
import com.subtracks.data.repo.DownloadRepository
|
||||
import com.subtracks.data.repo.QueueRepository
|
||||
import com.subtracks.data.repo.QueueSnapshot
|
||||
@@ -22,6 +24,7 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.drop
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
@@ -106,6 +109,7 @@ private data class ReloadUndo(
|
||||
private data class PendingPlay(
|
||||
val entry: QueueEntry,
|
||||
val position: Long,
|
||||
val behavior: SongTapBehavior?,
|
||||
)
|
||||
|
||||
class PlaybackController(
|
||||
@@ -113,6 +117,7 @@ class PlaybackController(
|
||||
private val queueRepository: QueueRepository,
|
||||
private val connection: PlayerConnection,
|
||||
private val downloads: DownloadRepository,
|
||||
private val preferences: UserPreferences,
|
||||
private val showMessage: (UiMessage) -> Unit = {},
|
||||
private val scope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate),
|
||||
) {
|
||||
@@ -190,7 +195,7 @@ class PlaybackController(
|
||||
val shuffle = pendingShuffle
|
||||
pendingShuffle = null
|
||||
when {
|
||||
pending != null -> start(pending.entry, pending.position)
|
||||
pending != null -> startPending(pending)
|
||||
shuffle != null -> startShuffled(shuffle)
|
||||
else -> restore()
|
||||
}
|
||||
@@ -239,6 +244,16 @@ class PlaybackController(
|
||||
startOrdinal: Long,
|
||||
) = play(queueRepository.starredEntry(sourceId), startOrdinal)
|
||||
|
||||
fun playAlbumInOrder(
|
||||
sourceId: Long,
|
||||
albumId: String,
|
||||
) = play(queueRepository.albumEntry(sourceId, albumId), 0, SongTapBehavior.InOrder)
|
||||
|
||||
fun playPlaylistInOrder(
|
||||
sourceId: Long,
|
||||
playlistId: String,
|
||||
) = play(queueRepository.playlistEntry(sourceId, playlistId), 0, SongTapBehavior.InOrder)
|
||||
|
||||
fun shuffleAlbum(
|
||||
sourceId: Long,
|
||||
albumId: String,
|
||||
@@ -968,22 +983,35 @@ class PlaybackController(
|
||||
private fun play(
|
||||
entry: QueueEntry,
|
||||
startPosition: Long,
|
||||
behavior: SongTapBehavior? = null,
|
||||
) {
|
||||
if (player == null) {
|
||||
pendingPlay = PendingPlay(entry, startPosition)
|
||||
pendingPlay = PendingPlay(entry, startPosition, behavior)
|
||||
connect()
|
||||
return
|
||||
}
|
||||
scope.launch { start(entry, startPosition) }
|
||||
scope.launch { start(entry, startPosition, behavior ?: preferences.songTapBehavior().first()) }
|
||||
}
|
||||
|
||||
private suspend fun startPending(pending: PendingPlay) {
|
||||
val behavior = pending.behavior ?: preferences.songTapBehavior().first()
|
||||
start(pending.entry, pending.position, behavior)
|
||||
}
|
||||
|
||||
private suspend fun start(
|
||||
entry: QueueEntry,
|
||||
startPosition: Long,
|
||||
behavior: SongTapBehavior,
|
||||
) = startLock.withLock {
|
||||
val snapshot = resetQueue(entry)
|
||||
val modes = queueRepository.modes()
|
||||
shuffleEnabled = false
|
||||
val shuffle =
|
||||
when (behavior) {
|
||||
SongTapBehavior.InOrder -> false
|
||||
SongTapBehavior.KeepShuffle -> modes.shuffle
|
||||
SongTapBehavior.Shuffle -> true
|
||||
}
|
||||
val snapshot = resetQueue(entry)
|
||||
shuffleEnabled = shuffle
|
||||
repeatMode = modes.repeat.toRepeatMode()
|
||||
player?.setRepeatOne(repeatMode == RepeatMode.One)
|
||||
queueSourceId = entry.sourceId
|
||||
@@ -991,7 +1019,14 @@ class PlaybackController(
|
||||
stopLocked()
|
||||
return@withLock
|
||||
}
|
||||
val position = startPosition.coerceIn(0, snapshot.contextSize - 1)
|
||||
val start = startPosition.coerceIn(0, snapshot.contextSize - 1)
|
||||
val position =
|
||||
if (shuffle) {
|
||||
queueRepository.setShuffle(pinnedSeed(snapshot.contextSize, start))
|
||||
0L
|
||||
} else {
|
||||
start
|
||||
}
|
||||
queueRepository.setCursor(position)
|
||||
this.snapshot = readSnapshot()
|
||||
loadWindow(position, autoplay = true)
|
||||
|
||||
@@ -96,7 +96,7 @@ class AlbumDetailViewModel(
|
||||
|
||||
fun playAll() {
|
||||
viewModelScope.launch {
|
||||
playbackController.playAlbum(sourceId.first(), albumId, 0)
|
||||
playbackController.playAlbumInOrder(sourceId.first(), albumId)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ class PlaylistDetailViewModel(
|
||||
|
||||
fun playAll() {
|
||||
viewModelScope.launch {
|
||||
playbackController.playPlaylist(sourceId.first(), playlistId, 0)
|
||||
playbackController.playPlaylistInOrder(sourceId.first(), playlistId)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ import com.subtracks.data.prefs.DEFAULT_SYNC_INTERVAL_MINUTES
|
||||
import com.subtracks.data.prefs.MAX_REPLAY_GAIN_PREAMP_DB
|
||||
import com.subtracks.data.prefs.MIN_REPLAY_GAIN_PREAMP_DB
|
||||
import com.subtracks.data.prefs.ReplayGainMode
|
||||
import com.subtracks.data.prefs.SongTapBehavior
|
||||
import com.subtracks.data.prefs.SortNameMode
|
||||
import com.subtracks.data.prefs.StreamQuality
|
||||
import com.subtracks.data.prefs.SyncMode
|
||||
@@ -103,6 +104,7 @@ private enum class SettingsDialog {
|
||||
ReplayGain,
|
||||
ReplayGainPreamp,
|
||||
SortNames,
|
||||
SongTap,
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -131,6 +133,7 @@ fun SettingsRoute(
|
||||
val replayGainMode by viewModel.replayGainMode.collectAsStateWithLifecycle()
|
||||
val replayGainPreamp by viewModel.replayGainPreamp.collectAsStateWithLifecycle()
|
||||
val sortNameMode by viewModel.sortNameMode.collectAsStateWithLifecycle()
|
||||
val songTapBehavior by viewModel.songTapBehavior.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
SettingsScreen(
|
||||
@@ -147,6 +150,7 @@ fun SettingsRoute(
|
||||
replayGainMode = replayGainMode,
|
||||
replayGainPreamp = replayGainPreamp,
|
||||
sortNameMode = sortNameMode,
|
||||
songTapBehavior = songTapBehavior,
|
||||
keepScreenOn = keepScreenOn,
|
||||
offline = offline,
|
||||
verboseLogging = verboseLogging,
|
||||
@@ -163,6 +167,7 @@ fun SettingsRoute(
|
||||
onReplayGainModeChange = viewModel::setReplayGainMode,
|
||||
onReplayGainPreampChange = viewModel::setReplayGainPreamp,
|
||||
onSortNameModeChange = viewModel::setSortNameMode,
|
||||
onSongTapBehaviorChange = viewModel::setSongTapBehavior,
|
||||
onKeepScreenOnChange = viewModel::setKeepScreenOn,
|
||||
onOfflineChange = viewModel::setOfflineMode,
|
||||
onVerboseLoggingChange = viewModel::setVerboseLogging,
|
||||
@@ -211,6 +216,7 @@ fun SettingsScreen(
|
||||
replayGainMode: ReplayGainMode = ReplayGainMode.Auto,
|
||||
replayGainPreamp: Float = 0f,
|
||||
sortNameMode: SortNameMode = SortNameMode.Name,
|
||||
songTapBehavior: SongTapBehavior = SongTapBehavior.InOrder,
|
||||
onSelectSource: (Long) -> Unit,
|
||||
onEditServer: (Long) -> Unit,
|
||||
onWifiQualityChange: (StreamQuality) -> Unit,
|
||||
@@ -224,6 +230,7 @@ fun SettingsScreen(
|
||||
onReplayGainModeChange: (ReplayGainMode) -> Unit = {},
|
||||
onReplayGainPreampChange: (Float) -> Unit = {},
|
||||
onSortNameModeChange: (SortNameMode) -> Unit = {},
|
||||
onSongTapBehaviorChange: (SongTapBehavior) -> Unit = {},
|
||||
onKeepScreenOnChange: (Boolean) -> Unit = {},
|
||||
onOfflineChange: (Boolean) -> Unit = {},
|
||||
onVerboseLoggingChange: (Boolean) -> Unit = {},
|
||||
@@ -421,6 +428,14 @@ fun SettingsScreen(
|
||||
colors = ListItemDefaults.colors(containerColor = Color.Transparent),
|
||||
)
|
||||
}
|
||||
item {
|
||||
ListItem(
|
||||
headlineContent = { Text(stringResource(R.string.settings_music_options_song_tap_title)) },
|
||||
supportingContent = { Text(songTapBehaviorLabel(LocalResources.current, songTapBehavior)) },
|
||||
modifier = Modifier.clickable { dialog = SettingsDialog.SongTap },
|
||||
colors = ListItemDefaults.colors(containerColor = Color.Transparent),
|
||||
)
|
||||
}
|
||||
item { SectionHeader(stringResource(R.string.downloads_title)) }
|
||||
item {
|
||||
ListItem(
|
||||
@@ -627,6 +642,14 @@ fun SettingsScreen(
|
||||
)
|
||||
}
|
||||
|
||||
SettingsDialog.SongTap -> {
|
||||
SongTapBehaviorDialog(
|
||||
selected = songTapBehavior,
|
||||
onSelect = onSongTapBehaviorChange,
|
||||
onDismiss = { dialog = null },
|
||||
)
|
||||
}
|
||||
|
||||
null -> {
|
||||
Unit
|
||||
}
|
||||
@@ -826,6 +849,51 @@ private fun SortNameModeDialog(
|
||||
)
|
||||
}
|
||||
|
||||
private val songTapBehaviorOptions = SongTapBehavior.entries
|
||||
|
||||
private fun songTapBehaviorLabel(
|
||||
resources: Resources,
|
||||
behavior: SongTapBehavior,
|
||||
): String =
|
||||
when (behavior) {
|
||||
SongTapBehavior.InOrder -> resources.getString(R.string.settings_music_options_song_tap_in_order)
|
||||
SongTapBehavior.KeepShuffle -> resources.getString(R.string.settings_music_options_song_tap_keep_shuffle)
|
||||
SongTapBehavior.Shuffle -> resources.getString(R.string.settings_music_options_song_tap_shuffle)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SongTapBehaviorDialog(
|
||||
selected: SongTapBehavior,
|
||||
onSelect: (SongTapBehavior) -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
val resources = LocalResources.current
|
||||
var draft by remember(selected) { mutableStateOf(selected) }
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(stringResource(R.string.settings_music_options_song_tap_title)) },
|
||||
text = {
|
||||
ChoiceGroup(
|
||||
header = stringResource(R.string.settings_music_options_song_tap_prompt),
|
||||
options = songTapBehaviorOptions.map { it to songTapBehaviorLabel(resources, it) },
|
||||
selected = draft,
|
||||
onSelect = { draft = it },
|
||||
)
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onSelect(draft)
|
||||
onDismiss()
|
||||
},
|
||||
) { Text(stringResource(R.string.action_done)) }
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) { Text(stringResource(R.string.actions_cancel)) }
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ReplayGainModeDialog(
|
||||
selected: ReplayGainMode,
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.subtracks.data.model.Source
|
||||
import com.subtracks.data.net.NetworkMode
|
||||
import com.subtracks.data.prefs.DEFAULT_SYNC_INTERVAL_MINUTES
|
||||
import com.subtracks.data.prefs.ReplayGainMode
|
||||
import com.subtracks.data.prefs.SongTapBehavior
|
||||
import com.subtracks.data.prefs.SortNameMode
|
||||
import com.subtracks.data.prefs.StreamQuality
|
||||
import com.subtracks.data.prefs.SyncMode
|
||||
@@ -82,6 +83,11 @@ class SettingsViewModel(
|
||||
.sortNameMode()
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), SortNameMode.Name)
|
||||
|
||||
val songTapBehavior: StateFlow<SongTapBehavior> =
|
||||
userPreferences
|
||||
.songTapBehavior()
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), SongTapBehavior.InOrder)
|
||||
|
||||
val keepScreenOn: StateFlow<Boolean> =
|
||||
userPreferences
|
||||
.keepScreenOn()
|
||||
@@ -153,4 +159,8 @@ class SettingsViewModel(
|
||||
fun setSortNameMode(mode: SortNameMode) {
|
||||
viewModelScope.launch { userPreferences.setSortNameMode(mode) }
|
||||
}
|
||||
|
||||
fun setSongTapBehavior(behavior: SongTapBehavior) {
|
||||
viewModelScope.launch { userPreferences.setSongTapBehavior(behavior) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,11 @@
|
||||
<string name="settings_music_name">Playback</string>
|
||||
<string name="settings_music_options_scrobble_description_on">Send now playing and play counts</string>
|
||||
<string name="settings_music_options_scrobble_title">Scrobble to server</string>
|
||||
<string name="settings_music_options_song_tap_in_order">Play without shuffling</string>
|
||||
<string name="settings_music_options_song_tap_keep_shuffle">Keep current shuffle mode</string>
|
||||
<string name="settings_music_options_song_tap_prompt">When tapping a song in a list</string>
|
||||
<string name="settings_music_options_song_tap_shuffle">Play and shuffle</string>
|
||||
<string name="settings_music_options_song_tap_title">New song tap behavior</string>
|
||||
<string name="settings_replay_gain_mode_album">Album gain</string>
|
||||
<string name="settings_replay_gain_mode_auto">Auto</string>
|
||||
<string name="settings_replay_gain_mode_off">Off</string>
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.subtracks.data.model.Song
|
||||
import com.subtracks.data.model.SongDownload
|
||||
import com.subtracks.data.model.Source
|
||||
import com.subtracks.data.net.NetworkMode
|
||||
import com.subtracks.data.prefs.SongTapBehavior
|
||||
import com.subtracks.data.prefs.StreamQuality
|
||||
import com.subtracks.data.prefs.UserPreferences
|
||||
import com.subtracks.data.prefs.fakeUserPreferences
|
||||
@@ -113,6 +114,7 @@ class PlaybackControllerTest {
|
||||
queues,
|
||||
FakePlayerConnection(handle),
|
||||
downloads,
|
||||
prefs,
|
||||
showMessage = { messages += it.resolve(resources) },
|
||||
scope = controllerScope,
|
||||
)
|
||||
@@ -2519,6 +2521,60 @@ class PlaybackControllerTest {
|
||||
assertEquals("s4", runBlocking { queues.itemAt(snapshot, controller.state.value.position!!)?.song?.id })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun tappingASongCanKeepTheCurrentShuffleMode() {
|
||||
seedAlbum(5, sourceId = 1)
|
||||
runBlocking { prefs.setSongTapBehavior(SongTapBehavior.KeepShuffle) }
|
||||
|
||||
controller.playAlbum(1, "al1", 0)
|
||||
await {
|
||||
controller.state.value.item
|
||||
?.id == "s1"
|
||||
}
|
||||
controller.toggleShuffle()
|
||||
await { controller.state.value.shuffle }
|
||||
|
||||
controller.playAlbum(1, "al1", 3)
|
||||
await {
|
||||
controller.state.value.item
|
||||
?.id == "s4" && controller.state.value.shuffle
|
||||
}
|
||||
|
||||
assertEquals(0L, controller.state.value.position)
|
||||
val snapshot = runBlocking { queues.snapshot() }
|
||||
assertTrue(snapshot.shuffled)
|
||||
assertEquals("s4", runBlocking { queues.itemAt(snapshot, controller.state.value.position!!)?.song?.id })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun tappingASongCanStartShuffled() {
|
||||
seedAlbum(5, sourceId = 1)
|
||||
runBlocking { prefs.setSongTapBehavior(SongTapBehavior.Shuffle) }
|
||||
|
||||
controller.playAlbum(1, "al1", 3)
|
||||
await {
|
||||
controller.state.value.item
|
||||
?.id == "s4" && controller.state.value.shuffle
|
||||
}
|
||||
|
||||
assertEquals(0L, controller.state.value.position)
|
||||
assertTrue(runBlocking { queues.snapshot().shuffled })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun playAllStartsInOrderRegardlessOfTheSongTapBehavior() {
|
||||
seedAlbum(3, sourceId = 1)
|
||||
runBlocking { prefs.setSongTapBehavior(SongTapBehavior.Shuffle) }
|
||||
|
||||
controller.playAlbumInOrder(1, "al1")
|
||||
await {
|
||||
controller.state.value.item
|
||||
?.id == "s1" && !controller.state.value.shuffle
|
||||
}
|
||||
|
||||
assertEquals(0L, controller.state.value.position)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun jumpingInTheQueueWhileShuffledKeepsTheOrder() {
|
||||
seedAlbum(5, sourceId = 1)
|
||||
@@ -3643,7 +3699,7 @@ class PlaybackControllerTest {
|
||||
handle: FakePlayerHandle,
|
||||
): PlaybackController {
|
||||
val scope = CoroutineScope(SupervisorJob() + dispatcher).also { extraScopes += it }
|
||||
return PlaybackController(sources, queues, FakePlayerConnection(handle), downloads, scope = scope)
|
||||
return PlaybackController(sources, queues, FakePlayerConnection(handle), downloads, prefs, scope = scope)
|
||||
}
|
||||
|
||||
private fun await(predicate: () -> Boolean) = awaitUntil("waiting for the expected playback state", predicate)
|
||||
|
||||
@@ -59,6 +59,7 @@ class ViewModelRepositoryFixture {
|
||||
queueRepository,
|
||||
FakePlayerConnection(FakePlayerHandle()),
|
||||
downloadRepository,
|
||||
fakeUserPreferences(),
|
||||
scope = controllerScope,
|
||||
)
|
||||
val libraryRepository =
|
||||
|
||||
@@ -101,6 +101,7 @@ class NowPlayingRouteTest {
|
||||
queues,
|
||||
FakePlayerConnection(handle),
|
||||
downloads,
|
||||
prefs,
|
||||
showMessage = {},
|
||||
scope = controllerScope,
|
||||
)
|
||||
|
||||
@@ -83,7 +83,15 @@ class QueueViewModelTest {
|
||||
artworkFetcher = { ByteArray(0) },
|
||||
scope = repoScope,
|
||||
).also { it.start() }
|
||||
controller = PlaybackController(sources, queues, FakePlayerConnection(FakePlayerHandle()), downloads, scope = controllerScope)
|
||||
controller =
|
||||
PlaybackController(
|
||||
sources,
|
||||
queues,
|
||||
FakePlayerConnection(FakePlayerHandle()),
|
||||
downloads,
|
||||
fakeUserPreferences(),
|
||||
scope = controllerScope,
|
||||
)
|
||||
viewModel = QueueViewModel(queues, controller, sources, downloads)
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollToNode
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.github.takahirom.roborazzi.RobolectricDeviceQualifiers
|
||||
import com.subtracks.data.prefs.SongTapBehavior
|
||||
import com.subtracks.data.prefs.SortNameMode
|
||||
import com.subtracks.data.prefs.StreamQuality
|
||||
import com.subtracks.ui.theme.SubtracksTheme
|
||||
@@ -82,10 +83,29 @@ class SettingsScreenTest {
|
||||
assertEquals(SortNameMode.SortName, requested)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun theSongTapBehaviorRowChangesTheSetting() {
|
||||
var requested: SongTapBehavior? = null
|
||||
renderSettings(
|
||||
keepScreenOn = false,
|
||||
onKeepScreenOnChange = {},
|
||||
onSongTapBehaviorChange = { requested = it },
|
||||
scrollTo = "New song tap behavior",
|
||||
)
|
||||
|
||||
composeRule.onNodeWithText("New song tap behavior").performClick()
|
||||
composeRule.onNodeWithText("Play and shuffle").performClick()
|
||||
composeRule.onNodeWithText("Done").performClick()
|
||||
composeRule.waitForIdle()
|
||||
|
||||
assertEquals(SongTapBehavior.Shuffle, requested)
|
||||
}
|
||||
|
||||
private fun renderSettings(
|
||||
keepScreenOn: Boolean,
|
||||
onKeepScreenOnChange: (Boolean) -> Unit,
|
||||
onSortNameModeChange: (SortNameMode) -> Unit = {},
|
||||
onSongTapBehaviorChange: (SongTapBehavior) -> Unit = {},
|
||||
scrollTo: String = "Keep screen on",
|
||||
) {
|
||||
composeRule.setContent {
|
||||
@@ -110,6 +130,7 @@ class SettingsScreenTest {
|
||||
onScrobblingChange = {},
|
||||
onKeepScreenOnChange = onKeepScreenOnChange,
|
||||
onSortNameModeChange = onSortNameModeChange,
|
||||
onSongTapBehaviorChange = onSongTapBehaviorChange,
|
||||
onAddServer = {},
|
||||
onOpenDownloads = {},
|
||||
onOpenLicenses = {},
|
||||
|
||||
Reference in New Issue
Block a user