From 9c952b6bc824b600ec916efd95be8b82ce52070b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 5 Nov 2019 15:12:23 +0100 Subject: [PATCH] Display ignored users list --- .../sync/UserAccountDataSyncHandler.kt | 4 +- .../model/accountdata/IgnoredUsersContent.kt | 12 +- .../UserAccountDataIgnoredUsers.kt | 17 +-- .../user/accountdata/SaveIgnoredUsersTask.kt | 13 +- .../accountdata/UpdateIgnoredUserIdsTask.kt | 17 ++- .../riotx/core/platform/VectorViewModel.kt | 9 ++ .../features/settings/VectorPreferences.kt | 6 +- .../VectorSettingsIgnoredUsersFragment.kt | 121 ------------------ .../settings/ignored/IgnoredUserItem.kt | 47 +++++++ .../ignored/IgnoredUsersController.kt | 64 +++++++++ .../settings/ignored/IgnoredUsersViewModel.kt | 103 +++++++++++++++ .../VectorSettingsIgnoredUsersFragment.kt | 98 ++++++++++++++ .../fragment_generic_recycler_epoxy.xml | 18 ++- .../src/main/res/layout/item_ignored_user.xml | 21 +++ .../res/layout/merge_overlay_waiting_view.xml | 3 +- vector/src/main/res/values/strings_riotX.xml | 2 + .../res/xml/vector_settings_ignored_users.xml | 13 -- .../src/main/res/xml/vector_settings_root.xml | 3 +- 18 files changed, 394 insertions(+), 177 deletions(-) delete mode 100644 vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsIgnoredUsersFragment.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUserItem.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUsersController.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUsersViewModel.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt create mode 100644 vector/src/main/res/layout/item_ignored_user.xml delete mode 100644 vector/src/main/res/xml/vector_settings_ignored_users.xml diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt index 07bf965ae1..56bc005805 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt @@ -125,7 +125,9 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc } private fun handleIgnoredUsers(userAccountDataIgnoredUsers: UserAccountDataIgnoredUsers) { - saveIgnoredUsersTask.configureWith(userAccountDataIgnoredUsers).executeBy(taskExecutor) + saveIgnoredUsersTask + .configureWith(SaveIgnoredUsersTask.Params(userAccountDataIgnoredUsers.content.ignoredUsers.keys.toList())) + .executeBy(taskExecutor) // TODO If not initial sync, we should execute a init sync } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/IgnoredUsersContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/IgnoredUsersContent.kt index c61c122ffe..ea591d79b0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/IgnoredUsersContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/IgnoredUsersContent.kt @@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.session.sync.model.accountdata import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import im.vector.matrix.android.api.util.JsonDict +import im.vector.matrix.android.api.util.emptyJsonDict @JsonClass(generateAdapter = true) internal data class IgnoredUsersContent( @@ -26,4 +27,13 @@ internal data class IgnoredUsersContent( * Required. The map of users to ignore. UserId -> empty object for future enhancement */ @Json(name = "ignored_users") val ignoredUsers: Map -) +) { + + companion object { + fun createWithUserIds(userIds: List): IgnoredUsersContent { + return IgnoredUsersContent( + ignoredUsers = userIds.associateWith { emptyJsonDict } + ) + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataIgnoredUsers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataIgnoredUsers.kt index f6d60b278b..63a7604305 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataIgnoredUsers.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataIgnoredUsers.kt @@ -18,24 +18,9 @@ package im.vector.matrix.android.internal.session.sync.model.accountdata import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import im.vector.matrix.android.api.util.emptyJsonDict @JsonClass(generateAdapter = true) internal data class UserAccountDataIgnoredUsers( @Json(name = "type") override val type: String = TYPE_IGNORED_USER_LIST, @Json(name = "content") val content: IgnoredUsersContent -) : UserAccountData() { - - - companion object { - fun createWithUserIds(userIds: List): UserAccountDataIgnoredUsers { - return UserAccountDataIgnoredUsers( - content = IgnoredUsersContent( - ignoredUsers = userIds.associateWith { emptyJsonDict } - ) - ) - } - } -} - - +) : UserAccountData() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/SaveIgnoredUsersTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/SaveIgnoredUsersTask.kt index ef3a5d0e76..c9a3eef440 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/SaveIgnoredUsersTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/SaveIgnoredUsersTask.kt @@ -16,9 +16,7 @@ package im.vector.matrix.android.internal.session.user.accountdata import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse import im.vector.matrix.android.internal.database.model.IgnoredUserEntity -import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataIgnoredUsers import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.util.awaitTransaction import javax.inject.Inject @@ -26,20 +24,23 @@ import javax.inject.Inject /** * Save the ignored users list in DB */ -internal interface SaveIgnoredUsersTask : Task { - data class Params(val pa: GetPushRulesResponse) +internal interface SaveIgnoredUsersTask : Task { + data class Params( + val userIds: List + ) } internal class DefaultSaveIgnoredUsersTask @Inject constructor(private val monarchy: Monarchy) : SaveIgnoredUsersTask { - override suspend fun execute(params: UserAccountDataIgnoredUsers) { + override suspend fun execute(params: SaveIgnoredUsersTask.Params) { monarchy.awaitTransaction { realm -> // clear current ignored users realm.where(IgnoredUserEntity::class.java) .findAll() .deleteAllFromRealm() - params.content.ignoredUsers.keys.forEach { realm.createObject(IgnoredUserEntity::class.java, it) } + // And save the new received list + params.userIds.forEach { realm.createObject(IgnoredUserEntity::class.java).apply { userId = it } } } } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateIgnoredUserIdsTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateIgnoredUserIdsTask.kt index 45dd4745d3..d098f2620f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateIgnoredUserIdsTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateIgnoredUserIdsTask.kt @@ -20,8 +20,8 @@ import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.internal.database.model.IgnoredUserEntity import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.network.executeRequest +import im.vector.matrix.android.internal.session.sync.model.accountdata.IgnoredUsersContent import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountData -import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataIgnoredUsers import im.vector.matrix.android.internal.task.Task import javax.inject.Inject @@ -36,6 +36,7 @@ internal interface UpdateIgnoredUserIdsTask : Task realm.where(IgnoredUserEntity::class.java) }, { it.userId } - ) + ).toMutableSet() val original = ignoredUserIds.toList() - ignoredUserIds -= params.userIdsToUnIgnore - ignoredUserIds += params.userIdsToIgnore + ignoredUserIds.removeAll { it in params.userIdsToUnIgnore } + ignoredUserIds.addAll(params.userIdsToIgnore) if (original == ignoredUserIds) { // No change return } - val body = UserAccountDataIgnoredUsers.createWithUserIds(ignoredUserIds) + val list = ignoredUserIds.toList() + val body = IgnoredUsersContent.createWithUserIds(list) - return executeRequest { + executeRequest { apiCall = accountDataApi.setAccountData(userId, UserAccountData.TYPE_IGNORED_USER_LIST, body) } + + // Update the DB right now (do not wait for the sync to come back with updated data, for a faster UI update) + saveIgnoredUsersTask.execute(SaveIgnoredUsersTask.Params(list)) } } diff --git a/vector/src/main/java/im/vector/riotx/core/platform/VectorViewModel.kt b/vector/src/main/java/im/vector/riotx/core/platform/VectorViewModel.kt index 9679c20efb..0e13ec12bd 100644 --- a/vector/src/main/java/im/vector/riotx/core/platform/VectorViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/core/platform/VectorViewModel.kt @@ -16,13 +16,22 @@ package im.vector.riotx.core.platform +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import com.airbnb.mvrx.* +import im.vector.riotx.core.utils.LiveEvent import io.reactivex.Observable import io.reactivex.Single abstract class VectorViewModel(initialState: S) : BaseMvRxViewModel(initialState, false) { + // Generic handling of any request error + protected val _requestErrorLiveData = MutableLiveData>() + val requestErrorLiveData: LiveData> + get() = _requestErrorLiveData + + /** * This method does the same thing as the execute function, but it doesn't subscribe to the stream * so you can use this in a switchMap or a flatMap diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt index a593bb6e96..78f57dd548 100755 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt @@ -55,8 +55,6 @@ class VectorPreferences @Inject constructor(private val context: Context) { const val SETTINGS_CONTACT_PREFERENCE_KEYS = "SETTINGS_CONTACT_PREFERENCE_KEYS" const val SETTINGS_NOTIFICATIONS_TARGETS_PREFERENCE_KEY = "SETTINGS_NOTIFICATIONS_TARGETS_PREFERENCE_KEY" const val SETTINGS_NOTIFICATIONS_TARGET_DIVIDER_PREFERENCE_KEY = "SETTINGS_NOTIFICATIONS_TARGET_DIVIDER_PREFERENCE_KEY" - const val SETTINGS_IGNORED_USERS_PREFERENCE_KEY = "SETTINGS_IGNORED_USERS_PREFERENCE_KEY" - const val SETTINGS_IGNORE_USERS_DIVIDER_PREFERENCE_KEY = "SETTINGS_IGNORE_USERS_DIVIDER_PREFERENCE_KEY" const val SETTINGS_BACKGROUND_SYNC_PREFERENCE_KEY = "SETTINGS_BACKGROUND_SYNC_PREFERENCE_KEY" const val SETTINGS_BACKGROUND_SYNC_DIVIDER_PREFERENCE_KEY = "SETTINGS_BACKGROUND_SYNC_DIVIDER_PREFERENCE_KEY" const val SETTINGS_LABS_PREFERENCE_KEY = "SETTINGS_LABS_PREFERENCE_KEY" @@ -544,7 +542,7 @@ class VectorPreferences @Inject constructor(private val context: Context) { MEDIA_SAVING_1_WEEK -> System.currentTimeMillis() / 1000 - 7 * 24 * 60 * 60 MEDIA_SAVING_1_MONTH -> System.currentTimeMillis() / 1000 - 30 * 24 * 60 * 60 MEDIA_SAVING_FOREVER -> 0 - else -> 0 + else -> 0 } } @@ -559,7 +557,7 @@ class VectorPreferences @Inject constructor(private val context: Context) { MEDIA_SAVING_1_WEEK -> context.getString(R.string.media_saving_period_1_week) MEDIA_SAVING_1_MONTH -> context.getString(R.string.media_saving_period_1_month) MEDIA_SAVING_FOREVER -> context.getString(R.string.media_saving_period_forever) - else -> "?" + else -> "?" } } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsIgnoredUsersFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsIgnoredUsersFragment.kt deleted file mode 100644 index 32a6fe8f41..0000000000 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsIgnoredUsersFragment.kt +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2019 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.riotx.features.settings - -import androidx.appcompat.app.AlertDialog -import androidx.preference.Preference -import androidx.preference.PreferenceCategory -import im.vector.riotx.R -import im.vector.riotx.core.preference.VectorPreference -import java.util.ArrayList -import kotlin.Comparator - -class VectorSettingsIgnoredUsersFragment : VectorSettingsBaseFragment() { - - override var titleRes = R.string.settings_ignored_users - override val preferenceXmlRes = R.xml.vector_settings_ignored_users - - // displayed the ignored users list - private val mIgnoredUserSettingsCategoryDivider by lazy { - findPreference(VectorPreferences.SETTINGS_IGNORE_USERS_DIVIDER_PREFERENCE_KEY)!! - } - private val mIgnoredUserSettingsCategory by lazy { - findPreference(VectorPreferences.SETTINGS_IGNORED_USERS_PREFERENCE_KEY)!! - } - - override fun bindPref() { - // Ignore users - refreshIgnoredUsersList() - } - - // ============================================================================================================== - // ignored users list management - // ============================================================================================================== - - /** - * Refresh the ignored users list - */ - private fun refreshIgnoredUsersList() { - val ignoredUsersList = mutableListOf() // TODO session.dataHandler.ignoredUserIds - - ignoredUsersList.sortWith(Comparator { u1, u2 -> - u1.toLowerCase(VectorLocale.applicationLocale).compareTo(u2.toLowerCase(VectorLocale.applicationLocale)) - }) - - val preferenceScreen = preferenceScreen - - preferenceScreen.removePreference(mIgnoredUserSettingsCategory) - preferenceScreen.removePreference(mIgnoredUserSettingsCategoryDivider) - mIgnoredUserSettingsCategory.removeAll() - - if (ignoredUsersList.size > 0) { - preferenceScreen.addPreference(mIgnoredUserSettingsCategoryDivider) - preferenceScreen.addPreference(mIgnoredUserSettingsCategory) - - for (userId in ignoredUsersList) { - val preference = Preference(activity) - - preference.title = userId - preference.key = IGNORED_USER_KEY_BASE + userId - - preference.onPreferenceClickListener = Preference.OnPreferenceClickListener { - activity?.let { - AlertDialog.Builder(it) - .setMessage(getString(R.string.settings_unignore_user, userId)) - .setPositiveButton(R.string.yes) { _, _ -> - displayLoadingView() - - val idsList = ArrayList() - idsList.add(userId) - - notImplemented() - /* TODO - session.unIgnoreUsers(idsList, object : MatrixCallback { - override fun onSuccess(info: Void?) { - onCommonDone(null) - } - - override fun onNetworkError(e: Exception) { - onCommonDone(e.localizedMessage) - } - - override fun onMatrixError(e: MatrixError) { - onCommonDone(e.localizedMessage) - } - - override fun onUnexpectedError(e: Exception) { - onCommonDone(e.localizedMessage) - } - }) - */ - } - .setNegativeButton(R.string.no, null) - .show() - } - - false - } - - mIgnoredUserSettingsCategory.addPreference(preference) - } - } - } - - companion object { - private const val IGNORED_USER_KEY_BASE = "IGNORED_USER_KEY_BASE" - } -} diff --git a/vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUserItem.kt b/vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUserItem.kt new file mode 100644 index 0000000000..2ce7df1dc4 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUserItem.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2019 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.riotx.features.settings.ignored + +import android.widget.TextView +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.riotx.R +import im.vector.riotx.core.epoxy.VectorEpoxyHolder +import im.vector.riotx.core.epoxy.VectorEpoxyModel +import im.vector.riotx.core.extensions.setTextOrHide + +/** + * A list item for ignored user. + */ +@EpoxyModelClass(layout = R.layout.item_ignored_user) +abstract class IgnoredUserItem : VectorEpoxyModel() { + + @EpoxyAttribute + var userId: String? = null + + @EpoxyAttribute + var itemClickAction: (() -> Unit)? = null + + override fun bind(holder: Holder) { + holder.userIdText.setTextOrHide(userId) + + holder.userIdText.setOnClickListener { itemClickAction?.invoke() } + } + + class Holder : VectorEpoxyHolder() { + val userIdText by bind(R.id.itemIgnoredUserId) + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUsersController.kt b/vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUsersController.kt new file mode 100644 index 0000000000..845f9bfb73 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUsersController.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2019 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.riotx.features.settings.ignored + +import com.airbnb.epoxy.EpoxyController +import im.vector.riotx.R +import im.vector.riotx.core.epoxy.noResultItem +import im.vector.riotx.core.resources.StringProvider +import javax.inject.Inject + +class IgnoredUsersController @Inject constructor(private val stringProvider: StringProvider) : EpoxyController() { + + var callback: Callback? = null + private var viewState: IgnoredUsersViewState? = null + + init { + requestModelBuild() + } + + fun update(viewState: IgnoredUsersViewState) { + this.viewState = viewState + requestModelBuild() + } + + override fun buildModels() { + val nonNullViewState = viewState ?: return + buildIgnoredUserModels(nonNullViewState.ignoredUserIds) + } + + private fun buildIgnoredUserModels(userIds: List) { + if (userIds.isEmpty()) { + noResultItem { + id("empty") + text(stringProvider.getString(R.string.no_ignored_users)) + } + } else { + userIds.forEach { userId -> + ignoredUserItem { + id(userId) + userId(userId) + itemClickAction { callback?.onUserIdClicked(userId) } + } + } + } + } + + interface Callback { + fun onUserIdClicked(userId: String) + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUsersViewModel.kt b/vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUsersViewModel.kt new file mode 100644 index 0000000000..fae596032e --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUsersViewModel.kt @@ -0,0 +1,103 @@ +/* + * Copyright 2019 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.riotx.features.settings.ignored + +import com.airbnb.mvrx.* +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject +import im.vector.matrix.android.api.MatrixCallback +import im.vector.matrix.android.api.session.Session +import im.vector.matrix.rx.rx +import im.vector.riotx.core.extensions.postLiveEvent +import im.vector.riotx.core.platform.VectorViewModel + +data class IgnoredUsersViewState( + val ignoredUserIds: List = emptyList(), + val unIgnoreRequest: Async = Uninitialized +) : MvRxState + + +sealed class IgnoredUsersAction { + data class UnIgnore(val userId: String) : IgnoredUsersAction() +} + +class IgnoredUsersViewModel @AssistedInject constructor(@Assisted initialState: IgnoredUsersViewState, + private val session: Session) : VectorViewModel(initialState) { + + @AssistedInject.Factory + interface Factory { + fun create(initialState: IgnoredUsersViewState): IgnoredUsersViewModel + } + + companion object : MvRxViewModelFactory { + + @JvmStatic + override fun create(viewModelContext: ViewModelContext, state: IgnoredUsersViewState): IgnoredUsersViewModel? { + val ignoredUsersFragment: VectorSettingsIgnoredUsersFragment = (viewModelContext as FragmentViewModelContext).fragment() + return ignoredUsersFragment.ignoredUsersViewModelFactory.create(state) + } + } + + init { + observeIgnoredUsers() + } + + private fun observeIgnoredUsers() { + session.rx() + .liveIgnoredUserIds() + .execute { async -> + copy( + ignoredUserIds = async.invoke().orEmpty() + ) + } + } + + fun handle(action: IgnoredUsersAction) { + when (action) { + is IgnoredUsersAction.UnIgnore -> handleUnIgnore(action) + } + } + + private fun handleUnIgnore(action: IgnoredUsersAction.UnIgnore) { + setState { + copy( + unIgnoreRequest = Loading() + ) + } + + session.unIgnoreUserIds(listOf(action.userId), object : MatrixCallback { + override fun onFailure(failure: Throwable) { + setState { + copy( + unIgnoreRequest = Fail(failure) + ) + } + + _requestErrorLiveData.postLiveEvent(failure) + } + + override fun onSuccess(data: Unit) { + setState { + copy( + unIgnoreRequest = Success(data) + ) + } + } + }) + } + +} diff --git a/vector/src/main/java/im/vector/riotx/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt new file mode 100644 index 0000000000..11e473ae24 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt @@ -0,0 +1,98 @@ +/* + * Copyright 2019 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.riotx.features.settings.ignored + +import android.os.Bundle +import android.view.View +import androidx.appcompat.app.AlertDialog +import androidx.core.view.isVisible +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.Loading +import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.withState +import im.vector.riotx.R +import im.vector.riotx.core.error.ErrorFormatter +import im.vector.riotx.core.extensions.observeEvent +import im.vector.riotx.core.platform.VectorBaseActivity +import im.vector.riotx.core.platform.VectorBaseFragment +import kotlinx.android.synthetic.main.fragment_generic_recycler_epoxy.* +import kotlinx.android.synthetic.main.merge_overlay_waiting_view.* +import javax.inject.Inject + +class VectorSettingsIgnoredUsersFragment @Inject constructor( + val ignoredUsersViewModelFactory: IgnoredUsersViewModel.Factory, + private val ignoredUsersController: IgnoredUsersController, + private val errorFormatter: ErrorFormatter +) : VectorBaseFragment(), IgnoredUsersController.Callback { + + override fun getLayoutResId() = R.layout.fragment_generic_recycler_epoxy + + private val ignoredUsersViewModel: IgnoredUsersViewModel by fragmentViewModel() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + waiting_view_status_text.setText(R.string.please_wait) + waiting_view_status_text.isVisible = true + ignoredUsersController.callback = this + epoxyRecyclerView.setController(ignoredUsersController) + ignoredUsersViewModel.requestErrorLiveData.observeEvent(this) { + displayErrorDialog(it) + } + } + + override fun onResume() { + super.onResume() + + (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_ignored_users) + } + + override fun onUserIdClicked(userId: String) { + AlertDialog.Builder(requireActivity()) + .setMessage(getString(R.string.settings_unignore_user, userId)) + .setPositiveButton(R.string.yes) { _, _ -> + ignoredUsersViewModel.handle(IgnoredUsersAction.UnIgnore(userId)) + } + .setNegativeButton(R.string.no, null) + .show() + } + + private fun displayErrorDialog(throwable: Throwable) { + AlertDialog.Builder(requireActivity()) + .setTitle(R.string.dialog_title_error) + .setMessage(errorFormatter.toHumanReadable(throwable)) + .setPositiveButton(R.string.ok, null) + .show() + } + + // ============================================================================================================== + // ignored users list management + // ============================================================================================================== + + override fun invalidate() = withState(ignoredUsersViewModel) { state -> + ignoredUsersController.update(state) + + handleUnIgnoreRequestStatus(state.unIgnoreRequest) + } + + private fun handleUnIgnoreRequestStatus(unIgnoreRequest: Async) { + when (unIgnoreRequest) { + is Loading -> waiting_view.isVisible = true + else -> waiting_view.isVisible = false + } + } +} diff --git a/vector/src/main/res/layout/fragment_generic_recycler_epoxy.xml b/vector/src/main/res/layout/fragment_generic_recycler_epoxy.xml index c794e8a5fa..3f02081b16 100644 --- a/vector/src/main/res/layout/fragment_generic_recycler_epoxy.xml +++ b/vector/src/main/res/layout/fragment_generic_recycler_epoxy.xml @@ -1,9 +1,17 @@ - + android:layout_height="match_parent"> + + + + + + diff --git a/vector/src/main/res/layout/item_ignored_user.xml b/vector/src/main/res/layout/item_ignored_user.xml new file mode 100644 index 0000000000..7003bb30ae --- /dev/null +++ b/vector/src/main/res/layout/item_ignored_user.xml @@ -0,0 +1,21 @@ + + + diff --git a/vector/src/main/res/layout/merge_overlay_waiting_view.xml b/vector/src/main/res/layout/merge_overlay_waiting_view.xml index 8f09ed0988..b7e7bf41c7 100644 --- a/vector/src/main/res/layout/merge_overlay_waiting_view.xml +++ b/vector/src/main/res/layout/merge_overlay_waiting_view.xml @@ -3,8 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical"> + android:layout_height="match_parent"> "%1$s made no changes" + You are not ignoring any users + diff --git a/vector/src/main/res/xml/vector_settings_ignored_users.xml b/vector/src/main/res/xml/vector_settings_ignored_users.xml deleted file mode 100644 index 4ad8aed5b6..0000000000 --- a/vector/src/main/res/xml/vector_settings_ignored_users.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/vector/src/main/res/xml/vector_settings_root.xml b/vector/src/main/res/xml/vector_settings_root.xml index e0cb4f778b..894784767a 100644 --- a/vector/src/main/res/xml/vector_settings_root.xml +++ b/vector/src/main/res/xml/vector_settings_root.xml @@ -37,10 +37,9 @@ + app:fragment="im.vector.riotx.features.settings.ignored.VectorSettingsIgnoredUsersFragment" />