From 78cbd9d1297b6563e40839e52b1e54a69b0657fd Mon Sep 17 00:00:00 2001 From: vfsfitvnm Date: Wed, 13 Jul 2022 23:21:58 +0200 Subject: [PATCH] Move sleep timer to PlayerView menu (#98) --- .../ui/components/themed/MediaItemMenu.kt | 139 +++++++++++++++++- .../screens/settings/PlayerSettingsScreen.kt | 135 +---------------- .../vfsfitvnm/vimusic/ui/views/PlayerView.kt | 2 +- app/src/main/res/drawable/alarm.xml | 15 ++ 4 files changed, 149 insertions(+), 142 deletions(-) create mode 100644 app/src/main/res/drawable/alarm.xml diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/MediaItemMenu.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/MediaItemMenu.kt index 2ab0062..2d8bae9 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/MediaItemMenu.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/MediaItemMenu.kt @@ -1,18 +1,22 @@ package it.vfsfitvnm.vimusic.ui.components.themed +import android.text.format.DateUtils import androidx.compose.animation.AnimatedContentScope import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.with +import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.detectTapGestures -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicText import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp import androidx.media3.common.MediaItem import it.vfsfitvnm.route.RouteHandler import it.vfsfitvnm.route.empty @@ -21,13 +25,18 @@ import it.vfsfitvnm.vimusic.R import it.vfsfitvnm.vimusic.models.DetailedSong import it.vfsfitvnm.vimusic.models.Playlist import it.vfsfitvnm.vimusic.models.SongPlaylistMap +import it.vfsfitvnm.vimusic.ui.components.ChunkyButton import it.vfsfitvnm.vimusic.ui.components.LocalMenuState +import it.vfsfitvnm.vimusic.ui.components.Pager import it.vfsfitvnm.vimusic.ui.screens.rememberAlbumRoute import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute import it.vfsfitvnm.vimusic.ui.screens.rememberCreatePlaylistRoute +import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette +import it.vfsfitvnm.vimusic.ui.styling.LocalTypography import it.vfsfitvnm.vimusic.utils.* import it.vfsfitvnm.youtubemusic.models.NavigationEndpoint import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.flowOf @ExperimentalAnimationApi @@ -361,12 +370,128 @@ fun MediaItemMenu( } onSetSleepTimer?.let { onSetSleepTimer -> + val binder = LocalPlayerServiceBinder.current + val typography = LocalTypography.current + val colorPalette = LocalColorPalette.current + + var isShowingSleepTimerDialog by remember { + mutableStateOf(false) + } + + val sleepTimerMillisLeft by (binder?.sleepTimerMillisLeft ?: flowOf(null)) + .collectAsState(initial = null) + + if (isShowingSleepTimerDialog) { + if (sleepTimerMillisLeft != null) { + ConfirmationDialog( + text = "Do you want to stop the sleep timer?", + cancelText = "No", + confirmText = "Stop", + onDismiss = { + isShowingSleepTimerDialog = false + }, + onConfirm = { + binder?.cancelSleepTimer() + } + ) + } else { + DefaultDialog( + onDismiss = { + isShowingSleepTimerDialog = false + } + ) { + var hours by remember { + mutableStateOf(0) + } + + var minutes by remember { + mutableStateOf(0) + } + + BasicText( + text = "Set sleep timer", + style = typography.s.semiBold, + modifier = Modifier + .padding(vertical = 8.dp, horizontal = 24.dp) + ) + + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .padding(vertical = 16.dp) + ) { + Pager( + selectedIndex = hours, + onSelectedIndex = { + hours = it + }, + orientation = Orientation.Vertical, + modifier = Modifier + .padding(horizontal = 8.dp) + .height(92.dp) + ) { + repeat(12) { + BasicText( + text = "$it h", + style = typography.xs.semiBold + ) + } + } + + Pager( + selectedIndex = minutes, + onSelectedIndex = { + minutes = it + }, + orientation = Orientation.Vertical, + modifier = Modifier + .padding(horizontal = 8.dp) + .height(72.dp) + ) { + repeat(4) { + BasicText( + text = "${it * 15} m", + style = typography.xs.semiBold + ) + } + } + } + + Row( + horizontalArrangement = Arrangement.SpaceEvenly, + modifier = Modifier + .fillMaxWidth() + ) { + ChunkyButton( + backgroundColor = Color.Transparent, + text = "Cancel", + textStyle = typography.xs.semiBold, + shape = RoundedCornerShape(36.dp), + onClick = { isShowingSleepTimerDialog = false } + ) + + ChunkyButton( + backgroundColor = colorPalette.primaryContainer, + text = "Set", + textStyle = typography.xs.semiBold.color(colorPalette.onPrimaryContainer), + shape = RoundedCornerShape(36.dp), + isEnabled = hours > 0 || minutes > 0, + onClick = { + binder?.startSleepTimer((hours * 60 + minutes * 15) * 60 * 1000L) + isShowingSleepTimerDialog = false + } + ) + } + } + } + } + MenuEntry( - icon = R.drawable.time, + icon = R.drawable.alarm, text = "Sleep timer", + secondaryText = sleepTimerMillisLeft?.let { "${DateUtils.formatElapsedTime(it / 1000)} left" }, onClick = { - onDismiss() - onSetSleepTimer() + isShowingSleepTimerDialog = true } ) } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/settings/PlayerSettingsScreen.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/settings/PlayerSettingsScreen.kt index 695335a..a868b2a 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/settings/PlayerSettingsScreen.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/settings/PlayerSettingsScreen.kt @@ -2,19 +2,15 @@ package it.vfsfitvnm.vimusic.ui.screens.settings import android.content.Intent import android.media.audiofx.AudioEffect -import android.text.format.DateUtils import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.* -import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicText -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource @@ -22,18 +18,12 @@ import androidx.compose.ui.unit.dp import it.vfsfitvnm.route.RouteHandler import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder import it.vfsfitvnm.vimusic.R -import it.vfsfitvnm.vimusic.ui.components.ChunkyButton -import it.vfsfitvnm.vimusic.ui.components.Pager import it.vfsfitvnm.vimusic.ui.components.TopAppBar -import it.vfsfitvnm.vimusic.ui.components.themed.ConfirmationDialog -import it.vfsfitvnm.vimusic.ui.components.themed.DefaultDialog import it.vfsfitvnm.vimusic.ui.screens.* import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette import it.vfsfitvnm.vimusic.ui.styling.LocalTypography import it.vfsfitvnm.vimusic.utils.LocalPreferences -import it.vfsfitvnm.vimusic.utils.color import it.vfsfitvnm.vimusic.utils.semiBold -import kotlinx.coroutines.flow.flowOf @ExperimentalAnimationApi @@ -68,118 +58,6 @@ fun PlayerSettingsScreen() { rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { } - val sleepTimerMillisLeft by (binder?.sleepTimerMillisLeft - ?: flowOf(null)).collectAsState(initial = null) - - var isShowingSleepTimerDialog by remember { - mutableStateOf(false) - } - - if (isShowingSleepTimerDialog) { - if (sleepTimerMillisLeft != null) { - ConfirmationDialog( - text = "Do you want to stop the sleep timer?", - cancelText = "No", - confirmText = "Stop", - onDismiss = { - isShowingSleepTimerDialog = false - }, - onConfirm = { - binder?.cancelSleepTimer() - } - ) - } else { - DefaultDialog( - onDismiss = { - isShowingSleepTimerDialog = false - }, - modifier = Modifier - ) { - var hours by remember { - mutableStateOf(0) - } - - var minutes by remember { - mutableStateOf(0) - } - - BasicText( - text = "Set sleep timer", - style = typography.s.semiBold, - modifier = Modifier - .padding(vertical = 8.dp, horizontal = 24.dp) - ) - - Row( - modifier = Modifier - .padding(vertical = 16.dp) - ) { - Pager( - selectedIndex = hours, - onSelectedIndex = { - hours = it - }, - orientation = Orientation.Vertical, - modifier = Modifier - .padding(horizontal = 8.dp) - .height(72.dp) - ) { - repeat(12) { - BasicText( - text = "$it h", - style = typography.xs.semiBold - ) - } - } - - Pager( - selectedIndex = minutes, - onSelectedIndex = { - minutes = it - }, - orientation = Orientation.Vertical, - modifier = Modifier - .padding(horizontal = 8.dp) - .height(72.dp) - ) { - repeat(4) { - BasicText( - text = "${it * 15} m", - style = typography.xs.semiBold - ) - } - } - } - - Row( - horizontalArrangement = Arrangement.SpaceEvenly, - modifier = Modifier - .fillMaxWidth() - ) { - ChunkyButton( - backgroundColor = Color.Transparent, - text = "Cancel", - textStyle = typography.xs.semiBold, - shape = RoundedCornerShape(36.dp), - onClick = { isShowingSleepTimerDialog = false } - ) - - ChunkyButton( - backgroundColor = colorPalette.primaryContainer, - text = "Set", - textStyle = typography.xs.semiBold.color(colorPalette.onPrimaryContainer), - shape = RoundedCornerShape(36.dp), - isEnabled = hours > 0 || minutes > 0, - onClick = { - binder?.startSleepTimer((hours * 60 + minutes * 15) * 60 * 1000L) - isShowingSleepTimerDialog = false - } - ) - } - } - } - } - Column( modifier = Modifier .background(colorPalette.background) @@ -262,17 +140,6 @@ fun PlayerSettingsScreen() { } } ) - - SettingsEntryGroupText(title = "OTHER") - - SettingsEntry( - title = "Sleep timer", - text = sleepTimerMillisLeft?.let { "${DateUtils.formatElapsedTime(it / 1000)} left" } - ?: "Stop the music after a period of time", - onClick = { - isShowingSleepTimerDialog = true - } - ) } } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt index 99fff7d..9601916 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt @@ -75,7 +75,6 @@ fun PlayerView( player ?: return playerState?.mediaItem ?: return - BottomSheet( state = layoutState, modifier = modifier, @@ -288,6 +287,7 @@ fun PlayerView( .show() } }, + onSetSleepTimer = {}, onDismiss = menuState::hide, onGlobalRouteEmitted = layoutState.collapse, ) diff --git a/app/src/main/res/drawable/alarm.xml b/app/src/main/res/drawable/alarm.xml new file mode 100644 index 0000000..daa0fec --- /dev/null +++ b/app/src/main/res/drawable/alarm.xml @@ -0,0 +1,15 @@ + + + + +