Loading app/src/main/java/foundation/e/apps/ui/settings/SettingsFragment.kt +1 −11 Original line number Diff line number Diff line Loading @@ -37,7 +37,6 @@ import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.Preference.OnPreferenceChangeListener import androidx.preference.PreferenceFragmentCompat import androidx.work.ExistingPeriodicWorkPolicy import coil.load import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint Loading @@ -50,7 +49,6 @@ import foundation.e.apps.domain.source.AppSource import foundation.e.apps.feature.auth.login.LoginNavigationArgs import foundation.e.apps.feature.auth.login.LoginUiEvent import foundation.e.apps.feature.auth.login.LoginViewModel import foundation.e.apps.updates.PeriodicUpdatesScheduler import kotlinx.coroutines.launch import timber.log.Timber import java.util.Locale Loading @@ -77,9 +75,6 @@ class SettingsFragment : PreferenceFragmentCompat() { @Inject lateinit var clipboardManager: ClipboardManager @Inject lateinit var periodicUpdatesScheduler: PeriodicUpdatesScheduler private val allSourceCheckboxes by lazy { listOf(showAllApplications, showFOSSApplications, showPWAApplications) } Loading Loading @@ -110,12 +105,7 @@ class SettingsFragment : PreferenceFragmentCompat() { val updateChangeListener = OnPreferenceChangeListener { _, newValue -> Timber.d("onCreatePreferences: updated Value: $newValue") lifecycleScope.launch { periodicUpdatesScheduler.syncPeriodicUpdates( interval = newValue.toString().toLong(), existingPeriodicWorkPolicy = ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE, ) } settingsViewModel.onUpdateCheckIntervalRequested(newValue.toString().toLong()) true } Loading app/src/main/java/foundation/e/apps/ui/settings/SettingsViewModel.kt +12 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ package foundation.e.apps.ui.settings import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.work.ExistingPeriodicWorkPolicy import dagger.hilt.android.lifecycle.HiltViewModel import foundation.e.apps.domain.auth.AuthSession import foundation.e.apps.domain.auth.AuthSessionRepository Loading @@ -31,6 +32,7 @@ import foundation.e.apps.domain.source.SourceSelection import foundation.e.apps.domain.source.SourceSelectionRepository import foundation.e.apps.feature.auth.session.SessionRefreshException import foundation.e.apps.feature.auth.source.UpdateSourceSelectionUseCase import foundation.e.apps.updates.PeriodicUpdatesScheduler import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharingStarted Loading @@ -49,6 +51,7 @@ class SettingsViewModel @Inject constructor( private val playStoreAccountRepository: PlayStoreAccountRepository, private val sourceSelectionRepository: SourceSelectionRepository, private val updateSourceSelectionUseCase: UpdateSourceSelectionUseCase, private val periodicUpdatesScheduler: PeriodicUpdatesScheduler, ) : ViewModel() { private sealed interface SourceSelectionRequestOutcome { data object Ignore : SourceSelectionRequestOutcome Loading Loading @@ -84,6 +87,15 @@ class SettingsViewModel @Inject constructor( } } fun onUpdateCheckIntervalRequested(intervalHours: Long) { viewModelScope.launch { periodicUpdatesScheduler.syncPeriodicUpdates( interval = intervalHours, existingPeriodicWorkPolicy = ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE, ) } } private fun submitSourceSelectionUpdate( sourceSelection: SourceSelection, ) { Loading app/src/test/java/foundation/e/apps/ui/settings/SettingsViewModelTest.kt +24 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package foundation.e.apps.ui.settings import androidx.work.ExistingPeriodicWorkPolicy import com.google.common.truth.Truth.assertThat import foundation.e.apps.domain.auth.AuthRefreshSnapshot import foundation.e.apps.domain.auth.AuthRefreshState Loading Loading @@ -204,12 +205,34 @@ class SettingsViewModelTest { assertThat(sessionStateController.refreshCallCount).isEqualTo(1) } @Test fun `onUpdateCheckIntervalRequested reschedules periodic updates with replacement policy`() = runTest(mainCoroutineRule.testDispatcher) { val periodicUpdatesScheduler = mockk<PeriodicUpdatesScheduler>(relaxed = true) val viewModel = buildViewModel( session = AuthSession.OpenSourceSession, periodicUpdatesScheduler = periodicUpdatesScheduler, ) advanceUntilIdle() viewModel.onUpdateCheckIntervalRequested(24L) advanceUntilIdle() io.mockk.coVerify(exactly = 1) { periodicUpdatesScheduler.syncPeriodicUpdates( interval = 24L, existingPeriodicWorkPolicy = ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE, ) } } private fun buildViewModel( session: AuthSession, account: PlayStoreAccount? = null, sourceSelection: SourceSelection = SourceSelection.DEFAULT, sourceSelectionRepository: FakeSourceSelectionRepository = FakeSourceSelectionRepository(sourceSelection), sessionStateController: FakeSessionStateController = FakeSessionStateController(), periodicUpdatesScheduler: PeriodicUpdatesScheduler = mockk(relaxed = true), ): SettingsViewModel { return SettingsViewModel( authSessionRepository = FakeAuthSessionRepository(session), Loading @@ -221,6 +244,7 @@ class SettingsViewModelTest { sessionStateController = sessionStateController, sourceSelectionRepository = sourceSelectionRepository, ), periodicUpdatesScheduler = periodicUpdatesScheduler, ) } Loading Loading
app/src/main/java/foundation/e/apps/ui/settings/SettingsFragment.kt +1 −11 Original line number Diff line number Diff line Loading @@ -37,7 +37,6 @@ import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.Preference.OnPreferenceChangeListener import androidx.preference.PreferenceFragmentCompat import androidx.work.ExistingPeriodicWorkPolicy import coil.load import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint Loading @@ -50,7 +49,6 @@ import foundation.e.apps.domain.source.AppSource import foundation.e.apps.feature.auth.login.LoginNavigationArgs import foundation.e.apps.feature.auth.login.LoginUiEvent import foundation.e.apps.feature.auth.login.LoginViewModel import foundation.e.apps.updates.PeriodicUpdatesScheduler import kotlinx.coroutines.launch import timber.log.Timber import java.util.Locale Loading @@ -77,9 +75,6 @@ class SettingsFragment : PreferenceFragmentCompat() { @Inject lateinit var clipboardManager: ClipboardManager @Inject lateinit var periodicUpdatesScheduler: PeriodicUpdatesScheduler private val allSourceCheckboxes by lazy { listOf(showAllApplications, showFOSSApplications, showPWAApplications) } Loading Loading @@ -110,12 +105,7 @@ class SettingsFragment : PreferenceFragmentCompat() { val updateChangeListener = OnPreferenceChangeListener { _, newValue -> Timber.d("onCreatePreferences: updated Value: $newValue") lifecycleScope.launch { periodicUpdatesScheduler.syncPeriodicUpdates( interval = newValue.toString().toLong(), existingPeriodicWorkPolicy = ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE, ) } settingsViewModel.onUpdateCheckIntervalRequested(newValue.toString().toLong()) true } Loading
app/src/main/java/foundation/e/apps/ui/settings/SettingsViewModel.kt +12 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ package foundation.e.apps.ui.settings import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.work.ExistingPeriodicWorkPolicy import dagger.hilt.android.lifecycle.HiltViewModel import foundation.e.apps.domain.auth.AuthSession import foundation.e.apps.domain.auth.AuthSessionRepository Loading @@ -31,6 +32,7 @@ import foundation.e.apps.domain.source.SourceSelection import foundation.e.apps.domain.source.SourceSelectionRepository import foundation.e.apps.feature.auth.session.SessionRefreshException import foundation.e.apps.feature.auth.source.UpdateSourceSelectionUseCase import foundation.e.apps.updates.PeriodicUpdatesScheduler import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharingStarted Loading @@ -49,6 +51,7 @@ class SettingsViewModel @Inject constructor( private val playStoreAccountRepository: PlayStoreAccountRepository, private val sourceSelectionRepository: SourceSelectionRepository, private val updateSourceSelectionUseCase: UpdateSourceSelectionUseCase, private val periodicUpdatesScheduler: PeriodicUpdatesScheduler, ) : ViewModel() { private sealed interface SourceSelectionRequestOutcome { data object Ignore : SourceSelectionRequestOutcome Loading Loading @@ -84,6 +87,15 @@ class SettingsViewModel @Inject constructor( } } fun onUpdateCheckIntervalRequested(intervalHours: Long) { viewModelScope.launch { periodicUpdatesScheduler.syncPeriodicUpdates( interval = intervalHours, existingPeriodicWorkPolicy = ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE, ) } } private fun submitSourceSelectionUpdate( sourceSelection: SourceSelection, ) { Loading
app/src/test/java/foundation/e/apps/ui/settings/SettingsViewModelTest.kt +24 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package foundation.e.apps.ui.settings import androidx.work.ExistingPeriodicWorkPolicy import com.google.common.truth.Truth.assertThat import foundation.e.apps.domain.auth.AuthRefreshSnapshot import foundation.e.apps.domain.auth.AuthRefreshState Loading Loading @@ -204,12 +205,34 @@ class SettingsViewModelTest { assertThat(sessionStateController.refreshCallCount).isEqualTo(1) } @Test fun `onUpdateCheckIntervalRequested reschedules periodic updates with replacement policy`() = runTest(mainCoroutineRule.testDispatcher) { val periodicUpdatesScheduler = mockk<PeriodicUpdatesScheduler>(relaxed = true) val viewModel = buildViewModel( session = AuthSession.OpenSourceSession, periodicUpdatesScheduler = periodicUpdatesScheduler, ) advanceUntilIdle() viewModel.onUpdateCheckIntervalRequested(24L) advanceUntilIdle() io.mockk.coVerify(exactly = 1) { periodicUpdatesScheduler.syncPeriodicUpdates( interval = 24L, existingPeriodicWorkPolicy = ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE, ) } } private fun buildViewModel( session: AuthSession, account: PlayStoreAccount? = null, sourceSelection: SourceSelection = SourceSelection.DEFAULT, sourceSelectionRepository: FakeSourceSelectionRepository = FakeSourceSelectionRepository(sourceSelection), sessionStateController: FakeSessionStateController = FakeSessionStateController(), periodicUpdatesScheduler: PeriodicUpdatesScheduler = mockk(relaxed = true), ): SettingsViewModel { return SettingsViewModel( authSessionRepository = FakeAuthSessionRepository(session), Loading @@ -221,6 +244,7 @@ class SettingsViewModelTest { sessionStateController = sessionStateController, sourceSelectionRepository = sourceSelectionRepository, ), periodicUpdatesScheduler = periodicUpdatesScheduler, ) } Loading