Merge pull request #5767 from vector-im/feature/bma/unignore_user

Unignore user must perform an initial sync
This commit is contained in:
Benoit Marty 2022-04-14 17:31:32 +02:00 committed by GitHub
commit 97f2206f2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 241 additions and 150 deletions

1
changelog.d/5767.bugfix Normal file
View File

@ -0,0 +1 @@
Unignoring a user will perform an initial sync

View File

@ -75,11 +75,14 @@ interface UserService {
/** /**
* Ignore users * Ignore users
* Note: once done, for the change to take effect, you have to request an initial sync.
* This may be improved in the future
*/ */
suspend fun ignoreUserIds(userIds: List<String>) suspend fun ignoreUserIds(userIds: List<String>)
/** /**
* Un-ignore some users * Un-ignore some users
* Note: once done, for the change to take effect, you have to request an initial sync.
*/ */
suspend fun unIgnoreUserIds(userIds: List<String>) suspend fun unIgnoreUserIds(userIds: List<String>)
} }

View File

@ -119,6 +119,8 @@ import im.vector.app.core.utils.startInstallFromSourceIntent
import im.vector.app.core.utils.toast import im.vector.app.core.utils.toast
import im.vector.app.databinding.DialogReportContentBinding import im.vector.app.databinding.DialogReportContentBinding
import im.vector.app.databinding.FragmentTimelineBinding import im.vector.app.databinding.FragmentTimelineBinding
import im.vector.app.features.MainActivity
import im.vector.app.features.MainActivityArgs
import im.vector.app.features.analytics.extensions.toAnalyticsInteraction import im.vector.app.features.analytics.extensions.toAnalyticsInteraction
import im.vector.app.features.analytics.plan.Interaction import im.vector.app.features.analytics.plan.Interaction
import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.analytics.plan.MobileScreen
@ -136,6 +138,7 @@ import im.vector.app.features.call.conference.ConferenceEventObserver
import im.vector.app.features.call.conference.JitsiCallViewModel import im.vector.app.features.call.conference.JitsiCallViewModel
import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.call.webrtc.WebRtcCallManager
import im.vector.app.features.command.Command import im.vector.app.features.command.Command
import im.vector.app.features.command.ParsedCommand
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity
import im.vector.app.features.crypto.verification.VerificationBottomSheet import im.vector.app.features.crypto.verification.VerificationBottomSheet
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
@ -438,6 +441,7 @@ class TimelineFragment @Inject constructor(
messageComposerViewModel.observeViewEvents { messageComposerViewModel.observeViewEvents {
when (it) { when (it) {
is MessageComposerViewEvents.JoinRoomCommandSuccess -> handleJoinedToAnotherRoom(it) is MessageComposerViewEvents.JoinRoomCommandSuccess -> handleJoinedToAnotherRoom(it)
is MessageComposerViewEvents.SlashCommandConfirmationRequest -> handleSlashCommandConfirmationRequest(it)
is MessageComposerViewEvents.SendMessageResult -> renderSendMessageResult(it) is MessageComposerViewEvents.SendMessageResult -> renderSendMessageResult(it)
is MessageComposerViewEvents.ShowMessage -> showSnackWithMessage(it.message) is MessageComposerViewEvents.ShowMessage -> showSnackWithMessage(it.message)
is MessageComposerViewEvents.ShowRoomUpgradeDialog -> handleShowRoomUpgradeDialog(it) is MessageComposerViewEvents.ShowRoomUpgradeDialog -> handleShowRoomUpgradeDialog(it)
@ -496,6 +500,25 @@ class TimelineFragment @Inject constructor(
} }
} }
private fun handleSlashCommandConfirmationRequest(action: MessageComposerViewEvents.SlashCommandConfirmationRequest) {
when (action.parsedCommand) {
is ParsedCommand.UnignoreUser -> promptUnignoreUser(action.parsedCommand)
else -> TODO("Add case for ${action.parsedCommand.javaClass.simpleName}")
}
lockSendButton = false
}
private fun promptUnignoreUser(command: ParsedCommand.UnignoreUser) {
MaterialAlertDialogBuilder(requireActivity())
.setTitle(R.string.room_participants_action_unignore_title)
.setMessage(getString(R.string.settings_unignore_user, command.userId))
.setPositiveButton(R.string.unignore) { _, _ ->
messageComposerViewModel.handle(MessageComposerAction.SlashCommandConfirmed(command))
}
.setNegativeButton(R.string.action_cancel, null)
.show()
}
private fun renderVoiceMessageMode(content: String) { private fun renderVoiceMessageMode(content: String) {
ContentAttachmentData.fromJsonString(content)?.let { audioAttachmentData -> ContentAttachmentData.fromJsonString(content)?.let { audioAttachmentData ->
views.voiceMessageRecorderView.isVisible = true views.voiceMessageRecorderView.isVisible = true
@ -1686,9 +1709,7 @@ class TimelineFragment @Inject constructor(
displayCommandError(getString(R.string.unrecognized_command, sendMessageResult.command)) displayCommandError(getString(R.string.unrecognized_command, sendMessageResult.command))
} }
is MessageComposerViewEvents.SlashCommandResultOk -> { is MessageComposerViewEvents.SlashCommandResultOk -> {
dismissLoadingDialog() handleSlashCommandResultOk(sendMessageResult.parsedCommand)
views.composerLayout.setTextIfDifferent("")
sendMessageResult.messageRes?.let { showSnackWithMessage(getString(it)) }
} }
is MessageComposerViewEvents.SlashCommandResultError -> { is MessageComposerViewEvents.SlashCommandResultError -> {
dismissLoadingDialog() dismissLoadingDialog()
@ -1705,6 +1726,21 @@ class TimelineFragment @Inject constructor(
lockSendButton = false lockSendButton = false
} }
private fun handleSlashCommandResultOk(parsedCommand: ParsedCommand) {
dismissLoadingDialog()
views.composerLayout.setTextIfDifferent("")
when (parsedCommand) {
is ParsedCommand.SetMarkdown -> {
showSnackWithMessage(getString(if (parsedCommand.enable) R.string.markdown_has_been_enabled else R.string.markdown_has_been_disabled))
}
is ParsedCommand.UnignoreUser -> {
// A user has been un-ignored, perform a initial sync
MainActivity.restartApp(requireActivity(), MainActivityArgs(clearCache = true))
}
else -> Unit
}
}
private fun displayCommandError(message: String) { private fun displayCommandError(message: String) {
MaterialAlertDialogBuilder(requireActivity()) MaterialAlertDialogBuilder(requireActivity())
.setTitle(R.string.command_error) .setTitle(R.string.command_error)

View File

@ -17,6 +17,7 @@
package im.vector.app.features.home.room.detail.composer package im.vector.app.features.home.room.detail.composer
import im.vector.app.core.platform.VectorViewModelAction import im.vector.app.core.platform.VectorViewModelAction
import im.vector.app.features.command.ParsedCommand
import im.vector.app.features.home.room.detail.composer.voice.VoiceMessageRecorderView import im.vector.app.features.home.room.detail.composer.voice.VoiceMessageRecorderView
import org.matrix.android.sdk.api.session.content.ContentAttachmentData import org.matrix.android.sdk.api.session.content.ContentAttachmentData
import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
@ -30,6 +31,7 @@ sealed class MessageComposerAction : VectorViewModelAction {
data class UserIsTyping(val isTyping: Boolean) : MessageComposerAction() data class UserIsTyping(val isTyping: Boolean) : MessageComposerAction()
data class OnTextChanged(val text: CharSequence) : MessageComposerAction() data class OnTextChanged(val text: CharSequence) : MessageComposerAction()
data class OnEntersBackground(val composerText: String) : MessageComposerAction() data class OnEntersBackground(val composerText: String) : MessageComposerAction()
data class SlashCommandConfirmed(val parsedCommand: ParsedCommand) : MessageComposerAction()
// Voice Message // Voice Message
data class InitializeVoiceRecorder(val attachmentData: ContentAttachmentData) : MessageComposerAction() data class InitializeVoiceRecorder(val attachmentData: ContentAttachmentData) : MessageComposerAction()

View File

@ -16,9 +16,9 @@
package im.vector.app.features.home.room.detail.composer package im.vector.app.features.home.room.detail.composer
import androidx.annotation.StringRes
import im.vector.app.core.platform.VectorViewEvents import im.vector.app.core.platform.VectorViewEvents
import im.vector.app.features.command.Command import im.vector.app.features.command.Command
import im.vector.app.features.command.ParsedCommand
sealed class MessageComposerViewEvents : VectorViewEvents { sealed class MessageComposerViewEvents : VectorViewEvents {
@ -30,13 +30,14 @@ sealed class MessageComposerViewEvents : VectorViewEvents {
object MessageSent : SendMessageResult() object MessageSent : SendMessageResult()
data class JoinRoomCommandSuccess(val roomId: String) : SendMessageResult() data class JoinRoomCommandSuccess(val roomId: String) : SendMessageResult()
class SlashCommandError(val command: Command) : SendMessageResult() data class SlashCommandError(val command: Command) : SendMessageResult()
class SlashCommandUnknown(val command: String) : SendMessageResult() data class SlashCommandUnknown(val command: String) : SendMessageResult()
class SlashCommandNotSupportedInThreads(val command: Command) : SendMessageResult() data class SlashCommandNotSupportedInThreads(val command: Command) : SendMessageResult()
data class SlashCommandHandled(@StringRes val messageRes: Int? = null) : SendMessageResult()
object SlashCommandLoading : SendMessageResult() object SlashCommandLoading : SendMessageResult()
data class SlashCommandResultOk(@StringRes val messageRes: Int? = null) : SendMessageResult() data class SlashCommandResultOk(val parsedCommand: ParsedCommand) : SendMessageResult()
class SlashCommandResultError(val throwable: Throwable) : SendMessageResult() data class SlashCommandResultError(val throwable: Throwable) : SendMessageResult()
data class SlashCommandConfirmationRequest(val parsedCommand: ParsedCommand) : MessageComposerViewEvents()
data class OpenRoomMemberProfile(val userId: String) : MessageComposerViewEvents() data class OpenRoomMemberProfile(val userId: String) : MessageComposerViewEvents()

View File

@ -110,6 +110,7 @@ class MessageComposerViewModel @AssistedInject constructor(
is MessageComposerAction.VoiceWaveformTouchedUp -> handleVoiceWaveformTouchedUp(action) is MessageComposerAction.VoiceWaveformTouchedUp -> handleVoiceWaveformTouchedUp(action)
is MessageComposerAction.VoiceWaveformMovedTo -> handleVoiceWaveformMovedTo(action) is MessageComposerAction.VoiceWaveformMovedTo -> handleVoiceWaveformMovedTo(action)
is MessageComposerAction.AudioSeekBarMovedTo -> handleAudioSeekBarMovedTo(action) is MessageComposerAction.AudioSeekBarMovedTo -> handleAudioSeekBarMovedTo(action)
is MessageComposerAction.SlashCommandConfirmed -> handleSlashCommandConfirmed(action)
} }
} }
@ -195,7 +196,7 @@ class MessageComposerViewModel @AssistedInject constructor(
} }
when (state.sendMode) { when (state.sendMode) {
is SendMode.Regular -> { is SendMode.Regular -> {
when (val slashCommandResult = commandParser.parseSlashCommand( when (val parsedCommand = commandParser.parseSlashCommand(
textMessage = action.text, textMessage = action.text,
isInThreadTimeline = state.isInThreadTimeline())) { isInThreadTimeline = state.isInThreadTimeline())) {
is ParsedCommand.ErrorNotACommand -> { is ParsedCommand.ErrorNotACommand -> {
@ -213,118 +214,117 @@ class MessageComposerViewModel @AssistedInject constructor(
popDraft() popDraft()
} }
is ParsedCommand.ErrorSyntax -> { is ParsedCommand.ErrorSyntax -> {
_viewEvents.post(MessageComposerViewEvents.SlashCommandError(slashCommandResult.command)) _viewEvents.post(MessageComposerViewEvents.SlashCommandError(parsedCommand.command))
} }
is ParsedCommand.ErrorEmptySlashCommand -> { is ParsedCommand.ErrorEmptySlashCommand -> {
_viewEvents.post(MessageComposerViewEvents.SlashCommandUnknown("/")) _viewEvents.post(MessageComposerViewEvents.SlashCommandUnknown("/"))
} }
is ParsedCommand.ErrorUnknownSlashCommand -> { is ParsedCommand.ErrorUnknownSlashCommand -> {
_viewEvents.post(MessageComposerViewEvents.SlashCommandUnknown(slashCommandResult.slashCommand)) _viewEvents.post(MessageComposerViewEvents.SlashCommandUnknown(parsedCommand.slashCommand))
} }
is ParsedCommand.ErrorCommandNotSupportedInThreads -> { is ParsedCommand.ErrorCommandNotSupportedInThreads -> {
_viewEvents.post(MessageComposerViewEvents.SlashCommandNotSupportedInThreads(slashCommandResult.command)) _viewEvents.post(MessageComposerViewEvents.SlashCommandNotSupportedInThreads(parsedCommand.command))
} }
is ParsedCommand.SendPlainText -> { is ParsedCommand.SendPlainText -> {
// Send the text message to the room, without markdown // Send the text message to the room, without markdown
if (state.rootThreadEventId != null) { if (state.rootThreadEventId != null) {
room.replyInThread( room.replyInThread(
rootThreadEventId = state.rootThreadEventId, rootThreadEventId = state.rootThreadEventId,
replyInThreadText = slashCommandResult.message, replyInThreadText = parsedCommand.message,
autoMarkdown = false) autoMarkdown = false)
} else { } else {
room.sendTextMessage(slashCommandResult.message, autoMarkdown = false) room.sendTextMessage(parsedCommand.message, autoMarkdown = false)
} }
_viewEvents.post(MessageComposerViewEvents.MessageSent) _viewEvents.post(MessageComposerViewEvents.MessageSent)
popDraft() popDraft()
} }
is ParsedCommand.ChangeRoomName -> { is ParsedCommand.ChangeRoomName -> {
handleChangeRoomNameSlashCommand(slashCommandResult) handleChangeRoomNameSlashCommand(parsedCommand)
} }
is ParsedCommand.Invite -> { is ParsedCommand.Invite -> {
handleInviteSlashCommand(slashCommandResult) handleInviteSlashCommand(parsedCommand)
} }
is ParsedCommand.Invite3Pid -> { is ParsedCommand.Invite3Pid -> {
handleInvite3pidSlashCommand(slashCommandResult) handleInvite3pidSlashCommand(parsedCommand)
} }
is ParsedCommand.SetUserPowerLevel -> { is ParsedCommand.SetUserPowerLevel -> {
handleSetUserPowerLevel(slashCommandResult) handleSetUserPowerLevel(parsedCommand)
} }
is ParsedCommand.ClearScalarToken -> { is ParsedCommand.ClearScalarToken -> {
// TODO // TODO
_viewEvents.post(MessageComposerViewEvents.SlashCommandNotImplemented) _viewEvents.post(MessageComposerViewEvents.SlashCommandNotImplemented)
} }
is ParsedCommand.SetMarkdown -> { is ParsedCommand.SetMarkdown -> {
vectorPreferences.setMarkdownEnabled(slashCommandResult.enable) vectorPreferences.setMarkdownEnabled(parsedCommand.enable)
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk( _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
if (slashCommandResult.enable) R.string.markdown_has_been_enabled else R.string.markdown_has_been_disabled))
popDraft() popDraft()
} }
is ParsedCommand.BanUser -> { is ParsedCommand.BanUser -> {
handleBanSlashCommand(slashCommandResult) handleBanSlashCommand(parsedCommand)
} }
is ParsedCommand.UnbanUser -> { is ParsedCommand.UnbanUser -> {
handleUnbanSlashCommand(slashCommandResult) handleUnbanSlashCommand(parsedCommand)
} }
is ParsedCommand.IgnoreUser -> { is ParsedCommand.IgnoreUser -> {
handleIgnoreSlashCommand(slashCommandResult) handleIgnoreSlashCommand(parsedCommand)
} }
is ParsedCommand.UnignoreUser -> { is ParsedCommand.UnignoreUser -> {
handleUnignoreSlashCommand(slashCommandResult) handleUnignoreSlashCommand(parsedCommand)
} }
is ParsedCommand.RemoveUser -> { is ParsedCommand.RemoveUser -> {
handleRemoveSlashCommand(slashCommandResult) handleRemoveSlashCommand(parsedCommand)
} }
is ParsedCommand.JoinRoom -> { is ParsedCommand.JoinRoom -> {
handleJoinToAnotherRoomSlashCommand(slashCommandResult) handleJoinToAnotherRoomSlashCommand(parsedCommand)
popDraft() popDraft()
} }
is ParsedCommand.PartRoom -> { is ParsedCommand.PartRoom -> {
handlePartSlashCommand(slashCommandResult) handlePartSlashCommand(parsedCommand)
} }
is ParsedCommand.SendEmote -> { is ParsedCommand.SendEmote -> {
if (state.rootThreadEventId != null) { if (state.rootThreadEventId != null) {
room.replyInThread( room.replyInThread(
rootThreadEventId = state.rootThreadEventId, rootThreadEventId = state.rootThreadEventId,
replyInThreadText = slashCommandResult.message, replyInThreadText = parsedCommand.message,
msgType = MessageType.MSGTYPE_EMOTE, msgType = MessageType.MSGTYPE_EMOTE,
autoMarkdown = action.autoMarkdown) autoMarkdown = action.autoMarkdown)
} else { } else {
room.sendTextMessage(slashCommandResult.message, msgType = MessageType.MSGTYPE_EMOTE, autoMarkdown = action.autoMarkdown) room.sendTextMessage(parsedCommand.message, msgType = MessageType.MSGTYPE_EMOTE, autoMarkdown = action.autoMarkdown)
} }
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk()) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
popDraft() popDraft()
} }
is ParsedCommand.SendRainbow -> { is ParsedCommand.SendRainbow -> {
val message = slashCommandResult.message.toString() val message = parsedCommand.message.toString()
if (state.rootThreadEventId != null) { if (state.rootThreadEventId != null) {
room.replyInThread( room.replyInThread(
rootThreadEventId = state.rootThreadEventId, rootThreadEventId = state.rootThreadEventId,
replyInThreadText = slashCommandResult.message, replyInThreadText = parsedCommand.message,
formattedText = rainbowGenerator.generate(message)) formattedText = rainbowGenerator.generate(message))
} else { } else {
room.sendFormattedTextMessage(message, rainbowGenerator.generate(message)) room.sendFormattedTextMessage(message, rainbowGenerator.generate(message))
} }
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk()) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
popDraft() popDraft()
} }
is ParsedCommand.SendRainbowEmote -> { is ParsedCommand.SendRainbowEmote -> {
val message = slashCommandResult.message.toString() val message = parsedCommand.message.toString()
if (state.rootThreadEventId != null) { if (state.rootThreadEventId != null) {
room.replyInThread( room.replyInThread(
rootThreadEventId = state.rootThreadEventId, rootThreadEventId = state.rootThreadEventId,
replyInThreadText = slashCommandResult.message, replyInThreadText = parsedCommand.message,
msgType = MessageType.MSGTYPE_EMOTE, msgType = MessageType.MSGTYPE_EMOTE,
formattedText = rainbowGenerator.generate(message)) formattedText = rainbowGenerator.generate(message))
} else { } else {
room.sendFormattedTextMessage(message, rainbowGenerator.generate(message), MessageType.MSGTYPE_EMOTE) room.sendFormattedTextMessage(message, rainbowGenerator.generate(message), MessageType.MSGTYPE_EMOTE)
} }
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk()) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
popDraft() popDraft()
} }
is ParsedCommand.SendSpoiler -> { is ParsedCommand.SendSpoiler -> {
val text = "[${stringProvider.getString(R.string.spoiler)}](${slashCommandResult.message})" val text = "[${stringProvider.getString(R.string.spoiler)}](${parsedCommand.message})"
val formattedText = "<span data-mx-spoiler>${slashCommandResult.message}</span>" val formattedText = "<span data-mx-spoiler>${parsedCommand.message}</span>"
if (state.rootThreadEventId != null) { if (state.rootThreadEventId != null) {
room.replyInThread( room.replyInThread(
rootThreadEventId = state.rootThreadEventId, rootThreadEventId = state.rootThreadEventId,
@ -335,51 +335,51 @@ class MessageComposerViewModel @AssistedInject constructor(
text, text,
formattedText) formattedText)
} }
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk()) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
popDraft() popDraft()
} }
is ParsedCommand.SendShrug -> { is ParsedCommand.SendShrug -> {
sendPrefixedMessage("¯\\_(ツ)_/¯", slashCommandResult.message, state.rootThreadEventId) sendPrefixedMessage("¯\\_(ツ)_/¯", parsedCommand.message, state.rootThreadEventId)
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk()) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
popDraft() popDraft()
} }
is ParsedCommand.SendLenny -> { is ParsedCommand.SendLenny -> {
sendPrefixedMessage("( ͡° ͜ʖ ͡°)", slashCommandResult.message, state.rootThreadEventId) sendPrefixedMessage("( ͡° ͜ʖ ͡°)", parsedCommand.message, state.rootThreadEventId)
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk()) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
popDraft() popDraft()
} }
is ParsedCommand.SendChatEffect -> { is ParsedCommand.SendChatEffect -> {
sendChatEffect(slashCommandResult) sendChatEffect(parsedCommand)
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk()) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
popDraft() popDraft()
} }
is ParsedCommand.ChangeTopic -> { is ParsedCommand.ChangeTopic -> {
handleChangeTopicSlashCommand(slashCommandResult) handleChangeTopicSlashCommand(parsedCommand)
} }
is ParsedCommand.ChangeDisplayName -> { is ParsedCommand.ChangeDisplayName -> {
handleChangeDisplayNameSlashCommand(slashCommandResult) handleChangeDisplayNameSlashCommand(parsedCommand)
} }
is ParsedCommand.ChangeDisplayNameForRoom -> { is ParsedCommand.ChangeDisplayNameForRoom -> {
handleChangeDisplayNameForRoomSlashCommand(slashCommandResult) handleChangeDisplayNameForRoomSlashCommand(parsedCommand)
} }
is ParsedCommand.ChangeRoomAvatar -> { is ParsedCommand.ChangeRoomAvatar -> {
handleChangeRoomAvatarSlashCommand(slashCommandResult) handleChangeRoomAvatarSlashCommand(parsedCommand)
} }
is ParsedCommand.ChangeAvatarForRoom -> { is ParsedCommand.ChangeAvatarForRoom -> {
handleChangeAvatarForRoomSlashCommand(slashCommandResult) handleChangeAvatarForRoomSlashCommand(parsedCommand)
} }
is ParsedCommand.ShowUser -> { is ParsedCommand.ShowUser -> {
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk()) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
handleWhoisSlashCommand(slashCommandResult) handleWhoisSlashCommand(parsedCommand)
popDraft() popDraft()
} }
is ParsedCommand.DiscardSession -> { is ParsedCommand.DiscardSession -> {
if (room.isEncrypted()) { if (room.isEncrypted()) {
session.cryptoService().discardOutboundSession(room.roomId) session.cryptoService().discardOutboundSession(room.roomId)
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk()) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
popDraft() popDraft()
} else { } else {
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk()) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
_viewEvents.post( _viewEvents.post(
MessageComposerViewEvents MessageComposerViewEvents
.ShowMessage(stringProvider.getString(R.string.command_description_discard_session_not_handled)) .ShowMessage(stringProvider.getString(R.string.command_description_discard_session_not_handled))
@ -391,8 +391,8 @@ class MessageComposerViewModel @AssistedInject constructor(
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
val params = CreateSpaceParams().apply { val params = CreateSpaceParams().apply {
name = slashCommandResult.name name = parsedCommand.name
invitedUserIds.addAll(slashCommandResult.invitees) invitedUserIds.addAll(parsedCommand.invitees)
} }
val spaceId = session.spaceService().createSpace(params) val spaceId = session.spaceService().createSpace(params)
session.spaceService().getSpace(spaceId) session.spaceService().getSpace(spaceId)
@ -403,7 +403,7 @@ class MessageComposerViewModel @AssistedInject constructor(
true true
) )
popDraft() popDraft()
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk()) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
} catch (failure: Throwable) { } catch (failure: Throwable) {
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultError(failure)) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultError(failure))
} }
@ -414,7 +414,7 @@ class MessageComposerViewModel @AssistedInject constructor(
_viewEvents.post(MessageComposerViewEvents.SlashCommandLoading) _viewEvents.post(MessageComposerViewEvents.SlashCommandLoading)
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
session.spaceService().getSpace(slashCommandResult.spaceId) session.spaceService().getSpace(parsedCommand.spaceId)
?.addChildren( ?.addChildren(
room.roomId, room.roomId,
null, null,
@ -422,7 +422,7 @@ class MessageComposerViewModel @AssistedInject constructor(
false false
) )
popDraft() popDraft()
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk()) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
} catch (failure: Throwable) { } catch (failure: Throwable) {
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultError(failure)) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultError(failure))
} }
@ -433,9 +433,9 @@ class MessageComposerViewModel @AssistedInject constructor(
_viewEvents.post(MessageComposerViewEvents.SlashCommandLoading) _viewEvents.post(MessageComposerViewEvents.SlashCommandLoading)
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
session.spaceService().joinSpace(slashCommandResult.spaceIdOrAlias) session.spaceService().joinSpace(parsedCommand.spaceIdOrAlias)
popDraft() popDraft()
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk()) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
} catch (failure: Throwable) { } catch (failure: Throwable) {
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultError(failure)) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultError(failure))
} }
@ -445,9 +445,9 @@ class MessageComposerViewModel @AssistedInject constructor(
is ParsedCommand.LeaveRoom -> { is ParsedCommand.LeaveRoom -> {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
session.leaveRoom(slashCommandResult.roomId) session.leaveRoom(parsedCommand.roomId)
popDraft() popDraft()
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk()) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
} catch (failure: Throwable) { } catch (failure: Throwable) {
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultError(failure)) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultError(failure))
} }
@ -457,11 +457,11 @@ class MessageComposerViewModel @AssistedInject constructor(
is ParsedCommand.UpgradeRoom -> { is ParsedCommand.UpgradeRoom -> {
_viewEvents.post( _viewEvents.post(
MessageComposerViewEvents.ShowRoomUpgradeDialog( MessageComposerViewEvents.ShowRoomUpgradeDialog(
slashCommandResult.newVersion, parsedCommand.newVersion,
room.roomSummary()?.isPublic ?: false room.roomSummary()?.isPublic ?: false
) )
) )
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk()) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
popDraft() popDraft()
} }
} }
@ -644,19 +644,19 @@ class MessageComposerViewModel @AssistedInject constructor(
} }
private fun handleChangeTopicSlashCommand(changeTopic: ParsedCommand.ChangeTopic) { private fun handleChangeTopicSlashCommand(changeTopic: ParsedCommand.ChangeTopic) {
launchSlashCommandFlowSuspendable { launchSlashCommandFlowSuspendable(changeTopic) {
room.updateTopic(changeTopic.topic) room.updateTopic(changeTopic.topic)
} }
} }
private fun handleInviteSlashCommand(invite: ParsedCommand.Invite) { private fun handleInviteSlashCommand(invite: ParsedCommand.Invite) {
launchSlashCommandFlowSuspendable { launchSlashCommandFlowSuspendable(invite) {
room.invite(invite.userId, invite.reason) room.invite(invite.userId, invite.reason)
} }
} }
private fun handleInvite3pidSlashCommand(invite: ParsedCommand.Invite3Pid) { private fun handleInvite3pidSlashCommand(invite: ParsedCommand.Invite3Pid) {
launchSlashCommandFlowSuspendable { launchSlashCommandFlowSuspendable(invite) {
room.invite3pid(invite.threePid) room.invite3pid(invite.threePid)
} }
} }
@ -669,19 +669,19 @@ class MessageComposerViewModel @AssistedInject constructor(
?.toContent() ?.toContent()
?: return ?: return
launchSlashCommandFlowSuspendable { launchSlashCommandFlowSuspendable(setUserPowerLevel) {
room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, stateKey = "", newPowerLevelsContent) room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, stateKey = "", newPowerLevelsContent)
} }
} }
private fun handleChangeDisplayNameSlashCommand(changeDisplayName: ParsedCommand.ChangeDisplayName) { private fun handleChangeDisplayNameSlashCommand(changeDisplayName: ParsedCommand.ChangeDisplayName) {
launchSlashCommandFlowSuspendable { launchSlashCommandFlowSuspendable(changeDisplayName) {
session.setDisplayName(session.myUserId, changeDisplayName.displayName) session.setDisplayName(session.myUserId, changeDisplayName.displayName)
} }
} }
private fun handlePartSlashCommand(command: ParsedCommand.PartRoom) { private fun handlePartSlashCommand(command: ParsedCommand.PartRoom) {
launchSlashCommandFlowSuspendable { launchSlashCommandFlowSuspendable(command) {
if (command.roomAlias == null) { if (command.roomAlias == null) {
// Leave the current room // Leave the current room
room room
@ -697,25 +697,25 @@ class MessageComposerViewModel @AssistedInject constructor(
} }
private fun handleRemoveSlashCommand(removeUser: ParsedCommand.RemoveUser) { private fun handleRemoveSlashCommand(removeUser: ParsedCommand.RemoveUser) {
launchSlashCommandFlowSuspendable { launchSlashCommandFlowSuspendable(removeUser) {
room.remove(removeUser.userId, removeUser.reason) room.remove(removeUser.userId, removeUser.reason)
} }
} }
private fun handleBanSlashCommand(ban: ParsedCommand.BanUser) { private fun handleBanSlashCommand(ban: ParsedCommand.BanUser) {
launchSlashCommandFlowSuspendable { launchSlashCommandFlowSuspendable(ban) {
room.ban(ban.userId, ban.reason) room.ban(ban.userId, ban.reason)
} }
} }
private fun handleUnbanSlashCommand(unban: ParsedCommand.UnbanUser) { private fun handleUnbanSlashCommand(unban: ParsedCommand.UnbanUser) {
launchSlashCommandFlowSuspendable { launchSlashCommandFlowSuspendable(unban) {
room.unban(unban.userId, unban.reason) room.unban(unban.userId, unban.reason)
} }
} }
private fun handleChangeRoomNameSlashCommand(changeRoomName: ParsedCommand.ChangeRoomName) { private fun handleChangeRoomNameSlashCommand(changeRoomName: ParsedCommand.ChangeRoomName) {
launchSlashCommandFlowSuspendable { launchSlashCommandFlowSuspendable(changeRoomName) {
room.updateName(changeRoomName.name) room.updateName(changeRoomName.name)
} }
} }
@ -727,7 +727,7 @@ class MessageComposerViewModel @AssistedInject constructor(
} }
private fun handleChangeDisplayNameForRoomSlashCommand(changeDisplayName: ParsedCommand.ChangeDisplayNameForRoom) { private fun handleChangeDisplayNameForRoomSlashCommand(changeDisplayName: ParsedCommand.ChangeDisplayNameForRoom) {
launchSlashCommandFlowSuspendable { launchSlashCommandFlowSuspendable(changeDisplayName) {
getMyRoomMemberContent() getMyRoomMemberContent()
?.copy(displayName = changeDisplayName.displayName) ?.copy(displayName = changeDisplayName.displayName)
?.toContent() ?.toContent()
@ -738,13 +738,13 @@ class MessageComposerViewModel @AssistedInject constructor(
} }
private fun handleChangeRoomAvatarSlashCommand(changeAvatar: ParsedCommand.ChangeRoomAvatar) { private fun handleChangeRoomAvatarSlashCommand(changeAvatar: ParsedCommand.ChangeRoomAvatar) {
launchSlashCommandFlowSuspendable { launchSlashCommandFlowSuspendable(changeAvatar) {
room.sendStateEvent(EventType.STATE_ROOM_AVATAR, stateKey = "", RoomAvatarContent(changeAvatar.url).toContent()) room.sendStateEvent(EventType.STATE_ROOM_AVATAR, stateKey = "", RoomAvatarContent(changeAvatar.url).toContent())
} }
} }
private fun handleChangeAvatarForRoomSlashCommand(changeAvatar: ParsedCommand.ChangeAvatarForRoom) { private fun handleChangeAvatarForRoomSlashCommand(changeAvatar: ParsedCommand.ChangeAvatarForRoom) {
launchSlashCommandFlowSuspendable { launchSlashCommandFlowSuspendable(changeAvatar) {
getMyRoomMemberContent() getMyRoomMemberContent()
?.copy(avatarUrl = changeAvatar.url) ?.copy(avatarUrl = changeAvatar.url)
?.toContent() ?.toContent()
@ -755,13 +755,24 @@ class MessageComposerViewModel @AssistedInject constructor(
} }
private fun handleIgnoreSlashCommand(ignore: ParsedCommand.IgnoreUser) { private fun handleIgnoreSlashCommand(ignore: ParsedCommand.IgnoreUser) {
launchSlashCommandFlowSuspendable { launchSlashCommandFlowSuspendable(ignore) {
session.ignoreUserIds(listOf(ignore.userId)) session.ignoreUserIds(listOf(ignore.userId))
} }
} }
private fun handleUnignoreSlashCommand(unignore: ParsedCommand.UnignoreUser) { private fun handleUnignoreSlashCommand(unignore: ParsedCommand.UnignoreUser) {
launchSlashCommandFlowSuspendable { _viewEvents.post(MessageComposerViewEvents.SlashCommandConfirmationRequest(unignore))
}
private fun handleSlashCommandConfirmed(action: MessageComposerAction.SlashCommandConfirmed) {
when (action.parsedCommand) {
is ParsedCommand.UnignoreUser -> handleUnignoreSlashCommandConfirmed(action.parsedCommand)
else -> TODO("Not handled yet")
}
}
private fun handleUnignoreSlashCommandConfirmed(unignore: ParsedCommand.UnignoreUser) {
launchSlashCommandFlowSuspendable(unignore) {
session.unIgnoreUserIds(listOf(unignore.userId)) session.unIgnoreUserIds(listOf(unignore.userId))
} }
} }
@ -900,13 +911,13 @@ class MessageComposerViewModel @AssistedInject constructor(
} }
} }
private fun launchSlashCommandFlowSuspendable(block: suspend () -> Unit) { private fun launchSlashCommandFlowSuspendable(parsedCommand: ParsedCommand, block: suspend () -> Unit) {
_viewEvents.post(MessageComposerViewEvents.SlashCommandLoading) _viewEvents.post(MessageComposerViewEvents.SlashCommandLoading)
viewModelScope.launch { viewModelScope.launch {
val event = try { val event = try {
block() block()
popDraft() popDraft()
MessageComposerViewEvents.SlashCommandResultOk() MessageComposerViewEvents.SlashCommandResultOk(parsedCommand)
} catch (failure: Throwable) { } catch (failure: Throwable) {
MessageComposerViewEvents.SlashCommandResultError(failure) MessageComposerViewEvents.SlashCommandResultError(failure)
} }

View File

@ -47,6 +47,8 @@ import im.vector.app.databinding.DialogBaseEditTextBinding
import im.vector.app.databinding.DialogShareQrCodeBinding import im.vector.app.databinding.DialogShareQrCodeBinding
import im.vector.app.databinding.FragmentMatrixProfileBinding import im.vector.app.databinding.FragmentMatrixProfileBinding
import im.vector.app.databinding.ViewStubRoomMemberProfileHeaderBinding import im.vector.app.databinding.ViewStubRoomMemberProfileHeaderBinding
import im.vector.app.features.MainActivity
import im.vector.app.features.MainActivityArgs
import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.analytics.plan.MobileScreen
import im.vector.app.features.crypto.verification.VerificationBottomSheet import im.vector.app.features.crypto.verification.VerificationBottomSheet
import im.vector.app.features.displayname.getBestName import im.vector.app.features.displayname.getBestName
@ -131,13 +133,20 @@ class RoomMemberProfileFragment @Inject constructor(
is RoomMemberProfileViewEvents.OnKickActionSuccess -> Unit is RoomMemberProfileViewEvents.OnKickActionSuccess -> Unit
is RoomMemberProfileViewEvents.OnSetPowerLevelSuccess -> Unit is RoomMemberProfileViewEvents.OnSetPowerLevelSuccess -> Unit
is RoomMemberProfileViewEvents.OnBanActionSuccess -> Unit is RoomMemberProfileViewEvents.OnBanActionSuccess -> Unit
is RoomMemberProfileViewEvents.OnIgnoreActionSuccess -> Unit is RoomMemberProfileViewEvents.OnIgnoreActionSuccess -> handleOnIgnoreActionSuccess(it)
is RoomMemberProfileViewEvents.OnInviteActionSuccess -> Unit is RoomMemberProfileViewEvents.OnInviteActionSuccess -> Unit
} }
} }
setupLongClicks() setupLongClicks()
} }
private fun handleOnIgnoreActionSuccess(action: RoomMemberProfileViewEvents.OnIgnoreActionSuccess) {
if (action.shouldPerformInitialSync) {
// A user has been un-ignored, perform a initial sync
MainActivity.restartApp(requireActivity(), MainActivityArgs(clearCache = true))
}
}
private fun setupLongClicks() { private fun setupLongClicks() {
headerViews.memberProfileNameView.copyOnLongClick() headerViews.memberProfileNameView.copyOnLongClick()
headerViews.memberProfileIdView.copyOnLongClick() headerViews.memberProfileIdView.copyOnLongClick()

View File

@ -25,7 +25,7 @@ sealed class RoomMemberProfileViewEvents : VectorViewEvents {
data class Loading(val message: CharSequence? = null) : RoomMemberProfileViewEvents() data class Loading(val message: CharSequence? = null) : RoomMemberProfileViewEvents()
data class Failure(val throwable: Throwable) : RoomMemberProfileViewEvents() data class Failure(val throwable: Throwable) : RoomMemberProfileViewEvents()
object OnIgnoreActionSuccess : RoomMemberProfileViewEvents() data class OnIgnoreActionSuccess(val shouldPerformInitialSync: Boolean) : RoomMemberProfileViewEvents()
object OnSetPowerLevelSuccess : RoomMemberProfileViewEvents() object OnSetPowerLevelSuccess : RoomMemberProfileViewEvents()
object OnInviteActionSuccess : RoomMemberProfileViewEvents() object OnInviteActionSuccess : RoomMemberProfileViewEvents()
object OnKickActionSuccess : RoomMemberProfileViewEvents() object OnKickActionSuccess : RoomMemberProfileViewEvents()

View File

@ -390,7 +390,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(
} else { } else {
session.ignoreUserIds(listOf(state.userId)) session.ignoreUserIds(listOf(state.userId))
} }
RoomMemberProfileViewEvents.OnIgnoreActionSuccess RoomMemberProfileViewEvents.OnIgnoreActionSuccess(isIgnored)
} catch (failure: Throwable) { } catch (failure: Throwable) {
RoomMemberProfileViewEvents.Failure(failure) RoomMemberProfileViewEvents.Failure(failure)
} }

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2022 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.ignored
import im.vector.app.core.platform.VectorViewModelAction
sealed class IgnoredUsersAction : VectorViewModelAction {
data class UnIgnore(val userId: String) : IgnoredUsersAction()
}

View File

@ -25,4 +25,5 @@ import im.vector.app.core.platform.VectorViewEvents
sealed class IgnoredUsersViewEvents : VectorViewEvents { sealed class IgnoredUsersViewEvents : VectorViewEvents {
data class Loading(val message: CharSequence? = null) : IgnoredUsersViewEvents() data class Loading(val message: CharSequence? = null) : IgnoredUsersViewEvents()
data class Failure(val throwable: Throwable) : IgnoredUsersViewEvents() data class Failure(val throwable: Throwable) : IgnoredUsersViewEvents()
object Success : IgnoredUsersViewEvents()
} }

View File

@ -16,37 +16,21 @@
package im.vector.app.features.settings.ignored package im.vector.app.features.settings.ignored
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.platform.VectorViewModelAction
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.user.model.User
import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.flow.flow
data class IgnoredUsersViewState( class IgnoredUsersViewModel @AssistedInject constructor(
val ignoredUsers: List<User> = emptyList(), @Assisted initialState: IgnoredUsersViewState,
val unIgnoreRequest: Async<Unit> = Uninitialized private val session: Session
) : MavericksState ) : VectorViewModel<IgnoredUsersViewState, IgnoredUsersAction, IgnoredUsersViewEvents>(initialState) {
sealed class IgnoredUsersAction : VectorViewModelAction {
data class UnIgnore(val userId: String) : IgnoredUsersAction()
}
class IgnoredUsersViewModel @AssistedInject constructor(@Assisted initialState: IgnoredUsersViewState,
private val session: Session) :
VectorViewModel<IgnoredUsersViewState, IgnoredUsersAction, IgnoredUsersViewEvents>(initialState) {
@AssistedFactory @AssistedFactory
interface Factory : MavericksAssistedViewModelFactory<IgnoredUsersViewModel, IgnoredUsersViewState> { interface Factory : MavericksAssistedViewModelFactory<IgnoredUsersViewModel, IgnoredUsersViewState> {
@ -76,20 +60,16 @@ class IgnoredUsersViewModel @AssistedInject constructor(@Assisted initialState:
} }
private fun handleUnIgnore(action: IgnoredUsersAction.UnIgnore) { private fun handleUnIgnore(action: IgnoredUsersAction.UnIgnore) {
setState { setState { copy(isLoading = true) }
copy(
unIgnoreRequest = Loading()
)
}
viewModelScope.launch { viewModelScope.launch {
val result = runCatching { session.unIgnoreUserIds(listOf(action.userId)) } val viewEvent = try {
setState { session.unIgnoreUserIds(listOf(action.userId))
copy( IgnoredUsersViewEvents.Success
unIgnoreRequest = result.fold(::Success, ::Fail) } catch (throwable: Throwable) {
) IgnoredUsersViewEvents.Failure(throwable)
} }
result.onFailure { _viewEvents.post(IgnoredUsersViewEvents.Failure(it)) } setState { copy(isLoading = false) }
_viewEvents.post(viewEvent)
} }
} }
} }

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2022 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.ignored
import com.airbnb.mvrx.MavericksState
import org.matrix.android.sdk.api.session.user.model.User
data class IgnoredUsersViewState(
val ignoredUsers: List<User> = emptyList(),
val isLoading: Boolean = false
) : MavericksState

View File

@ -22,8 +22,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -32,6 +30,8 @@ import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentGenericRecyclerBinding import im.vector.app.databinding.FragmentGenericRecyclerBinding
import im.vector.app.features.MainActivity
import im.vector.app.features.MainActivityArgs
import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.analytics.plan.MobileScreen
import javax.inject.Inject import javax.inject.Inject
@ -62,10 +62,16 @@ class VectorSettingsIgnoredUsersFragment @Inject constructor(
when (it) { when (it) {
is IgnoredUsersViewEvents.Loading -> showLoading(it.message) is IgnoredUsersViewEvents.Loading -> showLoading(it.message)
is IgnoredUsersViewEvents.Failure -> showFailure(it.throwable) is IgnoredUsersViewEvents.Failure -> showFailure(it.throwable)
IgnoredUsersViewEvents.Success -> handleSuccess()
} }
} }
} }
private fun handleSuccess() {
// A user has been un-ignored, perform a initial sync
MainActivity.restartApp(requireActivity(), MainActivityArgs(clearCache = true))
}
override fun onDestroyView() { override fun onDestroyView() {
ignoredUsersController.callback = null ignoredUsersController.callback = null
views.genericRecyclerView.cleanup() views.genericRecyclerView.cleanup()
@ -80,11 +86,12 @@ class VectorSettingsIgnoredUsersFragment @Inject constructor(
override fun onUserIdClicked(userId: String) { override fun onUserIdClicked(userId: String) {
MaterialAlertDialogBuilder(requireActivity()) MaterialAlertDialogBuilder(requireActivity())
.setTitle(R.string.room_participants_action_unignore_title)
.setMessage(getString(R.string.settings_unignore_user, userId)) .setMessage(getString(R.string.settings_unignore_user, userId))
.setPositiveButton(R.string.yes) { _, _ -> .setPositiveButton(R.string.unignore) { _, _ ->
viewModel.handle(IgnoredUsersAction.UnIgnore(userId)) viewModel.handle(IgnoredUsersAction.UnIgnore(userId))
} }
.setNegativeButton(R.string.no, null) .setNegativeButton(R.string.action_cancel, null)
.show() .show()
} }
@ -94,14 +101,6 @@ class VectorSettingsIgnoredUsersFragment @Inject constructor(
override fun invalidate() = withState(viewModel) { state -> override fun invalidate() = withState(viewModel) { state ->
ignoredUsersController.update(state) ignoredUsersController.update(state)
views.waitingView.root.isVisible = state.isLoading
handleUnIgnoreRequestStatus(state.unIgnoreRequest)
}
private fun handleUnIgnoreRequestStatus(unIgnoreRequest: Async<Unit>) {
views.waitingView.root.isVisible = when (unIgnoreRequest) {
is Loading -> true
else -> false
}
} }
} }

View File

@ -634,7 +634,7 @@
<string name="room_participants_action_ignore">Ignore</string> <string name="room_participants_action_ignore">Ignore</string>
<string name="room_participants_action_unignore_title">Unignore user</string> <string name="room_participants_action_unignore_title">Unignore user</string>
<string name="room_participants_action_unignore_prompt_msg">Unignoring this user will show all messages from them again.</string> <string name="room_participants_action_unignore_prompt_msg">Unignoring this user will show all messages from them again.\n\nNote that this action will restart the app and it may take some time.</string>
<string name="room_participants_action_unignore">Unignore</string> <string name="room_participants_action_unignore">Unignore</string>
<string name="room_participants_action_cancel_invite_title">Cancel invite</string> <string name="room_participants_action_cancel_invite_title">Cancel invite</string>