Animate progress

This commit is contained in:
Nishant Mishra
2025-06-29 19:42:57 +05:30
parent 41995776f9
commit f59bb5600c
4 changed files with 41 additions and 34 deletions

View File

@@ -4,6 +4,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import org.nsh07.pomodoro.ui.timerScreen.TimerScreen
@@ -16,6 +17,15 @@ fun AppScreen(
modifier: Modifier = Modifier
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
val remainingTime by viewModel.time.collectAsStateWithLifecycle()
TimerScreen(uiState = uiState, resetTimer = viewModel::resetTimer, toggleTimer = viewModel::toggleTimer, modifier = modifier)
val progress by rememberUpdatedState((uiState.totalTime.toFloat() - remainingTime) / uiState.totalTime)
TimerScreen(
uiState = uiState,
progress = { progress },
resetTimer = viewModel::resetTimer,
toggleTimer = viewModel::toggleTimer,
modifier = modifier
)
}

View File

@@ -49,6 +49,7 @@ import org.nsh07.pomodoro.ui.viewModel.UiState
@Composable
fun TimerScreen(
uiState: UiState,
progress: () -> Float,
resetTimer: () -> Unit,
toggleTimer: () -> Unit,
modifier: Modifier = Modifier
@@ -144,7 +145,7 @@ fun TimerScreen(
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Box(contentAlignment = Alignment.Center) {
CircularProgressIndicator(
progress = { (uiState.totalTime.toFloat() - uiState.remainingTime) / uiState.totalTime },
progress = progress,
modifier = Modifier.size(350.dp),
color = color,
trackColor = colorContainer,
@@ -238,5 +239,5 @@ fun TimerScreenPreview() {
val uiState = UiState(
timeStr = "08:34", nextTimeStr = "5:00"
)
TimerScreen(uiState, {}, {})
TimerScreen(uiState, { 0.3f }, {}, {})
}

View File

@@ -4,7 +4,6 @@ data class UiState(
val timerMode: TimerMode = TimerMode.FOCUS,
val timeStr: String = "25:00",
val totalTime: Int = 25 * 60,
val remainingTime: Int = 25 * 60,
val timerRunning: Boolean = false,
val nextTimerMode: TimerMode = TimerMode.SHORT_BREAK,
val nextTimeStr: String = "5:00"

View File

@@ -12,36 +12,36 @@ import kotlinx.coroutines.launch
import java.util.Locale
class UiViewModel : ViewModel() {
val focusTime = 10
val shortBreakTime = 5
val longBreakTime = 20
val focusTime = 10000
val shortBreakTime = 5000
val longBreakTime = 20000
private val _uiState = MutableStateFlow(
UiState(
totalTime = focusTime,
remainingTime = focusTime,
timeStr = secondsToStr(focusTime),
nextTimeStr = secondsToStr(shortBreakTime)
timeStr = millisecondsToStr(focusTime),
nextTimeStr = millisecondsToStr(shortBreakTime)
)
)
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
var timerJob: Job? = null
var time = focusTime
private val _time = MutableStateFlow(focusTime)
val time: StateFlow<Int> = _time.asStateFlow()
var cycles = 0
fun resetTimer() {
time = focusTime
_time.update { focusTime }
cycles = 0
_uiState.update { currentState ->
currentState.copy(
timerMode = TimerMode.FOCUS,
timeStr = secondsToStr(time),
totalTime = time,
remainingTime = time,
timeStr = millisecondsToStr(time.value),
totalTime = time.value,
nextTimerMode = TimerMode.SHORT_BREAK,
nextTimeStr = secondsToStr(shortBreakTime)
nextTimeStr = millisecondsToStr(shortBreakTime)
)
}
}
@@ -57,58 +57,55 @@ class UiViewModel : ViewModel() {
timerJob = viewModelScope.launch {
while (true) {
if (!uiState.value.timerRunning) break
time--
_time.update { it - 10 }
if (time < 0) {
if (time.value < 0) {
cycles++
if (cycles % 2 == 0) {
time = focusTime
_time.update { focusTime }
_uiState.update { currentState ->
currentState.copy(
timerMode = TimerMode.FOCUS,
timeStr = secondsToStr(time),
totalTime = time,
remainingTime = time,
timeStr = millisecondsToStr(time.value),
totalTime = time.value,
nextTimerMode = if (cycles % 6 == 0) TimerMode.LONG_BREAK else TimerMode.SHORT_BREAK,
nextTimeStr = if (cycles % 6 == 0) secondsToStr(longBreakTime) else secondsToStr(
nextTimeStr = if (cycles % 6 == 0) millisecondsToStr(longBreakTime) else millisecondsToStr(
shortBreakTime
)
)
}
} else {
val long = cycles % 7 == 0
time = if (long) longBreakTime else shortBreakTime
_time.update { if (long) longBreakTime else shortBreakTime }
_uiState.update { currentState ->
currentState.copy(
timerMode = if (long) TimerMode.LONG_BREAK else TimerMode.SHORT_BREAK,
timeStr = secondsToStr(time),
totalTime = time,
remainingTime = time,
timeStr = millisecondsToStr(time.value),
totalTime = time.value,
nextTimerMode = TimerMode.FOCUS,
nextTimeStr = secondsToStr(focusTime)
nextTimeStr = millisecondsToStr(focusTime)
)
}
}
} else {
_uiState.update { currentState ->
currentState.copy(
timeStr = secondsToStr(time),
remainingTime = time
timeStr = millisecondsToStr(time.value)
)
}
}
delay(1000)
delay(10)
}
}
}
}
private fun secondsToStr(t: Int): String {
val min = t / 60
val sec = t % 60
private fun millisecondsToStr(t: Int): String {
val min = (t / 1000) / 60
val sec = (t / 1000) % 60
return String.format(locale = Locale.getDefault(), "%02d:%02d", min, sec)
}
}