Animate progress
This commit is contained in:
@@ -4,6 +4,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
|||||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.rememberUpdatedState
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import org.nsh07.pomodoro.ui.timerScreen.TimerScreen
|
import org.nsh07.pomodoro.ui.timerScreen.TimerScreen
|
||||||
@@ -16,6 +17,15 @@ fun AppScreen(
|
|||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
@@ -49,6 +49,7 @@ import org.nsh07.pomodoro.ui.viewModel.UiState
|
|||||||
@Composable
|
@Composable
|
||||||
fun TimerScreen(
|
fun TimerScreen(
|
||||||
uiState: UiState,
|
uiState: UiState,
|
||||||
|
progress: () -> Float,
|
||||||
resetTimer: () -> Unit,
|
resetTimer: () -> Unit,
|
||||||
toggleTimer: () -> Unit,
|
toggleTimer: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
@@ -144,7 +145,7 @@ fun TimerScreen(
|
|||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
Box(contentAlignment = Alignment.Center) {
|
Box(contentAlignment = Alignment.Center) {
|
||||||
CircularProgressIndicator(
|
CircularProgressIndicator(
|
||||||
progress = { (uiState.totalTime.toFloat() - uiState.remainingTime) / uiState.totalTime },
|
progress = progress,
|
||||||
modifier = Modifier.size(350.dp),
|
modifier = Modifier.size(350.dp),
|
||||||
color = color,
|
color = color,
|
||||||
trackColor = colorContainer,
|
trackColor = colorContainer,
|
||||||
@@ -238,5 +239,5 @@ fun TimerScreenPreview() {
|
|||||||
val uiState = UiState(
|
val uiState = UiState(
|
||||||
timeStr = "08:34", nextTimeStr = "5:00"
|
timeStr = "08:34", nextTimeStr = "5:00"
|
||||||
)
|
)
|
||||||
TimerScreen(uiState, {}, {})
|
TimerScreen(uiState, { 0.3f }, {}, {})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ data class UiState(
|
|||||||
val timerMode: TimerMode = TimerMode.FOCUS,
|
val timerMode: TimerMode = TimerMode.FOCUS,
|
||||||
val timeStr: String = "25:00",
|
val timeStr: String = "25:00",
|
||||||
val totalTime: Int = 25 * 60,
|
val totalTime: Int = 25 * 60,
|
||||||
val remainingTime: Int = 25 * 60,
|
|
||||||
val timerRunning: Boolean = false,
|
val timerRunning: Boolean = false,
|
||||||
val nextTimerMode: TimerMode = TimerMode.SHORT_BREAK,
|
val nextTimerMode: TimerMode = TimerMode.SHORT_BREAK,
|
||||||
val nextTimeStr: String = "5:00"
|
val nextTimeStr: String = "5:00"
|
||||||
|
|||||||
@@ -12,36 +12,36 @@ import kotlinx.coroutines.launch
|
|||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
class UiViewModel : ViewModel() {
|
class UiViewModel : ViewModel() {
|
||||||
val focusTime = 10
|
val focusTime = 10000
|
||||||
val shortBreakTime = 5
|
val shortBreakTime = 5000
|
||||||
val longBreakTime = 20
|
val longBreakTime = 20000
|
||||||
|
|
||||||
private val _uiState = MutableStateFlow(
|
private val _uiState = MutableStateFlow(
|
||||||
UiState(
|
UiState(
|
||||||
totalTime = focusTime,
|
totalTime = focusTime,
|
||||||
remainingTime = focusTime,
|
timeStr = millisecondsToStr(focusTime),
|
||||||
timeStr = secondsToStr(focusTime),
|
nextTimeStr = millisecondsToStr(shortBreakTime)
|
||||||
nextTimeStr = secondsToStr(shortBreakTime)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
|
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
|
||||||
var timerJob: Job? = null
|
var timerJob: Job? = null
|
||||||
|
|
||||||
var time = focusTime
|
private val _time = MutableStateFlow(focusTime)
|
||||||
|
val time: StateFlow<Int> = _time.asStateFlow()
|
||||||
|
|
||||||
var cycles = 0
|
var cycles = 0
|
||||||
|
|
||||||
fun resetTimer() {
|
fun resetTimer() {
|
||||||
time = focusTime
|
_time.update { focusTime }
|
||||||
cycles = 0
|
cycles = 0
|
||||||
|
|
||||||
_uiState.update { currentState ->
|
_uiState.update { currentState ->
|
||||||
currentState.copy(
|
currentState.copy(
|
||||||
timerMode = TimerMode.FOCUS,
|
timerMode = TimerMode.FOCUS,
|
||||||
timeStr = secondsToStr(time),
|
timeStr = millisecondsToStr(time.value),
|
||||||
totalTime = time,
|
totalTime = time.value,
|
||||||
remainingTime = time,
|
|
||||||
nextTimerMode = TimerMode.SHORT_BREAK,
|
nextTimerMode = TimerMode.SHORT_BREAK,
|
||||||
nextTimeStr = secondsToStr(shortBreakTime)
|
nextTimeStr = millisecondsToStr(shortBreakTime)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,58 +57,55 @@ class UiViewModel : ViewModel() {
|
|||||||
timerJob = viewModelScope.launch {
|
timerJob = viewModelScope.launch {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!uiState.value.timerRunning) break
|
if (!uiState.value.timerRunning) break
|
||||||
time--
|
_time.update { it - 10 }
|
||||||
|
|
||||||
if (time < 0) {
|
if (time.value < 0) {
|
||||||
cycles++
|
cycles++
|
||||||
|
|
||||||
if (cycles % 2 == 0) {
|
if (cycles % 2 == 0) {
|
||||||
time = focusTime
|
_time.update { focusTime }
|
||||||
_uiState.update { currentState ->
|
_uiState.update { currentState ->
|
||||||
currentState.copy(
|
currentState.copy(
|
||||||
timerMode = TimerMode.FOCUS,
|
timerMode = TimerMode.FOCUS,
|
||||||
timeStr = secondsToStr(time),
|
timeStr = millisecondsToStr(time.value),
|
||||||
totalTime = time,
|
totalTime = time.value,
|
||||||
remainingTime = time,
|
|
||||||
nextTimerMode = if (cycles % 6 == 0) TimerMode.LONG_BREAK else TimerMode.SHORT_BREAK,
|
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
|
shortBreakTime
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val long = cycles % 7 == 0
|
val long = cycles % 7 == 0
|
||||||
time = if (long) longBreakTime else shortBreakTime
|
_time.update { if (long) longBreakTime else shortBreakTime }
|
||||||
|
|
||||||
_uiState.update { currentState ->
|
_uiState.update { currentState ->
|
||||||
currentState.copy(
|
currentState.copy(
|
||||||
timerMode = if (long) TimerMode.LONG_BREAK else TimerMode.SHORT_BREAK,
|
timerMode = if (long) TimerMode.LONG_BREAK else TimerMode.SHORT_BREAK,
|
||||||
timeStr = secondsToStr(time),
|
timeStr = millisecondsToStr(time.value),
|
||||||
totalTime = time,
|
totalTime = time.value,
|
||||||
remainingTime = time,
|
|
||||||
nextTimerMode = TimerMode.FOCUS,
|
nextTimerMode = TimerMode.FOCUS,
|
||||||
nextTimeStr = secondsToStr(focusTime)
|
nextTimeStr = millisecondsToStr(focusTime)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_uiState.update { currentState ->
|
_uiState.update { currentState ->
|
||||||
currentState.copy(
|
currentState.copy(
|
||||||
timeStr = secondsToStr(time),
|
timeStr = millisecondsToStr(time.value)
|
||||||
remainingTime = time
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(1000)
|
delay(10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun secondsToStr(t: Int): String {
|
private fun millisecondsToStr(t: Int): String {
|
||||||
val min = t / 60
|
val min = (t / 1000) / 60
|
||||||
val sec = t % 60
|
val sec = (t / 1000) % 60
|
||||||
return String.format(locale = Locale.getDefault(), "%02d:%02d", min, sec)
|
return String.format(locale = Locale.getDefault(), "%02d:%02d", min, sec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user