Move sleep timer to PlayerView menu (#98)

This commit is contained in:
vfsfitvnm 2022-07-13 23:21:58 +02:00
parent d905fb8614
commit 78cbd9d129
4 changed files with 149 additions and 142 deletions

View file

@ -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 ->
MenuEntry(
icon = R.drawable.time,
text = "Sleep timer",
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 = {
onDismiss()
onSetSleepTimer()
binder?.startSleepTimer((hours * 60 + minutes * 15) * 60 * 1000L)
isShowingSleepTimerDialog = false
}
)
}
}
}
}
MenuEntry(
icon = R.drawable.alarm,
text = "Sleep timer",
secondaryText = sleepTimerMillisLeft?.let { "${DateUtils.formatElapsedTime(it / 1000)} left" },
onClick = {
isShowingSleepTimerDialog = true
}
)
}

View file

@ -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
}
)
}
}
}

View file

@ -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,
)

View file

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512dp"
android:height="512dp"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="#FF000000"
android:pathData="M153.59,110.46A21.41,21.41 0,0 0,152.48 79h0A62.67,62.67 0,0 0,112 64l-3.27,0.09 -0.48,0C74.4,66.15 48,95.55 48.07,131c0,19 8,29.06 14.32,37.11a20.61,20.61 0,0 0,14.7 7.8c0.26,0 0.7,0.05 2,0.05a19.06,19.06 0,0 0,13.75 -5.89Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M403.79,64.11l-3.27,-0.1H400a62.67,62.67 0,0 0,-40.52 15,21.41 21.41,0 0,0 -1.11,31.44l60.77,59.65A19.06,19.06 0,0 0,432.93 176c1.28,0 1.72,0 2,-0.05a20.61,20.61 0,0 0,14.69 -7.8c6.36,-8.05 14.28,-18.08 14.32,-37.11C464,95.55 437.6,66.15 403.79,64.11Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M256.07,96c-97,0 -176,78.95 -176,176a175.23,175.23 0,0 0,40.81 112.56L84.76,420.69a16,16 0,1 0,22.63 22.62l36.12,-36.12a175.63,175.63 0,0 0,225.12 0l36.13,36.12a16,16 0,1 0,22.63 -22.62l-36.13,-36.13A175.17,175.17 0,0 0,432.07 272C432.07,175 353.12,96 256.07,96ZM272.07,272a16,16 0,0 1,-16 16h-80a16,16 0,0 1,0 -32h64L240.07,160a16,16 0,0 1,32 0Z"/>
</vector>