diff --git a/app/src/main/java/at/bitfire/icsdroid/db/dao/SubscriptionsDao.kt b/app/src/main/java/at/bitfire/icsdroid/db/dao/SubscriptionsDao.kt index 0089f5c5..3cbb7aa0 100644 --- a/app/src/main/java/at/bitfire/icsdroid/db/dao/SubscriptionsDao.kt +++ b/app/src/main/java/at/bitfire/icsdroid/db/dao/SubscriptionsDao.kt @@ -47,7 +47,7 @@ interface SubscriptionsDao { suspend fun getByUrl(url: String): Subscription? @Query("SELECT * FROM subscriptions WHERE id=:id") - fun getWithCredentialsByIdFlow(id: Long): Flow + suspend fun getWithCredentialsById(id: Long): SubscriptionWithCredential? @Query("SELECT errorMessage FROM subscriptions WHERE id=:id") fun getErrorMessageFlow(id: Long): Flow diff --git a/app/src/main/java/at/bitfire/icsdroid/model/EditSubscriptionModel.kt b/app/src/main/java/at/bitfire/icsdroid/model/EditSubscriptionModel.kt index a95d29f1..9be891d9 100644 --- a/app/src/main/java/at/bitfire/icsdroid/model/EditSubscriptionModel.kt +++ b/app/src/main/java/at/bitfire/icsdroid/model/EditSubscriptionModel.kt @@ -24,7 +24,6 @@ import dagger.assisted.AssistedInject import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.launch @HiltViewModel(assistedFactory = EditSubscriptionModel.EditSubscriptionModelFactory::class) @@ -42,7 +41,7 @@ class EditSubscriptionModel @AssistedInject constructor( private var initialSubscription: Subscription? = null private var initialCredential: Credential? = null - private var initialRequiresAuthValue: Boolean? = null + private val initialRequiresAuth: Boolean get() = initialCredential != null /** * Whether user input is error free @@ -69,7 +68,7 @@ class EditSubscriptionModel @AssistedInject constructor( get() = with(subscriptionSettingsUseCase) { val requiresAuth = uiState.requiresAuth - val credentialsDirty = initialRequiresAuthValue != requiresAuth || initialCredential?.let { + val credentialsDirty = initialRequiresAuth != requiresAuth || initialCredential?.let { !equalsCredential(it) } ?: false val subscriptionsDirty = initialSubscription?.let { @@ -82,15 +81,13 @@ class EditSubscriptionModel @AssistedInject constructor( var successMessage: String? by mutableStateOf(null) private set - val subscription = db.subscriptionsDao().getByIdFlow(subscriptionId) - val subscriptionWithCredential = db.subscriptionsDao().getWithCredentialsByIdFlow(subscriptionId) + var subscriptionWithCredential: SubscriptionsDao.SubscriptionWithCredential? = null + private set init { - // Initialise view models and save their initial state viewModelScope.launch { - subscriptionWithCredential.collect { data -> - if (data != null) - onSubscriptionLoaded(data) + db.subscriptionsDao().getWithCredentialsById(subscriptionId)?.let { + onSubscriptionLoaded(it) } } } @@ -98,40 +95,24 @@ class EditSubscriptionModel @AssistedInject constructor( /** * Initialise view models and remember their initial state */ - private fun onSubscriptionLoaded(subscriptionWithCredential: SubscriptionsDao.SubscriptionWithCredential) = - with(subscriptionSettingsUseCase) { - val subscription = subscriptionWithCredential.subscription - - setUrl(subscription.url.toString()) - setTitle(subscription.displayName) - setColor(subscription.color) - setCustomUserAgent(subscription.customUserAgent) - setIgnoreAlerts(subscription.ignoreEmbeddedAlerts) - setDefaultAlarmMinutes(subscription.defaultAlarmMinutes?.toString()) - setDefaultAllDayAlarmMinutes(subscription.defaultAllDayAlarmMinutes?.toString()) - setIgnoreDescription(subscription.ignoreDescription) - - val credential = subscriptionWithCredential.credential - val requiresAuth = credential != null - setRequiresAuth(requiresAuth) - - if (credential != null) { - setUsername(credential.username) - setPassword(credential.password) - } + private fun onSubscriptionLoaded(subscriptionWithCredential: SubscriptionsDao.SubscriptionWithCredential) { + val subscription = subscriptionWithCredential.subscription + val credential = subscriptionWithCredential.credential - // Save state, before user makes changes - initialSubscription = subscription - initialCredential = credential - initialRequiresAuthValue = uiState.requiresAuth - } + // Save the initial state, before updating the UI, so the state is persisted + initialSubscription = subscription + initialCredential = credential + this.subscriptionWithCredential = subscriptionWithCredential + + subscriptionSettingsUseCase.update(subscription, credential) + } /** * Updates the loaded subscription from the data provided by the view models. */ fun updateSubscription() = with(subscriptionSettingsUseCase.uiState) { viewModelScope.launch(Dispatchers.IO) { - subscription.firstOrNull()?.let { subscription -> + subscriptionWithCredential?.let { (subscription) -> val newSubscription = subscription.copy( displayName = title ?: subscription.displayName, color = color, @@ -163,7 +144,7 @@ class EditSubscriptionModel @AssistedInject constructor( */ fun removeSubscription() { viewModelScope.launch(Dispatchers.IO) { - subscription.firstOrNull()?.let { subscription -> + subscriptionWithCredential?.let { (subscription) -> db.subscriptionsDao().delete(subscription) // sync the subscription to reflect the changes in the calendar provider diff --git a/app/src/main/java/at/bitfire/icsdroid/model/SubscriptionSettingsUseCase.kt b/app/src/main/java/at/bitfire/icsdroid/model/SubscriptionSettingsUseCase.kt index 674386ef..233f7f1c 100644 --- a/app/src/main/java/at/bitfire/icsdroid/model/SubscriptionSettingsUseCase.kt +++ b/app/src/main/java/at/bitfire/icsdroid/model/SubscriptionSettingsUseCase.kt @@ -81,6 +81,23 @@ class SubscriptionSettingsUseCase @Inject constructor() { uiState = uiState.copy(ignoreDescription = value) } + fun update(subscription: Subscription, credential: Credential?) { + uiState = uiState.copy( + url = subscription.url.toString(), + title = subscription.displayName, + color = subscription.color, + customUserAgent = subscription.customUserAgent, + ignoreAlerts = subscription.ignoreEmbeddedAlerts, + defaultAlarmMinutes = subscription.defaultAlarmMinutes, + defaultAllDayAlarmMinutes = subscription.defaultAllDayAlarmMinutes, + ignoreDescription = subscription.ignoreDescription, + + requiresAuth = credential != null, + username = credential?.username, + password = credential?.password + ) + } + fun equalsSubscription(subscription: Subscription) = uiState.url == subscription.url.toString() && uiState.title == subscription.displayName diff --git a/app/src/main/java/at/bitfire/icsdroid/ui/screen/EditSubscriptionScreen.kt b/app/src/main/java/at/bitfire/icsdroid/ui/screen/EditSubscriptionScreen.kt index ace6c8ca..86795f92 100644 --- a/app/src/main/java/at/bitfire/icsdroid/ui/screen/EditSubscriptionScreen.kt +++ b/app/src/main/java/at/bitfire/icsdroid/ui/screen/EditSubscriptionScreen.kt @@ -33,7 +33,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle import at.bitfire.icsdroid.R import at.bitfire.icsdroid.db.entity.Subscription import at.bitfire.icsdroid.model.EditSubscriptionModel @@ -54,7 +53,7 @@ fun EditSubscriptionScreen( val model = hiltViewModel { factory -> factory.create(subscriptionId) } - val subscription = model.subscription.collectAsStateWithLifecycle(null) + with(model.subscriptionSettingsUseCase) { EditSubscriptionScreen( inputValid = model.inputValid, @@ -63,8 +62,8 @@ fun EditSubscriptionScreen( onDelete = model::removeSubscription, onSave = model::updateSubscription, onShare = { - subscription.value?.let { - onShare(it) + model.subscriptionWithCredential?.let { (subscription) -> + onShare(subscription) } }, onExit = onExit,