diff --git a/app/src/foss/java/org/nsh07/pomodoro/billing/FossBillingManager.kt b/app/src/foss/java/org/nsh07/pomodoro/billing/FossBillingManager.kt index 529b58c..4a155a3 100644 --- a/app/src/foss/java/org/nsh07/pomodoro/billing/FossBillingManager.kt +++ b/app/src/foss/java/org/nsh07/pomodoro/billing/FossBillingManager.kt @@ -25,7 +25,6 @@ import kotlinx.coroutines.flow.asStateFlow */ class FossBillingManager : BillingManager { override val isPlus = MutableStateFlow(true).asStateFlow() - override val isLoaded = MutableStateFlow(true).asStateFlow() } object BillingManagerProvider { diff --git a/app/src/main/java/org/nsh07/pomodoro/MainActivity.kt b/app/src/main/java/org/nsh07/pomodoro/MainActivity.kt index a36bb6d..95e9502 100644 --- a/app/src/main/java/org/nsh07/pomodoro/MainActivity.kt +++ b/app/src/main/java/org/nsh07/pomodoro/MainActivity.kt @@ -61,18 +61,6 @@ class MainActivity : ComponentActivity() { val seed = settingsState.colorScheme.toColor() val isPlus by settingsViewModel.isPlus.collectAsStateWithLifecycle() - val isPurchaseStateLoaded by settingsViewModel.isPurchaseStateLoaded.collectAsStateWithLifecycle() - val isSettingsLoaded by settingsViewModel.isSettingsLoaded.collectAsStateWithLifecycle() - - LaunchedEffect(isPurchaseStateLoaded, isPlus, isSettingsLoaded) { - if (isPurchaseStateLoaded && isSettingsLoaded) { - if (!isPlus) { - settingsViewModel.resetPaywalledSettings() - } else { - settingsViewModel.reloadSettings() - } - } - } TomatoTheme( darkTheme = darkTheme, diff --git a/app/src/main/java/org/nsh07/pomodoro/billing/BillingManager.kt b/app/src/main/java/org/nsh07/pomodoro/billing/BillingManager.kt index 4cdc106..66b1659 100644 --- a/app/src/main/java/org/nsh07/pomodoro/billing/BillingManager.kt +++ b/app/src/main/java/org/nsh07/pomodoro/billing/BillingManager.kt @@ -21,5 +21,4 @@ import kotlinx.coroutines.flow.StateFlow interface BillingManager { val isPlus: StateFlow - val isLoaded: StateFlow } \ No newline at end of file diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/SettingsScreen.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/SettingsScreen.kt index 2827eab..f7c2c44 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/SettingsScreen.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/SettingsScreen.kt @@ -101,10 +101,6 @@ fun SettingsScreenRoot( val longBreakTimeInputFieldState = viewModel.longBreakTimeTextFieldState val isPlus by viewModel.isPlus.collectAsStateWithLifecycle() - val alarmEnabled by viewModel.alarmEnabled.collectAsStateWithLifecycle(true) - val vibrateEnabled by viewModel.vibrateEnabled.collectAsStateWithLifecycle(true) - val dndEnabled by viewModel.dndEnabled.collectAsStateWithLifecycle(false) - val alarmSound by viewModel.alarmSound.collectAsStateWithLifecycle(viewModel.currentAlarmSound) val settingsState by viewModel.settingsState.collectAsStateWithLifecycle() @@ -125,10 +121,6 @@ fun SettingsScreenRoot( shortBreakTimeInputFieldState = shortBreakTimeInputFieldState, longBreakTimeInputFieldState = longBreakTimeInputFieldState, sessionsSliderState = sessionsSliderState, - alarmEnabled = alarmEnabled, - vibrateEnabled = vibrateEnabled, - dndEnabled = dndEnabled, - alarmSound = alarmSound, onAction = viewModel::onAction, setShowPaywall = setShowPaywall, modifier = modifier @@ -146,10 +138,6 @@ private fun SettingsScreen( shortBreakTimeInputFieldState: TextFieldState, longBreakTimeInputFieldState: TextFieldState, sessionsSliderState: SliderState, - alarmEnabled: Boolean, - vibrateEnabled: Boolean, - dndEnabled: Boolean, - alarmSound: String, onAction: (SettingsAction) -> Unit, setShowPaywall: (Boolean) -> Unit, modifier: Modifier = Modifier @@ -288,9 +276,6 @@ private fun SettingsScreen( entry { AlarmSettings( settingsState = settingsState, - alarmEnabled = alarmEnabled, - vibrateEnabled = vibrateEnabled, - alarmSound = alarmSound, onAction = onAction, onBack = backStack::removeLastOrNull ) @@ -307,8 +292,7 @@ private fun SettingsScreen( entry { TimerSettings( isPlus = isPlus, - aodEnabled = settingsState.aodEnabled, - dndEnabled = dndEnabled, + settingsState = settingsState, focusTimeInputFieldState = focusTimeInputFieldState, shortBreakTimeInputFieldState = shortBreakTimeInputFieldState, longBreakTimeInputFieldState = longBreakTimeInputFieldState, diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/screens/AlarmSettings.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/screens/AlarmSettings.kt index 186fba8..7b3fcdd 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/screens/AlarmSettings.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/screens/AlarmSettings.kt @@ -79,9 +79,6 @@ import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.topListItemShape @Composable fun AlarmSettings( settingsState: SettingsState, - alarmEnabled: Boolean, - vibrateEnabled: Boolean, - alarmSound: String, onAction: (SettingsAction) -> Unit, onBack: () -> Unit, modifier: Modifier = Modifier @@ -91,10 +88,11 @@ fun AlarmSettings( var alarmName by remember { mutableStateOf("...") } - LaunchedEffect(alarmSound) { + LaunchedEffect(settingsState.alarmSound) { withContext(Dispatchers.IO) { alarmName = - RingtoneManager.getRingtone(context, alarmSound.toUri())?.getTitle(context) ?: "" + RingtoneManager.getRingtone(context, settingsState.alarmSound.toUri()) + ?.getTitle(context) ?: "" } } @@ -117,30 +115,30 @@ fun AlarmSettings( } @SuppressLint("LocalContextGetResourceValueCall") - val ringtonePickerIntent = remember(alarmSound) { + val ringtonePickerIntent = remember(settingsState.alarmSound) { Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply { putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_ALARM) putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, context.getString(R.string.alarm_sound)) - putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, alarmSound.toUri()) + putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, settingsState.alarmSound.toUri()) } } val switchItems = remember( settingsState.blackTheme, settingsState.aodEnabled, - alarmEnabled, - vibrateEnabled + settingsState.alarmEnabled, + settingsState.vibrateEnabled ) { listOf( SettingsSwitchItem( - checked = alarmEnabled, + checked = settingsState.alarmEnabled, icon = R.drawable.alarm_on, label = R.string.sound, description = R.string.alarm_desc, onClick = { onAction(SettingsAction.SaveAlarmEnabled(it)) } ), SettingsSwitchItem( - checked = vibrateEnabled, + checked = settingsState.vibrateEnabled, icon = R.drawable.mobile_vibrate, label = R.string.vibrate, description = R.string.vibrate_desc, @@ -245,9 +243,7 @@ fun AlarmSettingsPreview() { val settingsState = SettingsState() AlarmSettings( settingsState = settingsState, - alarmEnabled = true, - vibrateEnabled = false, - alarmSound = "", onAction = {}, - onBack = {}) + onBack = {} + ) } diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/screens/TimerSettings.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/screens/TimerSettings.kt index 74504f0..a7cb380 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/screens/TimerSettings.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/screens/TimerSettings.kt @@ -41,6 +41,7 @@ import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.input.TextFieldState +import androidx.compose.foundation.text.input.rememberTextFieldState import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.FilledTonalIconToggleButton @@ -57,6 +58,7 @@ import androidx.compose.material3.Switch import androidx.compose.material3.SwitchDefaults import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.rememberSliderState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -78,6 +80,7 @@ import org.nsh07.pomodoro.ui.settingsScreen.SettingsSwitchItem import org.nsh07.pomodoro.ui.settingsScreen.components.MinuteInputField import org.nsh07.pomodoro.ui.settingsScreen.components.PlusDivider import org.nsh07.pomodoro.ui.settingsScreen.viewModel.SettingsAction +import org.nsh07.pomodoro.ui.settingsScreen.viewModel.SettingsState import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar import org.nsh07.pomodoro.ui.theme.CustomColors.listItemColors import org.nsh07.pomodoro.ui.theme.CustomColors.switchColors @@ -92,14 +95,13 @@ import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.topListItemShape @Composable fun TimerSettings( isPlus: Boolean, - aodEnabled: Boolean, - dndEnabled: Boolean, + settingsState: SettingsState, focusTimeInputFieldState: TextFieldState, shortBreakTimeInputFieldState: TextFieldState, longBreakTimeInputFieldState: TextFieldState, sessionsSliderState: SliderState, - setShowPaywall: (Boolean) -> Unit, onAction: (SettingsAction) -> Unit, + setShowPaywall: (Boolean) -> Unit, onBack: () -> Unit, modifier: Modifier = Modifier ) { @@ -116,7 +118,7 @@ fun TimerSettings( val switchItems = listOf( SettingsSwitchItem( - checked = dndEnabled, + checked = settingsState.dndEnabled, icon = R.drawable.dnd, label = R.string.dnd, description = R.string.dnd_desc, @@ -133,7 +135,7 @@ fun TimerSettings( } ), SettingsSwitchItem( - checked = aodEnabled, + checked = settingsState.aodEnabled, icon = R.drawable.aod, label = R.string.always_on_display, description = R.string.always_on_display_desc, @@ -393,18 +395,17 @@ fun TimerSettings( @Preview @Composable private fun TimerSettingsPreview() { - val focusTimeInputFieldState = TextFieldState("25") - val shortBreakTimeInputFieldState = TextFieldState("5") - val longBreakTimeInputFieldState = TextFieldState("15") - val sessionsSliderState = SliderState( + val focusTimeInputFieldState = rememberTextFieldState("25") + val shortBreakTimeInputFieldState = rememberTextFieldState("5") + val longBreakTimeInputFieldState = rememberTextFieldState("15") + val sessionsSliderState = rememberSliderState( value = 4f, valueRange = 1f..8f, steps = 6 ) TimerSettings( isPlus = false, - aodEnabled = true, - dndEnabled = false, + settingsState = remember { SettingsState() }, focusTimeInputFieldState = focusTimeInputFieldState, shortBreakTimeInputFieldState = shortBreakTimeInputFieldState, longBreakTimeInputFieldState = longBreakTimeInputFieldState, diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsState.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsState.kt index bb43365..b9d42b4 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsState.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsState.kt @@ -23,7 +23,11 @@ import androidx.compose.ui.graphics.Color @Immutable data class SettingsState( val theme: String = "auto", + val alarmSound: String = "", val colorScheme: String = Color.White.toString(), val blackTheme: Boolean = false, - val aodEnabled: Boolean = false + val aodEnabled: Boolean = false, + val alarmEnabled: Boolean = true, + val vibrateEnabled: Boolean = true, + val dndEnabled: Boolean = false ) diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt index c86bf3f..d412bdd 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt @@ -18,6 +18,7 @@ package org.nsh07.pomodoro.ui.settingsScreen.viewModel import android.net.Uri +import android.provider.Settings import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.SliderState @@ -36,7 +37,6 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.debounce -import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import org.nsh07.pomodoro.TomatoApplication @@ -54,10 +54,6 @@ class SettingsViewModel( val backStack = mutableStateListOf(Screen.Settings.Main) val isPlus = billingManager.isPlus - val isPurchaseStateLoaded = billingManager.isLoaded - - private val _isSettingsLoaded = MutableStateFlow(false) - val isSettingsLoaded = _isSettingsLoaded.asStateFlow() private val _settingsState = MutableStateFlow(SettingsState()) val settingsState = _settingsState.asStateFlow() @@ -81,25 +77,13 @@ class SettingsViewModel( ) } - val currentAlarmSound = timerRepository.alarmSoundUri.toString() - private var focusFlowCollectionJob: Job? = null private var shortBreakFlowCollectionJob: Job? = null private var longBreakFlowCollectionJob: Job? = null - val alarmSound = - preferenceRepository.getStringPreferenceFlow("alarm_sound").distinctUntilChanged() - val alarmEnabled = - preferenceRepository.getBooleanPreferenceFlow("alarm_enabled").distinctUntilChanged() - val vibrateEnabled = - preferenceRepository.getBooleanPreferenceFlow("vibrate_enabled").distinctUntilChanged() - val dndEnabled = - preferenceRepository.getBooleanPreferenceFlow("dnd_enabled").distinctUntilChanged() - init { viewModelScope.launch { reloadSettings() - _isSettingsLoaded.value = true } } @@ -176,6 +160,9 @@ class SettingsViewModel( private fun saveAlarmEnabled(enabled: Boolean) { viewModelScope.launch { timerRepository.alarmEnabled = enabled + _settingsState.update { currentState -> + currentState.copy(alarmEnabled = enabled) + } preferenceRepository.saveBooleanPreference("alarm_enabled", enabled) } } @@ -183,6 +170,9 @@ class SettingsViewModel( private fun saveVibrateEnabled(enabled: Boolean) { viewModelScope.launch { timerRepository.vibrateEnabled = enabled + _settingsState.update { currentState -> + currentState.copy(vibrateEnabled = enabled) + } preferenceRepository.saveBooleanPreference("vibrate_enabled", enabled) } } @@ -190,6 +180,9 @@ class SettingsViewModel( private fun saveDndEnabled(enabled: Boolean) { viewModelScope.launch { timerRepository.dndEnabled = enabled + _settingsState.update { currentState -> + currentState.copy(dndEnabled = enabled) + } preferenceRepository.saveBooleanPreference("dnd_enabled", enabled) } } @@ -197,6 +190,9 @@ class SettingsViewModel( private fun saveAlarmSound(uri: Uri?) { viewModelScope.launch { timerRepository.alarmSoundUri = uri + _settingsState.update { currentState -> + currentState.copy(alarmSound = uri.toString()) + } preferenceRepository.saveStringPreference("alarm_sound", uri.toString()) } } @@ -237,16 +233,6 @@ class SettingsViewModel( } } - fun resetPaywalledSettings() { - _settingsState.update { currentState -> - currentState.copy( - aodEnabled = false, - blackTheme = false, - colorScheme = Color.White.toString() - ) - } - } - suspend fun reloadSettings() { val theme = preferenceRepository.getStringPreference("theme") ?: preferenceRepository.saveStringPreference("theme", "auto") @@ -256,13 +242,29 @@ class SettingsViewModel( ?: preferenceRepository.saveBooleanPreference("black_theme", false) val aodEnabled = preferenceRepository.getBooleanPreference("aod_enabled") ?: preferenceRepository.saveBooleanPreference("aod_enabled", false) + val alarmSound = preferenceRepository.getStringPreference("alarm_sound") + ?: preferenceRepository.saveStringPreference( + "alarm_sound", + (Settings.System.DEFAULT_ALARM_ALERT_URI + ?: Settings.System.DEFAULT_RINGTONE_URI).toString() + ) + val alarmEnabled = preferenceRepository.getBooleanPreference("alarm_enabled") + ?: preferenceRepository.saveBooleanPreference("alarm_enabled", true) + val vibrateEnabled = preferenceRepository.getBooleanPreference("vibrate_enabled") + ?: preferenceRepository.saveBooleanPreference("vibrate_enabled", true) + val dndEnabled = preferenceRepository.getBooleanPreference("dnd_enabled") + ?: preferenceRepository.saveBooleanPreference("dnd_enabled", false) _settingsState.update { currentState -> currentState.copy( theme = theme, colorScheme = colorScheme, + alarmSound = alarmSound, blackTheme = blackTheme, - aodEnabled = aodEnabled + aodEnabled = aodEnabled, + alarmEnabled = alarmEnabled, + vibrateEnabled = vibrateEnabled, + dndEnabled = dndEnabled ) } } diff --git a/app/src/play/java/org/nsh07/pomodoro/billing/PlayBillingManager.kt b/app/src/play/java/org/nsh07/pomodoro/billing/PlayBillingManager.kt index a658884..94bfcb2 100644 --- a/app/src/play/java/org/nsh07/pomodoro/billing/PlayBillingManager.kt +++ b/app/src/play/java/org/nsh07/pomodoro/billing/PlayBillingManager.kt @@ -33,9 +33,6 @@ class PlayBillingManager : BillingManager { private val _isPlus = MutableStateFlow(false) override val isPlus = _isPlus.asStateFlow() - private val _isLoaded = MutableStateFlow(false) - override val isLoaded = _isLoaded.asStateFlow() - private val purchases by lazy { Purchases.sharedInstance } init { @@ -48,11 +45,9 @@ class PlayBillingManager : BillingManager { purchases.getCustomerInfoWith( onSuccess = { customerInfo -> _isPlus.value = customerInfo.entitlements[ENTITLEMENT_ID]?.isActive == true - _isLoaded.value = true }, onError = { error -> Log.e("GooglePlayPaywallManager", "Error fetching customer info: $error") - _isLoaded.value = true } ) }