mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 13:38:49 +03:00
Display ignored users list
This commit is contained in:
parent
fbae3d27c2
commit
9c952b6bc8
18 changed files with 394 additions and 177 deletions
|
@ -125,7 +125,9 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleIgnoredUsers(userAccountDataIgnoredUsers: UserAccountDataIgnoredUsers) {
|
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
|
// TODO If not initial sync, we should execute a init sync
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.session.sync.model.accountdata
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
import im.vector.matrix.android.api.util.JsonDict
|
import im.vector.matrix.android.api.util.JsonDict
|
||||||
|
import im.vector.matrix.android.api.util.emptyJsonDict
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
internal data class IgnoredUsersContent(
|
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
|
* Required. The map of users to ignore. UserId -> empty object for future enhancement
|
||||||
*/
|
*/
|
||||||
@Json(name = "ignored_users") val ignoredUsers: Map<String, JsonDict>
|
@Json(name = "ignored_users") val ignoredUsers: Map<String, JsonDict>
|
||||||
)
|
) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun createWithUserIds(userIds: List<String>): IgnoredUsersContent {
|
||||||
|
return IgnoredUsersContent(
|
||||||
|
ignoredUsers = userIds.associateWith { emptyJsonDict }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -18,24 +18,9 @@ package im.vector.matrix.android.internal.session.sync.model.accountdata
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
import im.vector.matrix.android.api.util.emptyJsonDict
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
internal data class UserAccountDataIgnoredUsers(
|
internal data class UserAccountDataIgnoredUsers(
|
||||||
@Json(name = "type") override val type: String = TYPE_IGNORED_USER_LIST,
|
@Json(name = "type") override val type: String = TYPE_IGNORED_USER_LIST,
|
||||||
@Json(name = "content") val content: IgnoredUsersContent
|
@Json(name = "content") val content: IgnoredUsersContent
|
||||||
) : UserAccountData() {
|
) : UserAccountData()
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun createWithUserIds(userIds: List<String>): UserAccountDataIgnoredUsers {
|
|
||||||
return UserAccountDataIgnoredUsers(
|
|
||||||
content = IgnoredUsersContent(
|
|
||||||
ignoredUsers = userIds.associateWith { emptyJsonDict }
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,7 @@
|
||||||
package im.vector.matrix.android.internal.session.user.accountdata
|
package im.vector.matrix.android.internal.session.user.accountdata
|
||||||
|
|
||||||
import com.zhuinden.monarchy.Monarchy
|
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.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.task.Task
|
||||||
import im.vector.matrix.android.internal.util.awaitTransaction
|
import im.vector.matrix.android.internal.util.awaitTransaction
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -26,20 +24,23 @@ import javax.inject.Inject
|
||||||
/**
|
/**
|
||||||
* Save the ignored users list in DB
|
* Save the ignored users list in DB
|
||||||
*/
|
*/
|
||||||
internal interface SaveIgnoredUsersTask : Task<UserAccountDataIgnoredUsers, Unit> {
|
internal interface SaveIgnoredUsersTask : Task<SaveIgnoredUsersTask.Params, Unit> {
|
||||||
data class Params(val pa: GetPushRulesResponse)
|
data class Params(
|
||||||
|
val userIds: List<String>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class DefaultSaveIgnoredUsersTask @Inject constructor(private val monarchy: Monarchy) : SaveIgnoredUsersTask {
|
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 ->
|
monarchy.awaitTransaction { realm ->
|
||||||
// clear current ignored users
|
// clear current ignored users
|
||||||
realm.where(IgnoredUserEntity::class.java)
|
realm.where(IgnoredUserEntity::class.java)
|
||||||
.findAll()
|
.findAll()
|
||||||
.deleteAllFromRealm()
|
.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 } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,8 @@ import com.zhuinden.monarchy.Monarchy
|
||||||
import im.vector.matrix.android.internal.database.model.IgnoredUserEntity
|
import im.vector.matrix.android.internal.database.model.IgnoredUserEntity
|
||||||
import im.vector.matrix.android.internal.di.UserId
|
import im.vector.matrix.android.internal.di.UserId
|
||||||
import im.vector.matrix.android.internal.network.executeRequest
|
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.UserAccountData
|
||||||
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.task.Task
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ internal interface UpdateIgnoredUserIdsTask : Task<UpdateIgnoredUserIdsTask.Para
|
||||||
|
|
||||||
internal class DefaultUpdateIgnoredUserIdsTask @Inject constructor(private val accountDataApi: AccountDataAPI,
|
internal class DefaultUpdateIgnoredUserIdsTask @Inject constructor(private val accountDataApi: AccountDataAPI,
|
||||||
private val monarchy: Monarchy,
|
private val monarchy: Monarchy,
|
||||||
|
private val saveIgnoredUsersTask: SaveIgnoredUsersTask,
|
||||||
@UserId private val userId: String) : UpdateIgnoredUserIdsTask {
|
@UserId private val userId: String) : UpdateIgnoredUserIdsTask {
|
||||||
|
|
||||||
override suspend fun execute(params: UpdateIgnoredUserIdsTask.Params) {
|
override suspend fun execute(params: UpdateIgnoredUserIdsTask.Params) {
|
||||||
|
@ -43,22 +44,26 @@ internal class DefaultUpdateIgnoredUserIdsTask @Inject constructor(private val a
|
||||||
val ignoredUserIds = monarchy.fetchAllMappedSync(
|
val ignoredUserIds = monarchy.fetchAllMappedSync(
|
||||||
{ realm -> realm.where(IgnoredUserEntity::class.java) },
|
{ realm -> realm.where(IgnoredUserEntity::class.java) },
|
||||||
{ it.userId }
|
{ it.userId }
|
||||||
)
|
).toMutableSet()
|
||||||
|
|
||||||
val original = ignoredUserIds.toList()
|
val original = ignoredUserIds.toList()
|
||||||
|
|
||||||
ignoredUserIds -= params.userIdsToUnIgnore
|
ignoredUserIds.removeAll { it in params.userIdsToUnIgnore }
|
||||||
ignoredUserIds += params.userIdsToIgnore
|
ignoredUserIds.addAll(params.userIdsToIgnore)
|
||||||
|
|
||||||
if (original == ignoredUserIds) {
|
if (original == ignoredUserIds) {
|
||||||
// No change
|
// No change
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val body = UserAccountDataIgnoredUsers.createWithUserIds(ignoredUserIds)
|
val list = ignoredUserIds.toList()
|
||||||
|
val body = IgnoredUsersContent.createWithUserIds(list)
|
||||||
|
|
||||||
return executeRequest {
|
executeRequest<Unit> {
|
||||||
apiCall = accountDataApi.setAccountData(userId, UserAccountData.TYPE_IGNORED_USER_LIST, body)
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,13 +16,22 @@
|
||||||
|
|
||||||
package im.vector.riotx.core.platform
|
package im.vector.riotx.core.platform
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
import com.airbnb.mvrx.*
|
import com.airbnb.mvrx.*
|
||||||
|
import im.vector.riotx.core.utils.LiveEvent
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
|
|
||||||
abstract class VectorViewModel<S : MvRxState>(initialState: S)
|
abstract class VectorViewModel<S : MvRxState>(initialState: S)
|
||||||
: BaseMvRxViewModel<S>(initialState, false) {
|
: BaseMvRxViewModel<S>(initialState, false) {
|
||||||
|
|
||||||
|
// Generic handling of any request error
|
||||||
|
protected val _requestErrorLiveData = MutableLiveData<LiveEvent<Throwable>>()
|
||||||
|
val requestErrorLiveData: LiveData<LiveEvent<Throwable>>
|
||||||
|
get() = _requestErrorLiveData
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method does the same thing as the execute function, but it doesn't subscribe to the stream
|
* 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
|
* so you can use this in a switchMap or a flatMap
|
||||||
|
|
|
@ -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_CONTACT_PREFERENCE_KEYS = "SETTINGS_CONTACT_PREFERENCE_KEYS"
|
||||||
const val SETTINGS_NOTIFICATIONS_TARGETS_PREFERENCE_KEY = "SETTINGS_NOTIFICATIONS_TARGETS_PREFERENCE_KEY"
|
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_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_PREFERENCE_KEY = "SETTINGS_BACKGROUND_SYNC_PREFERENCE_KEY"
|
||||||
const val SETTINGS_BACKGROUND_SYNC_DIVIDER_PREFERENCE_KEY = "SETTINGS_BACKGROUND_SYNC_DIVIDER_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"
|
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_WEEK -> System.currentTimeMillis() / 1000 - 7 * 24 * 60 * 60
|
||||||
MEDIA_SAVING_1_MONTH -> System.currentTimeMillis() / 1000 - 30 * 24 * 60 * 60
|
MEDIA_SAVING_1_MONTH -> System.currentTimeMillis() / 1000 - 30 * 24 * 60 * 60
|
||||||
MEDIA_SAVING_FOREVER -> 0
|
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_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_1_MONTH -> context.getString(R.string.media_saving_period_1_month)
|
||||||
MEDIA_SAVING_FOREVER -> context.getString(R.string.media_saving_period_forever)
|
MEDIA_SAVING_FOREVER -> context.getString(R.string.media_saving_period_forever)
|
||||||
else -> "?"
|
else -> "?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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<VectorPreference>(VectorPreferences.SETTINGS_IGNORE_USERS_DIVIDER_PREFERENCE_KEY)!!
|
|
||||||
}
|
|
||||||
private val mIgnoredUserSettingsCategory by lazy {
|
|
||||||
findPreference<PreferenceCategory>(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<String>() // 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<String>()
|
|
||||||
idsList.add(userId)
|
|
||||||
|
|
||||||
notImplemented()
|
|
||||||
/* TODO
|
|
||||||
session.unIgnoreUsers(idsList, object : MatrixCallback<Unit> {
|
|
||||||
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"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<IgnoredUserItem.Holder>() {
|
||||||
|
|
||||||
|
@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<TextView>(R.id.itemIgnoredUserId)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<String>) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<String> = emptyList(),
|
||||||
|
val unIgnoreRequest: Async<Unit> = Uninitialized
|
||||||
|
) : MvRxState
|
||||||
|
|
||||||
|
|
||||||
|
sealed class IgnoredUsersAction {
|
||||||
|
data class UnIgnore(val userId: String) : IgnoredUsersAction()
|
||||||
|
}
|
||||||
|
|
||||||
|
class IgnoredUsersViewModel @AssistedInject constructor(@Assisted initialState: IgnoredUsersViewState,
|
||||||
|
private val session: Session) : VectorViewModel<IgnoredUsersViewState>(initialState) {
|
||||||
|
|
||||||
|
@AssistedInject.Factory
|
||||||
|
interface Factory {
|
||||||
|
fun create(initialState: IgnoredUsersViewState): IgnoredUsersViewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : MvRxViewModelFactory<IgnoredUsersViewModel, IgnoredUsersViewState> {
|
||||||
|
|
||||||
|
@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<Unit> {
|
||||||
|
override fun onFailure(failure: Throwable) {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
unIgnoreRequest = Fail(failure)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
_requestErrorLiveData.postLiveEvent(failure)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSuccess(data: Unit) {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
unIgnoreRequest = Success(data)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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<Unit>) {
|
||||||
|
when (unIgnoreRequest) {
|
||||||
|
is Loading -> waiting_view.isVisible = true
|
||||||
|
else -> waiting_view.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,17 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<com.airbnb.epoxy.EpoxyRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/epoxyRecyclerView"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
app:itemSpacing="1dp"
|
|
||||||
tools:listitem="@layout/item_pushgateway" />
|
<com.airbnb.epoxy.EpoxyRecyclerView
|
||||||
|
android:id="@+id/epoxyRecyclerView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:itemSpacing="1dp"
|
||||||
|
tools:listitem="@layout/item_pushgateway" />
|
||||||
|
|
||||||
|
<include layout="@layout/merge_overlay_waiting_view" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
21
vector/src/main/res/layout/item_ignored_user.xml
Normal file
21
vector/src/main/res/layout/item_ignored_user.xml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/itemIgnoredUserId"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?riotx_background"
|
||||||
|
android:clickable="true"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:lines="2"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:minHeight="?listPreferredItemHeight"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:textColor="?riotx_text_primary"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:text="@sample/matrix.json/data/mxid" />
|
||||||
|
|
|
@ -3,8 +3,7 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/waiting_view"
|
android:id="@+id/waiting_view"
|
||||||
|
|
|
@ -4,4 +4,6 @@
|
||||||
<!-- Strings not defined in Riot -->
|
<!-- Strings not defined in Riot -->
|
||||||
<string name="notice_member_no_changes">"%1$s made no changes"</string>
|
<string name="notice_member_no_changes">"%1$s made no changes"</string>
|
||||||
|
|
||||||
|
<string name="no_ignored_users">You are not ignoring any users</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
|
|
||||||
<im.vector.riotx.core.preference.VectorPreferenceCategory
|
|
||||||
android:key="SETTINGS_IGNORED_USERS_PREFERENCE_KEY"
|
|
||||||
android:title="@string/settings_ignored_users" />
|
|
||||||
|
|
||||||
<im.vector.riotx.core.preference.VectorPreferenceDivider android:key="SETTINGS_IGNORE_USERS_DIVIDER_PREFERENCE_KEY" />
|
|
||||||
|
|
||||||
|
|
||||||
</androidx.preference.PreferenceScreen>
|
|
|
@ -37,10 +37,9 @@
|
||||||
|
|
||||||
<im.vector.riotx.core.preference.VectorPreference
|
<im.vector.riotx.core.preference.VectorPreference
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:enabled="@bool/false_not_implemented"
|
|
||||||
android:icon="@drawable/ic_settings_root_ignored_users"
|
android:icon="@drawable/ic_settings_root_ignored_users"
|
||||||
android:title="@string/settings_ignored_users"
|
android:title="@string/settings_ignored_users"
|
||||||
app:fragment="im.vector.riotx.features.settings.VectorSettingsIgnoredUsersFragment" />
|
app:fragment="im.vector.riotx.features.settings.ignored.VectorSettingsIgnoredUsersFragment" />
|
||||||
|
|
||||||
<im.vector.riotx.core.preference.VectorPreference
|
<im.vector.riotx.core.preference.VectorPreference
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
Loading…
Reference in a new issue