diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt index 911bbfa4a3..22fd3abde7 100644 --- a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt @@ -108,6 +108,7 @@ import im.vector.app.features.settings.labs.VectorSettingsLabsViewModel import im.vector.app.features.settings.legals.LegalsViewModel import im.vector.app.features.settings.locale.LocalePickerViewModel import im.vector.app.features.settings.notifications.VectorSettingsNotificationPreferenceViewModel +import im.vector.app.features.settings.notifications.VectorSettingsPushRuleNotificationPreferenceViewModel import im.vector.app.features.settings.push.PushGatewaysViewModel import im.vector.app.features.settings.threepids.ThreePidsSettingsViewModel import im.vector.app.features.share.IncomingShareViewModel @@ -694,6 +695,13 @@ interface MavericksViewModelModule { factory: VectorSettingsNotificationPreferenceViewModel.Factory ): MavericksAssistedViewModelFactory<*, *> + @Binds + @IntoMap + @MavericksViewModelKey(VectorSettingsPushRuleNotificationPreferenceViewModel::class) + fun vectorSettingsPushRuleNotificationPreferenceViewModelFactory( + factory: VectorSettingsPushRuleNotificationPreferenceViewModel.Factory + ): MavericksAssistedViewModelFactory<*, *> + @Binds @IntoMap @MavericksViewModelKey(SetLinkViewModel::class) diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceFragment.kt index 33f1b2dc6d..e3ea07f9f5 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceFragment.kt @@ -16,19 +16,36 @@ package im.vector.app.features.settings.notifications -import androidx.lifecycle.lifecycleScope +import android.os.Bundle +import android.view.View import androidx.preference.Preference +import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.withState import im.vector.app.core.preference.VectorCheckboxPreference import im.vector.app.features.settings.VectorSettingsBaseFragment -import kotlinx.coroutines.launch -import org.matrix.android.sdk.api.session.pushrules.RuleKind import org.matrix.android.sdk.api.session.pushrules.rest.PushRuleAndKind abstract class VectorSettingsPushRuleNotificationPreferenceFragment : VectorSettingsBaseFragment() { + private val viewModel: VectorSettingsPushRuleNotificationPreferenceViewModel by fragmentViewModel() + abstract val prefKeyToPushRuleId: Map + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + observeViewEvents() + } + + private fun observeViewEvents() { + viewModel.observeViewEvents { + when (it) { + is VectorSettingsPushRuleNotificationPreferenceViewEvent.Failure -> refreshDisplay() + is VectorSettingsPushRuleNotificationPreferenceViewEvent.PushRuleUpdated -> updatePreference(it.ruleId, it.enabled) + } + } + } + override fun bindPref() { for (preferenceKey in prefKeyToPushRuleId.keys) { val preference = findPreference(preferenceKey)!! @@ -42,45 +59,29 @@ abstract class VectorSettingsPushRuleNotificationPreferenceFragment : val initialIndex = ruleAndKind.pushRule.notificationIndex preference.isChecked = initialIndex != NotificationIndex.OFF preference.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> - updatePushRule(ruleAndKind.pushRule.ruleId, ruleAndKind.kind, newValue as Boolean, preference) + viewModel.handle(VectorSettingsPushRuleNotificationPreferenceViewAction.UpdatePushRule(ruleAndKind, newValue as Boolean)) false } } } } - fun updatePushRule(ruleId: String, kind: RuleKind, checked: Boolean, preference: VectorCheckboxPreference) { - val newIndex = if (checked) NotificationIndex.NOISY else NotificationIndex.OFF - val standardAction = getStandardAction(ruleId, newIndex) ?: return - val enabled = standardAction != StandardActions.Disabled - val newActions = standardAction.actions - displayLoadingView() - - lifecycleScope.launch { - val result = runCatching { - session.pushRuleService().updatePushRuleActions( - kind, - ruleId, - enabled, - newActions - ) - } + override fun invalidate() = withState(viewModel) { state -> + if (state.isLoading) { + displayLoadingView() + } else { hideLoadingView() - if (!isAdded) { - return@launch - } - result.onSuccess { - preference.isChecked = checked - } - result.onFailure { failure -> - // Restore the previous value - refreshDisplay() - displayErrorDialog(failure) - } } } - fun refreshDisplay() { + protected fun refreshDisplay() { listView?.adapter?.notifyDataSetChanged() } + + private fun updatePreference(ruleId: String, checked: Boolean) { + val preferenceKey = prefKeyToPushRuleId.entries.find { it.value == ruleId }?.key ?: return + val preference = findPreference(preferenceKey) ?: return + + preference.isChecked = checked + } } diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceViewAction.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceViewAction.kt new file mode 100644 index 0000000000..766b1aa730 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceViewAction.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.notifications + +import im.vector.app.core.platform.VectorViewModelAction +import org.matrix.android.sdk.api.session.pushrules.rest.PushRuleAndKind + +sealed interface VectorSettingsPushRuleNotificationPreferenceViewAction : VectorViewModelAction { + data class UpdatePushRule(val pushRuleAndKind: PushRuleAndKind, val checked: Boolean) : VectorSettingsPushRuleNotificationPreferenceViewAction +} diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceViewEvent.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceViewEvent.kt new file mode 100644 index 0000000000..be8cd6c47a --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceViewEvent.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.notifications + +import im.vector.app.core.platform.VectorViewEvents + +sealed interface VectorSettingsPushRuleNotificationPreferenceViewEvent : VectorViewEvents { + data class PushRuleUpdated(val ruleId: String, val enabled: Boolean) : VectorSettingsPushRuleNotificationPreferenceViewEvent + data class Failure(val throwable: Throwable) : VectorSettingsPushRuleNotificationPreferenceViewEvent +} diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceViewModel.kt new file mode 100644 index 0000000000..0d2d2b9876 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceViewModel.kt @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.notifications + +import com.airbnb.mvrx.MavericksViewModelFactory +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.core.di.MavericksAssistedViewModelFactory +import im.vector.app.core.di.hiltMavericksViewModelFactory +import im.vector.app.core.platform.VectorViewModel +import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.session.pushrules.rest.PushRuleAndKind + +class VectorSettingsPushRuleNotificationPreferenceViewModel @AssistedInject constructor( + @Assisted initialState: VectorSettingsPushRuleNotificationPreferenceViewState, + private val activeSessionHolder: ActiveSessionHolder, +) : VectorViewModel(initialState) { + + @AssistedFactory + interface Factory : MavericksAssistedViewModelFactory { + override fun create(initialState: VectorSettingsPushRuleNotificationPreferenceViewState): VectorSettingsPushRuleNotificationPreferenceViewModel + } + + companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() + + override fun handle(action: VectorSettingsPushRuleNotificationPreferenceViewAction) { + when (action) { + is VectorSettingsPushRuleNotificationPreferenceViewAction.UpdatePushRule -> handleUpdatePushRule(action.pushRuleAndKind, action.checked) + } + } + + private fun handleUpdatePushRule(pushRuleAndKind: PushRuleAndKind, checked: Boolean) { + val ruleId = pushRuleAndKind.pushRule.ruleId + val kind = pushRuleAndKind.kind + val newIndex = if (checked) NotificationIndex.NOISY else NotificationIndex.OFF + val standardAction = getStandardAction(ruleId, newIndex) ?: return + val enabled = standardAction != StandardActions.Disabled + val newActions = standardAction.actions + setState { copy(isLoading = true) } + + viewModelScope.launch { + runCatching { + activeSessionHolder.getSafeActiveSession()?.pushRuleService()?.updatePushRuleActions( + kind = kind, + ruleId = ruleId, + enable = enabled, + actions = newActions + ) + }.fold( + onSuccess = { + setState { copy(isLoading = false) } + _viewEvents.post(VectorSettingsPushRuleNotificationPreferenceViewEvent.PushRuleUpdated(ruleId, checked)) + }, + onFailure = { failure -> + setState { copy(isLoading = false) } + _viewEvents.post(VectorSettingsPushRuleNotificationPreferenceViewEvent.Failure(failure)) + } + ) + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceViewState.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceViewState.kt new file mode 100644 index 0000000000..6f9095f1d9 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceViewState.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.notifications + +import com.airbnb.mvrx.MavericksState + +data class VectorSettingsPushRuleNotificationPreferenceViewState( + val isLoading: Boolean = false, +): MavericksState