Merge branch 'dev'

This commit is contained in:
Nishant Mishra
2025-09-27 22:56:56 +05:30
4 changed files with 37 additions and 14 deletions

View File

@@ -33,8 +33,8 @@ android {
applicationId = "org.nsh07.pomodoro" applicationId = "org.nsh07.pomodoro"
minSdk = 26 minSdk = 26
targetSdk = 36 targetSdk = 36
versionCode = 8 versionCode = 9
versionName = "1.4.0" versionName = "1.4.1"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }

View File

@@ -12,6 +12,7 @@ import android.content.Intent
import android.media.RingtoneManager import android.media.RingtoneManager
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.provider.MediaStore
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
@@ -72,6 +73,7 @@ import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.compose.ui.util.fastCoerceAtLeast
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
@@ -89,6 +91,7 @@ import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.topListItemShape
import org.nsh07.pomodoro.ui.theme.TomatoTheme import org.nsh07.pomodoro.ui.theme.TomatoTheme
import org.nsh07.pomodoro.utils.toColor import org.nsh07.pomodoro.utils.toColor
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun SettingsScreenRoot( fun SettingsScreenRoot(
@@ -197,9 +200,17 @@ private fun SettingsScreen(
val context = LocalContext.current val context = LocalContext.current
var alarmName by remember { mutableStateOf("") } var alarmName by remember { mutableStateOf("") }
LaunchedEffect(Unit) { LaunchedEffect(alarmSound) {
alarmName = RingtoneManager.getRingtone(context, alarmSound.toUri()) val returnCursor = context.contentResolver.query(alarmSound.toUri(), null, null, null, null)
?.getTitle(context) ?: "" returnCursor?.moveToFirst()
alarmName =
returnCursor
?.getString(
returnCursor
.getColumnIndex(MediaStore.MediaColumns.TITLE)
.fastCoerceAtLeast(0)
) ?: ""
returnCursor?.close()
} }
val ringtonePickerLauncher = rememberLauncherForActivityResult( val ringtonePickerLauncher = rememberLauncherForActivityResult(

View File

@@ -22,7 +22,6 @@ import androidx.lifecycle.viewmodel.viewModelFactory
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.debounce
@@ -60,10 +59,9 @@ class SettingsViewModel(
val currentAlarmSound = timerRepository.alarmSoundUri.toString() val currentAlarmSound = timerRepository.alarmSoundUri.toString()
private val flowCollectionJob = SupervisorJob() private var focusFlowCollectionJob: Job? = null
private val focusFlowCollectionJob = Job(flowCollectionJob) private var shortBreakFlowCollectionJob: Job? = null
private val shortBreakFlowCollectionJob = Job(flowCollectionJob) private var longBreakFlowCollectionJob: Job? = null
private val longBreakFlowCollectionJob = Job(flowCollectionJob)
val alarmSound = val alarmSound =
preferenceRepository.getStringPreferenceFlow("alarm_sound").distinctUntilChanged() preferenceRepository.getStringPreferenceFlow("alarm_sound").distinctUntilChanged()
@@ -101,7 +99,7 @@ class SettingsViewModel(
} }
fun runTextFieldFlowCollection() { fun runTextFieldFlowCollection() {
viewModelScope.launch(focusFlowCollectionJob + Dispatchers.IO) { focusFlowCollectionJob = viewModelScope.launch(Dispatchers.IO) {
snapshotFlow { focusTimeTextFieldState.text } snapshotFlow { focusTimeTextFieldState.text }
.debounce(500) .debounce(500)
.collect { .collect {
@@ -114,7 +112,7 @@ class SettingsViewModel(
} }
} }
} }
viewModelScope.launch(shortBreakFlowCollectionJob + Dispatchers.IO) { shortBreakFlowCollectionJob = viewModelScope.launch(Dispatchers.IO) {
snapshotFlow { shortBreakTimeTextFieldState.text } snapshotFlow { shortBreakTimeTextFieldState.text }
.debounce(500) .debounce(500)
.collect { .collect {
@@ -127,7 +125,7 @@ class SettingsViewModel(
} }
} }
} }
viewModelScope.launch(longBreakFlowCollectionJob + Dispatchers.IO) { longBreakFlowCollectionJob = viewModelScope.launch(Dispatchers.IO) {
snapshotFlow { longBreakTimeTextFieldState.text } snapshotFlow { longBreakTimeTextFieldState.text }
.debounce(500) .debounce(500)
.collect { .collect {
@@ -142,7 +140,11 @@ class SettingsViewModel(
} }
} }
fun cancelTextFieldFlowCollection() = flowCollectionJob.cancel() fun cancelTextFieldFlowCollection() {
focusFlowCollectionJob?.cancel()
shortBreakFlowCollectionJob?.cancel()
longBreakFlowCollectionJob?.cancel()
}
fun saveAlarmEnabled(enabled: Boolean) { fun saveAlarmEnabled(enabled: Boolean) {
viewModelScope.launch { viewModelScope.launch {

View File

@@ -0,0 +1,10 @@
This release contains bug fixes on top of the existing new features of 1.4.0:
New features:
- You can now choose a custom theme and color scheme for the app's UI
- New pure black dark theme mode
Fixes:
- Average focus durations now do not include days with no activity
- Fix a critical bug that caused the app's timer state to reset to Focus whenever the app was closed from recents and then opened
- Replace the word "Reset" with "Exit" in the notification to make its purpose less ambiguous