Make session length slider functional
This commit is contained in:
@@ -9,7 +9,7 @@ import org.nsh07.pomodoro.ui.AppScreen
|
||||
import org.nsh07.pomodoro.ui.NavItem
|
||||
import org.nsh07.pomodoro.ui.Screen
|
||||
import org.nsh07.pomodoro.ui.theme.TomatoTheme
|
||||
import org.nsh07.pomodoro.ui.viewModel.TimerViewModel
|
||||
import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerViewModel
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
|
||||
@@ -4,10 +4,12 @@ interface TimerRepository {
|
||||
var focusTime: Int
|
||||
var shortBreakTime: Int
|
||||
var longBreakTime: Int
|
||||
var sessionLength: Int
|
||||
}
|
||||
|
||||
class AppTimerRepository : TimerRepository {
|
||||
override var focusTime = 25 * 60 * 1000
|
||||
override var shortBreakTime = 5 * 60 * 1000
|
||||
override var longBreakTime = 15 * 60 * 1000
|
||||
override var sessionLength = 4
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import androidx.compose.material3.MaterialTheme.motionScheme
|
||||
import androidx.compose.material3.NavigationItemIconPosition
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.ShortNavigationBar
|
||||
import androidx.compose.material3.ShortNavigationBarArrangement
|
||||
import androidx.compose.material3.ShortNavigationBarItem
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||
@@ -44,7 +45,7 @@ import org.nsh07.pomodoro.MainActivity.Companion.screens
|
||||
import org.nsh07.pomodoro.ui.settingsScreen.SettingsScreenRoot
|
||||
import org.nsh07.pomodoro.ui.statsScreen.StatsScreen
|
||||
import org.nsh07.pomodoro.ui.timerScreen.TimerScreen
|
||||
import org.nsh07.pomodoro.ui.viewModel.TimerViewModel
|
||||
import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
@@ -52,7 +53,7 @@ fun AppScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: TimerViewModel = viewModel(factory = TimerViewModel.Factory)
|
||||
) {
|
||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||
val uiState by viewModel.timerState.collectAsStateWithLifecycle()
|
||||
val remainingTime by viewModel.time.collectAsStateWithLifecycle()
|
||||
|
||||
val progress by rememberUpdatedState((uiState.totalTime.toFloat() - remainingTime) / uiState.totalTime)
|
||||
@@ -78,7 +79,16 @@ fun AppScreen(
|
||||
|
||||
Scaffold(
|
||||
bottomBar = {
|
||||
ShortNavigationBar {
|
||||
val wide = remember {
|
||||
windowSizeClass.isWidthAtLeastBreakpoint(
|
||||
WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND
|
||||
)
|
||||
}
|
||||
ShortNavigationBar(
|
||||
arrangement =
|
||||
if (wide) ShortNavigationBarArrangement.Centered
|
||||
else ShortNavigationBarArrangement.EqualWeight
|
||||
) {
|
||||
screens.forEach {
|
||||
val selected = backStack.last() == it.route
|
||||
ShortNavigationBarItem(
|
||||
@@ -98,10 +108,7 @@ fun AppScreen(
|
||||
}
|
||||
},
|
||||
iconPosition =
|
||||
if (windowSizeClass.isWidthAtLeastBreakpoint(
|
||||
WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND
|
||||
)
|
||||
) NavigationItemIconPosition.Start
|
||||
if (wide) NavigationItemIconPosition.Start
|
||||
else NavigationItemIconPosition.Top,
|
||||
label = { Text(it.label) }
|
||||
)
|
||||
@@ -134,7 +141,7 @@ fun AppScreen(
|
||||
entryProvider = entryProvider {
|
||||
entry<Screen.Timer> {
|
||||
TimerScreen(
|
||||
uiState = uiState,
|
||||
timerState = uiState,
|
||||
showBrandTitle = showBrandTitle,
|
||||
progress = { progress },
|
||||
resetTimer = viewModel::resetTimer,
|
||||
|
||||
@@ -25,6 +25,7 @@ import androidx.compose.material3.MaterialTheme.colorScheme
|
||||
import androidx.compose.material3.MaterialTheme.shapes
|
||||
import androidx.compose.material3.MaterialTheme.typography
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.SliderState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
@@ -43,10 +44,11 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import org.nsh07.pomodoro.R
|
||||
import org.nsh07.pomodoro.ui.settingsScreen.viewModel.SettingsViewModel
|
||||
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTitle
|
||||
import org.nsh07.pomodoro.ui.theme.TomatoTheme
|
||||
import org.nsh07.pomodoro.ui.viewModel.SettingsViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SettingsScreenRoot(
|
||||
modifier: Modifier = Modifier,
|
||||
@@ -62,10 +64,20 @@ fun SettingsScreenRoot(
|
||||
viewModel.longBreakTimeTextFieldState
|
||||
}
|
||||
|
||||
val sessionsSliderState = rememberSaveable(
|
||||
saver = SliderState.Saver(
|
||||
viewModel.sessionsSliderState.onValueChangeFinished,
|
||||
viewModel.sessionsSliderState.valueRange
|
||||
)
|
||||
) {
|
||||
viewModel.sessionsSliderState
|
||||
}
|
||||
|
||||
SettingsScreen(
|
||||
focusTimeInputFieldState = focusTimeInputFieldState,
|
||||
shortBreakTimeInputFieldState = shortBreakTimeInputFieldState,
|
||||
longBreakTimeInputFieldState = longBreakTimeInputFieldState,
|
||||
sessionsSliderState = sessionsSliderState,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
@@ -76,10 +88,10 @@ private fun SettingsScreen(
|
||||
focusTimeInputFieldState: TextFieldState,
|
||||
shortBreakTimeInputFieldState: TextFieldState,
|
||||
longBreakTimeInputFieldState: TextFieldState,
|
||||
sessionsSliderState: SliderState,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
||||
val sessionsSliderState = rememberSliderState(value = 3f, steps = 3, valueRange = 1f..5f)
|
||||
|
||||
Column(modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) {
|
||||
TopAppBar(
|
||||
@@ -184,11 +196,11 @@ private fun SettingsScreen(
|
||||
)
|
||||
},
|
||||
headlineContent = {
|
||||
Text("Sessions")
|
||||
Text("Session length")
|
||||
},
|
||||
supportingContent = {
|
||||
Column {
|
||||
Text("${sessionsSliderState.value.toInt()} sessions before a long break")
|
||||
Text("Focus intervals in one session: ${sessionsSliderState.value.toInt()}")
|
||||
Slider(
|
||||
state = sessionsSliderState,
|
||||
modifier = Modifier.padding(vertical = 4.dp)
|
||||
@@ -202,6 +214,7 @@ private fun SettingsScreen(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Preview(
|
||||
showSystemUi = true,
|
||||
device = Devices.PIXEL_9_PRO
|
||||
@@ -213,6 +226,7 @@ fun SettingsScreenPreview() {
|
||||
focusTimeInputFieldState = rememberTextFieldState((25 * 60 * 1000).toString()),
|
||||
shortBreakTimeInputFieldState = rememberTextFieldState((5 * 60 * 1000).toString()),
|
||||
longBreakTimeInputFieldState = rememberTextFieldState((15 * 60 * 1000).toString()),
|
||||
sessionsSliderState = rememberSliderState(value = 3f, steps = 3, valueRange = 1f..5f),
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package org.nsh07.pomodoro.ui.viewModel
|
||||
package org.nsh07.pomodoro.ui.settingsScreen.viewModel
|
||||
|
||||
import androidx.compose.foundation.text.input.TextFieldState
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.SliderState
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
@@ -8,6 +10,7 @@ import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.AP
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -15,7 +18,7 @@ import org.nsh07.pomodoro.TomatoApplication
|
||||
import org.nsh07.pomodoro.data.AppPreferenceRepository
|
||||
import org.nsh07.pomodoro.data.TimerRepository
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
@OptIn(FlowPreview::class, ExperimentalMaterial3Api::class)
|
||||
class SettingsViewModel(
|
||||
private val preferenceRepository: AppPreferenceRepository,
|
||||
private val timerRepository: TimerRepository
|
||||
@@ -27,8 +30,15 @@ class SettingsViewModel(
|
||||
val longBreakTimeTextFieldState =
|
||||
TextFieldState((timerRepository.longBreakTime / 60000).toString())
|
||||
|
||||
val sessionsSliderState = SliderState(
|
||||
value = timerRepository.sessionLength.toFloat(),
|
||||
steps = 4,
|
||||
valueRange = 1f..6f,
|
||||
onValueChangeFinished = ::updateSessionLength
|
||||
)
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
snapshotFlow { focusTimeTextFieldState.text }
|
||||
.debounce(500)
|
||||
.collect {
|
||||
@@ -39,6 +49,8 @@ class SettingsViewModel(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
snapshotFlow { shortBreakTimeTextFieldState.text }
|
||||
.debounce(500)
|
||||
.collect {
|
||||
@@ -49,6 +61,8 @@ class SettingsViewModel(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
snapshotFlow { longBreakTimeTextFieldState.text }
|
||||
.debounce(500)
|
||||
.collect {
|
||||
@@ -62,6 +76,15 @@ class SettingsViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSessionLength() {
|
||||
viewModelScope.launch {
|
||||
timerRepository.sessionLength = preferenceRepository.saveIntPreference(
|
||||
"session_length",
|
||||
sessionsSliderState.value.toInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
@@ -53,13 +53,13 @@ import org.nsh07.pomodoro.R
|
||||
import org.nsh07.pomodoro.ui.theme.AppFonts.openRundeClock
|
||||
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTitle
|
||||
import org.nsh07.pomodoro.ui.theme.TomatoTheme
|
||||
import org.nsh07.pomodoro.ui.viewModel.TimerMode
|
||||
import org.nsh07.pomodoro.ui.viewModel.UiState
|
||||
import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerMode
|
||||
import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerState
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
fun TimerScreen(
|
||||
uiState: UiState,
|
||||
timerState: TimerState,
|
||||
showBrandTitle: Boolean,
|
||||
progress: () -> Float,
|
||||
resetTimer: () -> Unit,
|
||||
@@ -70,17 +70,17 @@ fun TimerScreen(
|
||||
val motionScheme = motionScheme
|
||||
|
||||
val color by animateColorAsState(
|
||||
if (uiState.timerMode == TimerMode.FOCUS) colorScheme.primary
|
||||
if (timerState.timerMode == TimerMode.FOCUS) colorScheme.primary
|
||||
else colorScheme.tertiary,
|
||||
animationSpec = motionScheme.slowEffectsSpec()
|
||||
)
|
||||
val onColor by animateColorAsState(
|
||||
if (uiState.timerMode == TimerMode.FOCUS) colorScheme.onPrimary
|
||||
if (timerState.timerMode == TimerMode.FOCUS) colorScheme.onPrimary
|
||||
else colorScheme.onTertiary,
|
||||
animationSpec = motionScheme.slowEffectsSpec()
|
||||
)
|
||||
val colorContainer by animateColorAsState(
|
||||
if (uiState.timerMode == TimerMode.FOCUS) colorScheme.secondaryContainer
|
||||
if (timerState.timerMode == TimerMode.FOCUS) colorScheme.secondaryContainer
|
||||
else colorScheme.tertiaryContainer,
|
||||
animationSpec = motionScheme.slowEffectsSpec()
|
||||
)
|
||||
@@ -89,7 +89,7 @@ fun TimerScreen(
|
||||
TopAppBar(
|
||||
title = {
|
||||
AnimatedContent(
|
||||
if (!showBrandTitle) uiState.timerMode else TimerMode.BRAND,
|
||||
if (!showBrandTitle) timerState.timerMode else TimerMode.BRAND,
|
||||
transitionSpec = {
|
||||
slideInVertically(
|
||||
animationSpec = motionScheme.slowSpatialSpec(),
|
||||
@@ -166,7 +166,7 @@ fun TimerScreen(
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Box(contentAlignment = Alignment.Center) {
|
||||
if (uiState.timerMode == TimerMode.FOCUS) {
|
||||
if (timerState.timerMode == TimerMode.FOCUS) {
|
||||
CircularProgressIndicator(
|
||||
progress = progress,
|
||||
modifier = Modifier
|
||||
@@ -204,7 +204,7 @@ fun TimerScreen(
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = uiState.timeStr,
|
||||
text = timerState.timeStr,
|
||||
style = TextStyle(
|
||||
fontFamily = openRundeClock,
|
||||
fontWeight = FontWeight.Bold,
|
||||
@@ -246,7 +246,7 @@ fun TimerScreen(
|
||||
{
|
||||
FilledIconToggleButton(
|
||||
onCheckedChange = { toggleTimer() },
|
||||
checked = uiState.timerRunning,
|
||||
checked = timerState.timerRunning,
|
||||
colors = IconButtonDefaults.filledIconToggleButtonColors(
|
||||
checkedContainerColor = color,
|
||||
checkedContentColor = onColor
|
||||
@@ -257,7 +257,7 @@ fun TimerScreen(
|
||||
.size(width = 128.dp, height = 96.dp)
|
||||
.animateWidth(interactionSources[0])
|
||||
) {
|
||||
if (uiState.timerRunning) {
|
||||
if (timerState.timerRunning) {
|
||||
Icon(
|
||||
painterResource(R.drawable.pause_large),
|
||||
contentDescription = "Pause",
|
||||
@@ -275,7 +275,7 @@ fun TimerScreen(
|
||||
{ state ->
|
||||
DropdownMenuItem(
|
||||
leadingIcon = {
|
||||
if (uiState.timerRunning) {
|
||||
if (timerState.timerRunning) {
|
||||
Icon(
|
||||
painterResource(R.drawable.pause),
|
||||
contentDescription = "Pause"
|
||||
@@ -287,7 +287,7 @@ fun TimerScreen(
|
||||
)
|
||||
}
|
||||
},
|
||||
text = { Text(if (uiState.timerRunning) "Pause" else "Play") },
|
||||
text = { Text(if (timerState.timerRunning) "Pause" else "Play") },
|
||||
onClick = {
|
||||
toggleTimer()
|
||||
state.dismiss()
|
||||
@@ -377,17 +377,17 @@ fun TimerScreen(
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text("Up next", style = typography.titleSmall)
|
||||
Text(
|
||||
uiState.nextTimeStr,
|
||||
timerState.nextTimeStr,
|
||||
style = TextStyle(
|
||||
fontFamily = openRundeClock,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 22.sp,
|
||||
lineHeight = 28.sp,
|
||||
color = if (uiState.nextTimerMode == TimerMode.FOCUS) colorScheme.primary else colorScheme.tertiary
|
||||
color = if (timerState.nextTimerMode == TimerMode.FOCUS) colorScheme.primary else colorScheme.tertiary
|
||||
)
|
||||
)
|
||||
Text(
|
||||
when (uiState.nextTimerMode) {
|
||||
when (timerState.nextTimerMode) {
|
||||
TimerMode.FOCUS -> "Focus"
|
||||
TimerMode.SHORT_BREAK -> "Short Break"
|
||||
else -> "Long Break"
|
||||
@@ -405,12 +405,12 @@ fun TimerScreen(
|
||||
)
|
||||
@Composable
|
||||
fun TimerScreenPreview() {
|
||||
val uiState = UiState(
|
||||
val timerState = TimerState(
|
||||
timeStr = "03:34", nextTimeStr = "5:00", timerMode = TimerMode.FOCUS, timerRunning = true
|
||||
)
|
||||
TomatoTheme {
|
||||
TimerScreen(
|
||||
uiState,
|
||||
timerState,
|
||||
false,
|
||||
{ 0.3f },
|
||||
{},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package org.nsh07.pomodoro.ui.viewModel
|
||||
package org.nsh07.pomodoro.ui.timerScreen.viewModel
|
||||
|
||||
data class UiState(
|
||||
data class TimerState(
|
||||
val timerMode: TimerMode = TimerMode.FOCUS,
|
||||
val timeStr: String = "25:00",
|
||||
val totalTime: Int = 25 * 60,
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.nsh07.pomodoro.ui.viewModel
|
||||
package org.nsh07.pomodoro.ui.timerScreen.viewModel
|
||||
|
||||
import android.os.SystemClock
|
||||
import androidx.lifecycle.ViewModel
|
||||
@@ -34,19 +34,21 @@ class TimerViewModel(
|
||||
?: preferenceRepository.saveIntPreference("short_break_time", timerRepository.shortBreakTime)
|
||||
timerRepository.longBreakTime = preferenceRepository.getIntPreference("long_break_time")
|
||||
?: preferenceRepository.saveIntPreference("long_break_time", timerRepository.longBreakTime)
|
||||
timerRepository.sessionLength = preferenceRepository.getIntPreference("session_length")
|
||||
?: preferenceRepository.saveIntPreference("session_length", timerRepository.sessionLength)
|
||||
|
||||
resetTimer()
|
||||
}
|
||||
}
|
||||
|
||||
private val _uiState = MutableStateFlow(
|
||||
UiState(
|
||||
private val _timerState = MutableStateFlow(
|
||||
TimerState(
|
||||
totalTime = timerRepository.focusTime,
|
||||
timeStr = millisecondsToStr(timerRepository.focusTime),
|
||||
nextTimeStr = millisecondsToStr(timerRepository.shortBreakTime)
|
||||
)
|
||||
)
|
||||
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
|
||||
val timerState: StateFlow<TimerState> = _timerState.asStateFlow()
|
||||
var timerJob: Job? = null
|
||||
|
||||
private val _time = MutableStateFlow(timerRepository.focusTime)
|
||||
@@ -64,7 +66,7 @@ class TimerViewModel(
|
||||
pauseTime = 0L
|
||||
pauseDuration = 0L
|
||||
|
||||
_uiState.update { currentState ->
|
||||
_timerState.update { currentState ->
|
||||
currentState.copy(
|
||||
timerMode = TimerMode.FOCUS,
|
||||
timeStr = millisecondsToStr(time.value),
|
||||
@@ -79,11 +81,11 @@ class TimerViewModel(
|
||||
startTime = 0L
|
||||
pauseTime = 0L
|
||||
pauseDuration = 0L
|
||||
cycles = (cycles + 1) % 8
|
||||
cycles = (cycles + 1) % (timerRepository.sessionLength * 2)
|
||||
|
||||
if (cycles % 2 == 0) {
|
||||
_time.update { timerRepository.focusTime }
|
||||
_uiState.update { currentState ->
|
||||
_timerState.update { currentState ->
|
||||
currentState.copy(
|
||||
timerMode = TimerMode.FOCUS,
|
||||
timeStr = millisecondsToStr(time.value),
|
||||
@@ -97,10 +99,10 @@ class TimerViewModel(
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val long = cycles == 7
|
||||
val long = cycles == (timerRepository.sessionLength * 2) - 1
|
||||
_time.update { if (long) timerRepository.longBreakTime else timerRepository.shortBreakTime }
|
||||
|
||||
_uiState.update { currentState ->
|
||||
_timerState.update { currentState ->
|
||||
currentState.copy(
|
||||
timerMode = if (long) TimerMode.LONG_BREAK else TimerMode.SHORT_BREAK,
|
||||
timeStr = millisecondsToStr(time.value),
|
||||
@@ -113,23 +115,23 @@ class TimerViewModel(
|
||||
}
|
||||
|
||||
fun toggleTimer() {
|
||||
if (uiState.value.timerRunning) {
|
||||
_uiState.update { currentState ->
|
||||
if (timerState.value.timerRunning) {
|
||||
_timerState.update { currentState ->
|
||||
currentState.copy(timerRunning = false)
|
||||
}
|
||||
timerJob?.cancel()
|
||||
pauseTime = SystemClock.elapsedRealtime()
|
||||
} else {
|
||||
_uiState.update { it.copy(timerRunning = true) }
|
||||
_timerState.update { it.copy(timerRunning = true) }
|
||||
if (pauseTime != 0L) pauseDuration += SystemClock.elapsedRealtime() - pauseTime
|
||||
|
||||
timerJob = viewModelScope.launch {
|
||||
while (true) {
|
||||
if (!uiState.value.timerRunning) break
|
||||
if (!timerState.value.timerRunning) break
|
||||
if (startTime == 0L) startTime = SystemClock.elapsedRealtime()
|
||||
|
||||
_time.update {
|
||||
when (uiState.value.timerMode) {
|
||||
when (timerState.value.timerMode) {
|
||||
TimerMode.FOCUS ->
|
||||
timerRepository.focusTime - (SystemClock.elapsedRealtime() - startTime - pauseDuration).toInt()
|
||||
|
||||
@@ -144,12 +146,12 @@ class TimerViewModel(
|
||||
if (time.value < 0) {
|
||||
skipTimer()
|
||||
|
||||
_uiState.update { currentState ->
|
||||
_timerState.update { currentState ->
|
||||
currentState.copy(timerRunning = false)
|
||||
}
|
||||
timerJob?.cancel()
|
||||
} else {
|
||||
_uiState.update { currentState ->
|
||||
_timerState.update { currentState ->
|
||||
currentState.copy(
|
||||
timeStr = millisecondsToStr(time.value)
|
||||
)
|
||||
10
app/src/main/res/drawable/info.xml
Normal file
10
app/src/main/res/drawable/info.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#000000"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M480,680q17,0 28.5,-11.5T520,640v-160q0,-17 -11.5,-28.5T480,440q-17,0 -28.5,11.5T440,480v160q0,17 11.5,28.5T480,680ZM480,360q17,0 28.5,-11.5T520,320q0,-17 -11.5,-28.5T480,280q-17,0 -28.5,11.5T440,320q0,17 11.5,28.5T480,360ZM480,880q-83,0 -156,-31.5T197,763q-54,-54 -85.5,-127T80,480q0,-83 31.5,-156T197,197q54,-54 127,-85.5T480,80q83,0 156,31.5T763,197q54,54 85.5,127T880,480q0,83 -31.5,156T763,763q-54,54 -127,85.5T480,880Z" />
|
||||
</vector>
|
||||
Reference in New Issue
Block a user