feat: Save time to database when timer state changes
This commit is contained in:
@@ -10,14 +10,14 @@ package org.nsh07.pomodoro.data
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
|
||||||
interface AppContainer {
|
interface AppContainer {
|
||||||
val appPreferencesRepository: AppPreferenceRepository
|
val appPreferenceRepository: AppPreferenceRepository
|
||||||
val appStatRepository: AppStatRepository
|
val appStatRepository: AppStatRepository
|
||||||
val appTimerRepository: AppTimerRepository
|
val appTimerRepository: AppTimerRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
class DefaultAppContainer(context: Context) : AppContainer {
|
class DefaultAppContainer(context: Context) : AppContainer {
|
||||||
|
|
||||||
override val appPreferencesRepository: AppPreferenceRepository by lazy {
|
override val appPreferenceRepository: AppPreferenceRepository by lazy {
|
||||||
AppPreferenceRepository(AppDatabase.getDatabase(context).preferenceDao())
|
AppPreferenceRepository(AppDatabase.getDatabase(context).preferenceDao())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import kotlinx.coroutines.CoroutineDispatcher
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
interface PreferencesRepository {
|
interface PreferenceRepository {
|
||||||
suspend fun saveIntPreference(key: String, value: Int): Int
|
suspend fun saveIntPreference(key: String, value: Int): Int
|
||||||
|
|
||||||
suspend fun getIntPreference(key: String): Int?
|
suspend fun getIntPreference(key: String): Int?
|
||||||
@@ -15,7 +15,7 @@ interface PreferencesRepository {
|
|||||||
class AppPreferenceRepository(
|
class AppPreferenceRepository(
|
||||||
private val preferenceDao: PreferenceDao,
|
private val preferenceDao: PreferenceDao,
|
||||||
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
|
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||||
) : PreferencesRepository {
|
) : PreferenceRepository {
|
||||||
override suspend fun saveIntPreference(key: String, value: Int): Int =
|
override suspend fun saveIntPreference(key: String, value: Int): Int =
|
||||||
withContext(ioDispatcher) {
|
withContext(ioDispatcher) {
|
||||||
preferenceDao.insertIntPreference(IntPreference(key, value))
|
preferenceDao.insertIntPreference(IntPreference(key, value))
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2025 Nishant Mishra
|
* Copyright (c) 2025 Nishant Mishra
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.nsh07.pomodoro.data
|
package org.nsh07.pomodoro.data
|
||||||
@@ -14,6 +14,9 @@ import androidx.room.PrimaryKey
|
|||||||
data class Stat(
|
data class Stat(
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
val date: String,
|
val date: String,
|
||||||
val focusTime: Int,
|
val focusTimeQ1: Long,
|
||||||
val breakTime: Int
|
val focusTimeQ2: Long,
|
||||||
|
val focusTimeQ3: Long,
|
||||||
|
val focusTimeQ4: Long,
|
||||||
|
val breakTime: Long
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -18,11 +18,20 @@ interface StatDao {
|
|||||||
@Insert(onConflict = REPLACE)
|
@Insert(onConflict = REPLACE)
|
||||||
suspend fun insertStat(stat: Stat)
|
suspend fun insertStat(stat: Stat)
|
||||||
|
|
||||||
@Query("UPDATE stat SET focusTime = focusTime + :focusTime WHERE date = :date")
|
@Query("UPDATE stat SET focusTimeQ1 = focusTimeQ1 + :focusTime WHERE date = :date")
|
||||||
suspend fun addFocusTime(date: String, focusTime: Int)
|
suspend fun addFocusTimeQ1(date: String, focusTime: Long)
|
||||||
|
|
||||||
|
@Query("UPDATE stat SET focusTimeQ2 = focusTimeQ2 + :focusTime WHERE date = :date")
|
||||||
|
suspend fun addFocusTimeQ2(date: String, focusTime: Long)
|
||||||
|
|
||||||
|
@Query("UPDATE stat SET focusTimeQ3 = focusTimeQ3 + :focusTime WHERE date = :date")
|
||||||
|
suspend fun addFocusTimeQ3(date: String, focusTime: Long)
|
||||||
|
|
||||||
|
@Query("UPDATE stat SET focusTimeQ4 = focusTimeQ4 + :focusTime WHERE date = :date")
|
||||||
|
suspend fun addFocusTimeQ4(date: String, focusTime: Long)
|
||||||
|
|
||||||
@Query("UPDATE stat SET breakTime = breakTime + :breakTime WHERE date = :date")
|
@Query("UPDATE stat SET breakTime = breakTime + :breakTime WHERE date = :date")
|
||||||
suspend fun addBreakTime(date: String, breakTime: Int)
|
suspend fun addBreakTime(date: String, breakTime: Long)
|
||||||
|
|
||||||
@Query("SELECT * FROM stat WHERE date = :date")
|
@Query("SELECT * FROM stat WHERE date = :date")
|
||||||
fun getStat(date: String): Flow<Stat?>
|
fun getStat(date: String): Flow<Stat?>
|
||||||
|
|||||||
@@ -12,11 +12,12 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
|
import java.time.LocalTime
|
||||||
|
|
||||||
interface StatRepository {
|
interface StatRepository {
|
||||||
suspend fun addFocusTime(focusTime: Int)
|
suspend fun addFocusTime(focusTime: Long)
|
||||||
|
|
||||||
suspend fun addBreakTime(breakTime: Int)
|
suspend fun addBreakTime(breakTime: Long)
|
||||||
|
|
||||||
fun getTodayStat(): Flow<Stat?>
|
fun getTodayStat(): Flow<Stat?>
|
||||||
|
|
||||||
@@ -27,21 +28,55 @@ class AppStatRepository(
|
|||||||
private val statDao: StatDao,
|
private val statDao: StatDao,
|
||||||
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
|
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||||
) : StatRepository {
|
) : StatRepository {
|
||||||
override suspend fun addFocusTime(focusTime: Int) = withContext(ioDispatcher) {
|
override suspend fun addFocusTime(focusTime: Long) = withContext(ioDispatcher) {
|
||||||
val currentDate = LocalDate.now().toString()
|
val currentDate = LocalDate.now().toString()
|
||||||
|
val currentTime = LocalTime.now().toSecondOfDay()
|
||||||
|
val secondsInDay = 24 * 60 * 60
|
||||||
|
|
||||||
if (statDao.statExists(currentDate)) {
|
if (statDao.statExists(currentDate)) {
|
||||||
statDao.addFocusTime(currentDate, focusTime)
|
when (currentTime) {
|
||||||
|
in 0..(secondsInDay / 4) ->
|
||||||
|
statDao.addFocusTimeQ1(currentDate, focusTime)
|
||||||
|
|
||||||
|
in (secondsInDay / 4)..(secondsInDay / 2) ->
|
||||||
|
statDao.addFocusTimeQ2(currentDate, focusTime)
|
||||||
|
|
||||||
|
in (secondsInDay / 2)..(3 * secondsInDay / 4) ->
|
||||||
|
statDao.addFocusTimeQ3(currentDate, focusTime)
|
||||||
|
|
||||||
|
else -> statDao.addFocusTimeQ4(currentDate, focusTime)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
statDao.insertStat(Stat(currentDate, focusTime, 0))
|
when (currentTime) {
|
||||||
|
in 0..(secondsInDay / 4) ->
|
||||||
|
statDao.insertStat(
|
||||||
|
Stat(currentDate, focusTime, 0, 0, 0, 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
in (secondsInDay / 4)..(secondsInDay / 2) ->
|
||||||
|
statDao.insertStat(
|
||||||
|
Stat(currentDate, 0, focusTime, 0, 0, 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
in (secondsInDay / 2)..(3 * secondsInDay / 4) ->
|
||||||
|
statDao.insertStat(
|
||||||
|
Stat(currentDate, 0, 0, focusTime, 0, 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
else ->
|
||||||
|
statDao.insertStat(
|
||||||
|
Stat(currentDate, 0, 0, 0, focusTime, 0)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun addBreakTime(breakTime: Int) = withContext(ioDispatcher) {
|
override suspend fun addBreakTime(breakTime: Long) = withContext(ioDispatcher) {
|
||||||
val currentDate = LocalDate.now().toString()
|
val currentDate = LocalDate.now().toString()
|
||||||
if (statDao.statExists(currentDate)) {
|
if (statDao.statExists(currentDate)) {
|
||||||
statDao.addBreakTime(currentDate, breakTime)
|
statDao.addBreakTime(currentDate, breakTime)
|
||||||
} else {
|
} else {
|
||||||
statDao.insertStat(Stat(currentDate, 0, breakTime))
|
statDao.insertStat(Stat(currentDate, 0, 0, 0, 0, breakTime))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Nishant Mishra
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.nsh07.pomodoro.data
|
package org.nsh07.pomodoro.data
|
||||||
|
|
||||||
interface TimerRepository {
|
interface TimerRepository {
|
||||||
var focusTime: Int
|
var focusTime: Long
|
||||||
var shortBreakTime: Int
|
var shortBreakTime: Long
|
||||||
var longBreakTime: Int
|
var longBreakTime: Long
|
||||||
var sessionLength: Int
|
var sessionLength: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppTimerRepository : TimerRepository {
|
class AppTimerRepository : TimerRepository {
|
||||||
override var focusTime = 25 * 60 * 1000
|
override var focusTime = 25 * 60 * 1000L
|
||||||
override var shortBreakTime = 5 * 60 * 1000
|
override var shortBreakTime = 5 * 60 * 1000L
|
||||||
override var longBreakTime = 15 * 60 * 1000
|
override var longBreakTime = 15 * 60 * 1000L
|
||||||
override var sessionLength = 4
|
override var sessionLength = 4
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Nishant Mishra
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.nsh07.pomodoro.ui.settingsScreen.viewModel
|
package org.nsh07.pomodoro.ui.settingsScreen.viewModel
|
||||||
|
|
||||||
import androidx.compose.foundation.text.input.TextFieldState
|
import androidx.compose.foundation.text.input.TextFieldState
|
||||||
@@ -46,7 +53,7 @@ class SettingsViewModel(
|
|||||||
timerRepository.focusTime = preferenceRepository.saveIntPreference(
|
timerRepository.focusTime = preferenceRepository.saveIntPreference(
|
||||||
"focus_time",
|
"focus_time",
|
||||||
it.toString().toInt() * 60 * 1000
|
it.toString().toInt() * 60 * 1000
|
||||||
)
|
).toLong()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,7 +65,7 @@ class SettingsViewModel(
|
|||||||
timerRepository.shortBreakTime = preferenceRepository.saveIntPreference(
|
timerRepository.shortBreakTime = preferenceRepository.saveIntPreference(
|
||||||
"short_break_time",
|
"short_break_time",
|
||||||
it.toString().toInt() * 60 * 1000
|
it.toString().toInt() * 60 * 1000
|
||||||
)
|
).toLong()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,7 +77,7 @@ class SettingsViewModel(
|
|||||||
timerRepository.longBreakTime = preferenceRepository.saveIntPreference(
|
timerRepository.longBreakTime = preferenceRepository.saveIntPreference(
|
||||||
"long_break_time",
|
"long_break_time",
|
||||||
it.toString().toInt() * 60 * 1000
|
it.toString().toInt() * 60 * 1000
|
||||||
)
|
).toLong()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,7 +96,7 @@ class SettingsViewModel(
|
|||||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||||
initializer {
|
initializer {
|
||||||
val application = (this[APPLICATION_KEY] as TomatoApplication)
|
val application = (this[APPLICATION_KEY] as TomatoApplication)
|
||||||
val appPreferenceRepository = application.container.appPreferencesRepository
|
val appPreferenceRepository = application.container.appPreferenceRepository
|
||||||
val appTimerRepository = application.container.appTimerRepository
|
val appTimerRepository = application.container.appTimerRepository
|
||||||
|
|
||||||
SettingsViewModel(
|
SettingsViewModel(
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Nishant Mishra
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.nsh07.pomodoro.ui.timerScreen.viewModel
|
package org.nsh07.pomodoro.ui.timerScreen.viewModel
|
||||||
|
|
||||||
data class TimerState(
|
data class TimerState(
|
||||||
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: Long = 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"
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Nishant Mishra
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.nsh07.pomodoro.ui.timerScreen.viewModel
|
package org.nsh07.pomodoro.ui.timerScreen.viewModel
|
||||||
|
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
@@ -17,30 +24,18 @@ import kotlinx.coroutines.flow.asStateFlow
|
|||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.nsh07.pomodoro.TomatoApplication
|
import org.nsh07.pomodoro.TomatoApplication
|
||||||
import org.nsh07.pomodoro.data.AppPreferenceRepository
|
import org.nsh07.pomodoro.data.PreferenceRepository
|
||||||
|
import org.nsh07.pomodoro.data.StatRepository
|
||||||
import org.nsh07.pomodoro.data.TimerRepository
|
import org.nsh07.pomodoro.data.TimerRepository
|
||||||
import org.nsh07.pomodoro.utils.millisecondsToStr
|
import org.nsh07.pomodoro.utils.millisecondsToStr
|
||||||
|
|
||||||
@OptIn(FlowPreview::class)
|
@OptIn(FlowPreview::class)
|
||||||
class TimerViewModel(
|
class TimerViewModel(
|
||||||
private val preferenceRepository: AppPreferenceRepository,
|
private val preferenceRepository: PreferenceRepository,
|
||||||
|
private val statRepository: StatRepository,
|
||||||
private val timerRepository: TimerRepository
|
private val timerRepository: TimerRepository
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
init {
|
// TODO: Document code
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
|
||||||
timerRepository.focusTime = preferenceRepository.getIntPreference("focus_time")
|
|
||||||
?: preferenceRepository.saveIntPreference("focus_time", timerRepository.focusTime)
|
|
||||||
timerRepository.shortBreakTime = preferenceRepository.getIntPreference("short_break_time")
|
|
||||||
?: 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 _timerState = MutableStateFlow(
|
private val _timerState = MutableStateFlow(
|
||||||
TimerState(
|
TimerState(
|
||||||
totalTime = timerRepository.focusTime,
|
totalTime = timerRepository.focusTime,
|
||||||
@@ -48,68 +43,106 @@ class TimerViewModel(
|
|||||||
nextTimeStr = millisecondsToStr(timerRepository.shortBreakTime)
|
nextTimeStr = millisecondsToStr(timerRepository.shortBreakTime)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val timerState: StateFlow<TimerState> = _timerState.asStateFlow()
|
val timerState: StateFlow<TimerState> = _timerState.asStateFlow()
|
||||||
var timerJob: Job? = null
|
var timerJob: Job? = null
|
||||||
|
|
||||||
private val _time = MutableStateFlow(timerRepository.focusTime)
|
private val _time = MutableStateFlow(timerRepository.focusTime)
|
||||||
val time: StateFlow<Int> = _time.asStateFlow()
|
|
||||||
|
|
||||||
|
val time: StateFlow<Long> = _time.asStateFlow()
|
||||||
private var cycles = 0
|
private var cycles = 0
|
||||||
|
|
||||||
private var startTime = 0L
|
private var startTime = 0L
|
||||||
private var pauseTime = 0L
|
private var pauseTime = 0L
|
||||||
private var pauseDuration = 0L
|
private var pauseDuration = 0L
|
||||||
|
|
||||||
fun resetTimer() {
|
init {
|
||||||
_time.update { timerRepository.focusTime }
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
cycles = 0
|
timerRepository.focusTime =
|
||||||
startTime = 0L
|
preferenceRepository.getIntPreference("focus_time")?.toLong()
|
||||||
pauseTime = 0L
|
?: preferenceRepository.saveIntPreference(
|
||||||
pauseDuration = 0L
|
"focus_time",
|
||||||
|
timerRepository.focusTime.toInt()
|
||||||
|
).toLong()
|
||||||
|
timerRepository.shortBreakTime =
|
||||||
|
preferenceRepository.getIntPreference("short_break_time")?.toLong()
|
||||||
|
?: preferenceRepository.saveIntPreference(
|
||||||
|
"short_break_time",
|
||||||
|
timerRepository.shortBreakTime.toInt()
|
||||||
|
).toLong()
|
||||||
|
timerRepository.longBreakTime =
|
||||||
|
preferenceRepository.getIntPreference("long_break_time")?.toLong()
|
||||||
|
?: preferenceRepository.saveIntPreference(
|
||||||
|
"long_break_time",
|
||||||
|
timerRepository.longBreakTime.toInt()
|
||||||
|
).toLong()
|
||||||
|
timerRepository.sessionLength = preferenceRepository.getIntPreference("session_length")
|
||||||
|
?: preferenceRepository.saveIntPreference(
|
||||||
|
"session_length",
|
||||||
|
timerRepository.sessionLength
|
||||||
|
)
|
||||||
|
|
||||||
_timerState.update { currentState ->
|
resetTimer()
|
||||||
currentState.copy(
|
|
||||||
timerMode = TimerMode.FOCUS,
|
|
||||||
timeStr = millisecondsToStr(time.value),
|
|
||||||
totalTime = time.value,
|
|
||||||
nextTimerMode = TimerMode.SHORT_BREAK,
|
|
||||||
nextTimeStr = millisecondsToStr(timerRepository.shortBreakTime)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun skipTimer() {
|
fun resetTimer() {
|
||||||
startTime = 0L
|
viewModelScope.launch {
|
||||||
pauseTime = 0L
|
saveTimeToDb()
|
||||||
pauseDuration = 0L
|
|
||||||
cycles = (cycles + 1) % (timerRepository.sessionLength * 2)
|
|
||||||
|
|
||||||
if (cycles % 2 == 0) {
|
|
||||||
_time.update { timerRepository.focusTime }
|
_time.update { timerRepository.focusTime }
|
||||||
|
cycles = 0
|
||||||
|
startTime = 0L
|
||||||
|
pauseTime = 0L
|
||||||
|
pauseDuration = 0L
|
||||||
|
|
||||||
_timerState.update { currentState ->
|
_timerState.update { currentState ->
|
||||||
currentState.copy(
|
currentState.copy(
|
||||||
timerMode = TimerMode.FOCUS,
|
timerMode = TimerMode.FOCUS,
|
||||||
timeStr = millisecondsToStr(time.value),
|
timeStr = millisecondsToStr(time.value),
|
||||||
totalTime = time.value,
|
totalTime = time.value,
|
||||||
nextTimerMode = if (cycles == 6) TimerMode.LONG_BREAK else TimerMode.SHORT_BREAK,
|
nextTimerMode = TimerMode.SHORT_BREAK,
|
||||||
nextTimeStr = if (cycles == 6) millisecondsToStr(
|
nextTimeStr = millisecondsToStr(timerRepository.shortBreakTime)
|
||||||
timerRepository.longBreakTime
|
|
||||||
) else millisecondsToStr(
|
|
||||||
timerRepository.shortBreakTime
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
val long = cycles == (timerRepository.sessionLength * 2) - 1
|
}
|
||||||
_time.update { if (long) timerRepository.longBreakTime else timerRepository.shortBreakTime }
|
|
||||||
|
|
||||||
_timerState.update { currentState ->
|
fun skipTimer() {
|
||||||
currentState.copy(
|
viewModelScope.launch {
|
||||||
timerMode = if (long) TimerMode.LONG_BREAK else TimerMode.SHORT_BREAK,
|
saveTimeToDb()
|
||||||
timeStr = millisecondsToStr(time.value),
|
startTime = 0L
|
||||||
totalTime = time.value,
|
pauseTime = 0L
|
||||||
nextTimerMode = TimerMode.FOCUS,
|
pauseDuration = 0L
|
||||||
nextTimeStr = millisecondsToStr(timerRepository.focusTime)
|
|
||||||
)
|
cycles = (cycles + 1) % (timerRepository.sessionLength * 2)
|
||||||
|
|
||||||
|
if (cycles % 2 == 0) {
|
||||||
|
_time.update { timerRepository.focusTime }
|
||||||
|
_timerState.update { currentState ->
|
||||||
|
currentState.copy(
|
||||||
|
timerMode = TimerMode.FOCUS,
|
||||||
|
timeStr = millisecondsToStr(time.value),
|
||||||
|
totalTime = time.value,
|
||||||
|
nextTimerMode = if (cycles == 6) TimerMode.LONG_BREAK else TimerMode.SHORT_BREAK,
|
||||||
|
nextTimeStr = if (cycles == 6) millisecondsToStr(
|
||||||
|
timerRepository.longBreakTime
|
||||||
|
) else millisecondsToStr(
|
||||||
|
timerRepository.shortBreakTime
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val long = cycles == (timerRepository.sessionLength * 2) - 1
|
||||||
|
_time.update { if (long) timerRepository.longBreakTime else timerRepository.shortBreakTime }
|
||||||
|
|
||||||
|
_timerState.update { currentState ->
|
||||||
|
currentState.copy(
|
||||||
|
timerMode = if (long) TimerMode.LONG_BREAK else TimerMode.SHORT_BREAK,
|
||||||
|
timeStr = millisecondsToStr(time.value),
|
||||||
|
totalTime = time.value,
|
||||||
|
nextTimerMode = TimerMode.FOCUS,
|
||||||
|
nextTimeStr = millisecondsToStr(timerRepository.focusTime)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -164,15 +197,27 @@ class TimerViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun saveTimeToDb() {
|
||||||
|
when (timerState.value.timerMode) {
|
||||||
|
TimerMode.FOCUS -> statRepository
|
||||||
|
.addFocusTime((timerState.value.totalTime - time.value))
|
||||||
|
|
||||||
|
else -> statRepository
|
||||||
|
.addBreakTime((timerState.value.totalTime - time.value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||||
initializer {
|
initializer {
|
||||||
val application = (this[APPLICATION_KEY] as TomatoApplication)
|
val application = (this[APPLICATION_KEY] as TomatoApplication)
|
||||||
val appPreferenceRepository = application.container.appPreferencesRepository
|
val appPreferenceRepository = application.container.appPreferenceRepository
|
||||||
|
val appStatRepository = application.container.appStatRepository
|
||||||
val appTimerRepository = application.container.appTimerRepository
|
val appTimerRepository = application.container.appTimerRepository
|
||||||
|
|
||||||
TimerViewModel(
|
TimerViewModel(
|
||||||
preferenceRepository = appPreferenceRepository,
|
preferenceRepository = appPreferenceRepository,
|
||||||
|
statRepository = appStatRepository,
|
||||||
timerRepository = appTimerRepository
|
timerRepository = appTimerRepository
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Nishant Mishra
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.nsh07.pomodoro.utils
|
package org.nsh07.pomodoro.utils
|
||||||
|
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
|
|
||||||
fun millisecondsToStr(t: Int): String {
|
fun millisecondsToStr(t: Long): String {
|
||||||
val min = (ceil(t / 1000.0).toInt() / 60)
|
val min = (ceil(t / 1000.0).toInt() / 60)
|
||||||
val sec = (ceil(t / 1000.0).toInt() % 60)
|
val sec = (ceil(t / 1000.0).toInt() % 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