Remove coordinator, fix minor issues

This commit is contained in:
Jorge Martín 2022-10-04 12:30:56 +02:00
parent baf527ec9d
commit 2c9526543b
7 changed files with 41 additions and 61 deletions

View File

@ -129,7 +129,6 @@ import im.vector.app.features.crypto.verification.VerificationBottomSheet
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.arguments.TimelineArgs import im.vector.app.features.home.room.detail.arguments.TimelineArgs
import im.vector.app.features.home.room.detail.composer.CanSendStatus import im.vector.app.features.home.room.detail.composer.CanSendStatus
import im.vector.app.features.home.room.detail.composer.MessageComposer
import im.vector.app.features.home.room.detail.composer.MessageComposerAction import im.vector.app.features.home.room.detail.composer.MessageComposerAction
import im.vector.app.features.home.room.detail.composer.MessageComposerFragment import im.vector.app.features.home.room.detail.composer.MessageComposerFragment
import im.vector.app.features.home.room.detail.composer.MessageComposerViewModel import im.vector.app.features.home.room.detail.composer.MessageComposerViewModel
@ -289,8 +288,6 @@ class TimelineFragment :
private val lazyLoadedViews = RoomDetailLazyLoadedViews() private val lazyLoadedViews = RoomDetailLazyLoadedViews()
private lateinit var composer: MessageComposer
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
analyticsScreenName = MobileScreen.ScreenName.Room analyticsScreenName = MobileScreen.ScreenName.Room
@ -301,15 +298,13 @@ class TimelineFragment :
} }
} }
val composer = childFragmentManager.findFragmentById(R.id.composerContainer) as? MessageComposerFragment ?: run { childFragmentManager.findFragmentById(R.id.composerContainer) as? MessageComposerFragment ?: run {
val fragment = MessageComposerFragment()
fragment.arguments = timelineArgs.toMvRxBundle()
childFragmentManager.commitTransaction { childFragmentManager.commitTransaction {
val fragment = MessageComposerFragment()
fragment.arguments = timelineArgs.toMvRxBundle()
replace(R.id.composerContainer, fragment) replace(R.id.composerContainer, fragment)
} }
fragment
} }
this.composer = composer
childFragmentManager.findFragmentById(R.id.voiceMessageRecorderContainer) as? VoiceRecorderFragment ?: run { childFragmentManager.findFragmentById(R.id.voiceMessageRecorderContainer) as? VoiceRecorderFragment ?: run {
childFragmentManager.commitTransaction { childFragmentManager.commitTransaction {
@ -970,7 +965,7 @@ class TimelineFragment :
is RoomDetailPendingAction.JumpToReadReceipt -> is RoomDetailPendingAction.JumpToReadReceipt ->
timelineViewModel.handle(RoomDetailAction.JumpToReadReceipt(roomDetailPendingAction.userId)) timelineViewModel.handle(RoomDetailAction.JumpToReadReceipt(roomDetailPendingAction.userId))
is RoomDetailPendingAction.MentionUser -> is RoomDetailPendingAction.MentionUser ->
insertUserDisplayNameInTextEditor(roomDetailPendingAction.userId) messageComposerViewModel.handle(MessageComposerAction.InsertUserDisplayName(roomDetailPendingAction.userId))
is RoomDetailPendingAction.OpenRoom -> is RoomDetailPendingAction.OpenRoom ->
handleOpenRoom(RoomDetailViewEvents.OpenRoom(roomDetailPendingAction.roomId, roomDetailPendingAction.closeCurrentRoom)) handleOpenRoom(RoomDetailViewEvents.OpenRoom(roomDetailPendingAction.roomId, roomDetailPendingAction.closeCurrentRoom))
} }
@ -1051,7 +1046,7 @@ class TimelineFragment :
override fun performQuickReplyOnHolder(model: EpoxyModel<*>) { override fun performQuickReplyOnHolder(model: EpoxyModel<*>) {
(model as? AbsMessageItem)?.attributes?.informationData?.let { (model as? AbsMessageItem)?.attributes?.informationData?.let {
val eventId = it.eventId val eventId = it.eventId
messageComposerViewModel.handle(MessageComposerAction.EnterReplyMode(eventId, composer.getCurrentText().toString())) messageComposerViewModel.handle(MessageComposerAction.EnterReplyMode(eventId))
} }
} }
@ -1573,7 +1568,7 @@ class TimelineFragment :
} }
override fun onMemberNameClicked(informationData: MessageInformationData) { override fun onMemberNameClicked(informationData: MessageInformationData) {
insertUserDisplayNameInTextEditor(informationData.senderId) messageComposerViewModel.handle(MessageComposerAction.InsertUserDisplayName(informationData.senderId))
} }
override fun onClickOnReactionPill(informationData: MessageInformationData, reaction: String, on: Boolean) { override fun onClickOnReactionPill(informationData: MessageInformationData, reaction: String, on: Boolean) {
@ -1776,11 +1771,11 @@ class TimelineFragment :
} }
} }
is EventSharedAction.Quote -> { is EventSharedAction.Quote -> {
messageComposerViewModel.handle(MessageComposerAction.EnterQuoteMode(action.eventId, composer.getCurrentText().toString())) messageComposerViewModel.handle(MessageComposerAction.EnterQuoteMode(action.eventId))
} }
is EventSharedAction.Reply -> { is EventSharedAction.Reply -> {
if (withState(messageComposerViewModel) { it.isVoiceMessageIdle }) { if (withState(messageComposerViewModel) { it.isVoiceMessageIdle }) {
messageComposerViewModel.handle(MessageComposerAction.EnterReplyMode(action.eventId, composer.getCurrentText().toString())) messageComposerViewModel.handle(MessageComposerAction.EnterReplyMode(action.eventId))
} else { } else {
requireActivity().toast(R.string.error_voice_message_cannot_reply_or_edit) requireActivity().toast(R.string.error_voice_message_cannot_reply_or_edit)
} }
@ -1881,16 +1876,6 @@ class TimelineFragment :
.show() .show()
} }
/**
* Insert a user displayName in the message editor.
*
* @param userId the userId.
*/
@SuppressLint("SetTextI18n")
private fun insertUserDisplayNameInTextEditor(userId: String) {
composer.insertUserDisplayNameInTextEditor(userId)
}
private fun showSnackWithMessage(message: String) { private fun showSnackWithMessage(message: String) {
view?.showOptimizedSnackbar(message) view?.showOptimizedSnackbar(message)
} }

View File

@ -25,13 +25,14 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
sealed class MessageComposerAction : VectorViewModelAction { sealed class MessageComposerAction : VectorViewModelAction {
data class SendMessage(val text: CharSequence, val autoMarkdown: Boolean) : MessageComposerAction() data class SendMessage(val text: CharSequence, val autoMarkdown: Boolean) : MessageComposerAction()
data class EnterEditMode(val eventId: String) : MessageComposerAction() data class EnterEditMode(val eventId: String) : MessageComposerAction()
data class EnterQuoteMode(val eventId: String, val text: String) : MessageComposerAction() data class EnterQuoteMode(val eventId: String) : MessageComposerAction()
data class EnterReplyMode(val eventId: String, val text: String) : MessageComposerAction() data class EnterReplyMode(val eventId: String) : MessageComposerAction()
data class EnterRegularMode(val text: String, val fromSharing: Boolean) : MessageComposerAction() data class EnterRegularMode(val fromSharing: Boolean) : MessageComposerAction()
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() data class SlashCommandConfirmed(val parsedCommand: ParsedCommand) : MessageComposerAction()
data class InsertUserDisplayName(val userId: String) : MessageComposerAction()
// Voice Message // Voice Message
data class InitializeVoiceRecorder(val attachmentData: ContentAttachmentData) : MessageComposerAction() data class InitializeVoiceRecorder(val attachmentData: ContentAttachmentData) : MessageComposerAction()

View File

@ -22,7 +22,6 @@ import android.content.res.Configuration
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.text.Editable
import android.text.Spannable import android.text.Spannable
import android.text.format.DateUtils import android.text.format.DateUtils
import android.view.KeyEvent import android.view.KeyEvent
@ -112,13 +111,8 @@ import reactivecircus.flowbinding.android.widget.textChanges
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
interface MessageComposer {
fun getCurrentText(): Editable?
fun insertUserDisplayNameInTextEditor(userId: String)
}
@AndroidEntryPoint @AndroidEntryPoint
class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), MessageComposer, AttachmentsHelper.Callback, AttachmentTypeSelectorView.Callback { class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), AttachmentsHelper.Callback, AttachmentTypeSelectorView.Callback {
companion object { companion object {
private const val ircPattern = " (IRC)" private const val ircPattern = " (IRC)"
@ -196,6 +190,7 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), M
} }
showErrorInSnackbar(it.throwable) showErrorInSnackbar(it.throwable)
} }
is MessageComposerViewEvents.InsertUserDisplayName -> insertUserDisplayNameInTextEditor(it.userId)
} }
} }
@ -204,10 +199,10 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), M
return@onEach return@onEach
} }
when (mode) { when (mode) {
is SendMode.Regular -> renderRegularMode(mode.text) is SendMode.Regular -> renderRegularMode(mode.text.toString())
is SendMode.Edit -> renderSpecialMode(mode.timelineEvent, R.drawable.ic_edit, R.string.edit, mode.text) is SendMode.Edit -> renderSpecialMode(mode.timelineEvent, R.drawable.ic_edit, R.string.edit, mode.text.toString())
is SendMode.Quote -> renderSpecialMode(mode.timelineEvent, R.drawable.ic_quote, R.string.action_quote, mode.text) is SendMode.Quote -> renderSpecialMode(mode.timelineEvent, R.drawable.ic_quote, R.string.action_quote, mode.text.toString())
is SendMode.Reply -> renderSpecialMode(mode.timelineEvent, R.drawable.ic_reply, R.string.reply, mode.text) is SendMode.Reply -> renderSpecialMode(mode.timelineEvent, R.drawable.ic_reply, R.string.reply, mode.text.toString())
is SendMode.Voice -> renderVoiceMessageMode(mode.text) is SendMode.Voice -> renderVoiceMessageMode(mode.text)
} }
} }
@ -304,7 +299,7 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), M
} }
override fun onCloseRelatedMessage() { override fun onCloseRelatedMessage() {
messageComposerViewModel.handle(MessageComposerAction.EnterRegularMode(views.composerLayout.text.toString(), false)) messageComposerViewModel.handle(MessageComposerAction.EnterRegularMode(false))
} }
override fun onRichContentSelected(contentUri: Uri): Boolean { override fun onRichContentSelected(contentUri: Uri): Boolean {
@ -723,7 +718,8 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), M
private fun handleShareData() { private fun handleShareData() {
when (val sharedData = timelineArgs.sharedData) { when (val sharedData = timelineArgs.sharedData) {
is SharedData.Text -> { is SharedData.Text -> {
messageComposerViewModel.handle(MessageComposerAction.EnterRegularMode(sharedData.text, fromSharing = true)) messageComposerViewModel.handle(MessageComposerAction.OnTextChanged(sharedData.text))
messageComposerViewModel.handle(MessageComposerAction.EnterRegularMode(fromSharing = true))
} }
is SharedData.Attachments -> { is SharedData.Attachments -> {
// open share edition // open share edition
@ -733,17 +729,13 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), M
} }
} }
override fun getCurrentText(): Editable? { private fun insertUserDisplayNameInTextEditor(userId: String) {
return views.composerLayout.text
}
override fun insertUserDisplayNameInTextEditor(userId: String) {
val startToCompose = views.composerLayout.text.isNullOrBlank() val startToCompose = views.composerLayout.text.isNullOrBlank()
if (startToCompose && if (startToCompose &&
userId == session.myUserId) { userId == session.myUserId) {
// Empty composer, current user: start an emote // Empty composer, current user: start an emote
views.composerLayout.views.composerEditText.setText(Command.EMOTE.command + " ") views.composerLayout.views.composerEditText.setText("${Command.EMOTE.command} ")
views.composerLayout.views.composerEditText.setSelection(Command.EMOTE.command.length + 1) views.composerLayout.views.composerEditText.setSelection(Command.EMOTE.command.length + 1)
} else { } else {
val roomMember = timelineViewModel.getMember(userId) val roomMember = timelineViewModel.getMember(userId)

View File

@ -47,4 +47,6 @@ sealed class MessageComposerViewEvents : VectorViewEvents {
data class ShowRoomUpgradeDialog(val newVersion: String, val isPublic: Boolean) : MessageComposerViewEvents() data class ShowRoomUpgradeDialog(val newVersion: String, val isPublic: Boolean) : MessageComposerViewEvents()
data class VoicePlaybackOrRecordingFailure(val throwable: Throwable) : MessageComposerViewEvents() data class VoicePlaybackOrRecordingFailure(val throwable: Throwable) : MessageComposerViewEvents()
data class InsertUserDisplayName(val userId: String) : MessageComposerViewEvents()
} }

View File

@ -113,6 +113,7 @@ class MessageComposerViewModel @AssistedInject constructor(
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) is MessageComposerAction.SlashCommandConfirmed -> handleSlashCommandConfirmed(action)
is MessageComposerAction.InsertUserDisplayName -> handleInsertUserDisplayName(action)
} }
} }
@ -144,7 +145,7 @@ class MessageComposerViewModel @AssistedInject constructor(
} }
private fun handleEnterRegularMode(action: MessageComposerAction.EnterRegularMode) = setState { private fun handleEnterRegularMode(action: MessageComposerAction.EnterRegularMode) = setState {
copy(sendMode = SendMode.Regular(action.text, action.fromSharing)) copy(sendMode = SendMode.Regular(currentComposerText, action.fromSharing))
} }
private fun handleEnterEditMode(action: MessageComposerAction.EnterEditMode) { private fun handleEnterEditMode(action: MessageComposerAction.EnterEditMode) {
@ -181,13 +182,13 @@ class MessageComposerViewModel @AssistedInject constructor(
private fun handleEnterQuoteMode(action: MessageComposerAction.EnterQuoteMode) { private fun handleEnterQuoteMode(action: MessageComposerAction.EnterQuoteMode) {
room.getTimelineEvent(action.eventId)?.let { timelineEvent -> room.getTimelineEvent(action.eventId)?.let { timelineEvent ->
setState { copy(sendMode = SendMode.Quote(timelineEvent, action.text)) } setState { copy(sendMode = SendMode.Quote(timelineEvent, currentComposerText)) }
} }
} }
private fun handleEnterReplyMode(action: MessageComposerAction.EnterReplyMode) { private fun handleEnterReplyMode(action: MessageComposerAction.EnterReplyMode) {
room.getTimelineEvent(action.eventId)?.let { timelineEvent -> room.getTimelineEvent(action.eventId)?.let { timelineEvent ->
setState { copy(sendMode = SendMode.Reply(timelineEvent, action.text)) } setState { copy(sendMode = SendMode.Reply(timelineEvent, currentComposerText)) }
} }
} }
@ -875,7 +876,7 @@ class MessageComposerViewModel @AssistedInject constructor(
} }
} }
} }
handleEnterRegularMode(MessageComposerAction.EnterRegularMode(text = "", fromSharing = false)) handleEnterRegularMode(MessageComposerAction.EnterRegularMode(fromSharing = false))
} }
private fun handlePlayOrPauseVoicePlayback(action: MessageComposerAction.PlayOrPauseVoicePlayback) { private fun handlePlayOrPauseVoicePlayback(action: MessageComposerAction.PlayOrPauseVoicePlayback) {
@ -943,6 +944,10 @@ class MessageComposerViewModel @AssistedInject constructor(
} }
} }
private fun handleInsertUserDisplayName(action: MessageComposerAction.InsertUserDisplayName) {
_viewEvents.post(MessageComposerViewEvents.InsertUserDisplayName(action.userId))
}
private fun launchSlashCommandFlowSuspendable(parsedCommand: ParsedCommand, block: suspend () -> Unit) { private fun launchSlashCommandFlowSuspendable(parsedCommand: ParsedCommand, block: suspend () -> Unit) {
_viewEvents.post(MessageComposerViewEvents.SlashCommandLoading) _viewEvents.post(MessageComposerViewEvents.SlashCommandLoading)
viewModelScope.launch { viewModelScope.launch {

View File

@ -33,15 +33,15 @@ import kotlin.random.Random
*/ */
sealed interface SendMode { sealed interface SendMode {
data class Regular( data class Regular(
val text: String, val text: CharSequence,
val fromSharing: Boolean, val fromSharing: Boolean,
// This is necessary for forcing refresh on selectSubscribe // This is necessary for forcing refresh on selectSubscribe
private val random: Int = Random.nextInt() private val random: Int = Random.nextInt()
) : SendMode ) : SendMode
data class Quote(val timelineEvent: TimelineEvent, val text: String) : SendMode data class Quote(val timelineEvent: TimelineEvent, val text: CharSequence) : SendMode
data class Edit(val timelineEvent: TimelineEvent, val text: String) : SendMode data class Edit(val timelineEvent: TimelineEvent, val text: CharSequence) : SendMode
data class Reply(val timelineEvent: TimelineEvent, val text: String) : SendMode data class Reply(val timelineEvent: TimelineEvent, val text: CharSequence) : SendMode
data class Voice(val text: String) : SendMode data class Voice(val text: String) : SendMode
} }
@ -66,7 +66,8 @@ data class MessageComposerViewState(
val rootThreadEventId: String? = null, val rootThreadEventId: String? = null,
val startsThread: Boolean = false, val startsThread: Boolean = false,
val sendMode: SendMode = SendMode.Regular("", false), val sendMode: SendMode = SendMode.Regular("", false),
val voiceRecordingUiState: VoiceMessageRecorderView.RecordingUiState = VoiceMessageRecorderView.RecordingUiState.Idle val voiceRecordingUiState: VoiceMessageRecorderView.RecordingUiState = VoiceMessageRecorderView.RecordingUiState.Idle,
val text: CharSequence? = null,
) : MavericksState { ) : MavericksState {
val isVoiceRecording = when (voiceRecordingUiState) { val isVoiceRecording = when (voiceRecordingUiState) {

View File

@ -63,12 +63,6 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder>(
} }
} }
private val _memberNameClickListener = object : ClickListener {
override fun invoke(p1: View) {
attributes.avatarCallback?.onMemberNameClicked(attributes.informationData)
}
}
private val _threadClickListener = object : ClickListener { private val _threadClickListener = object : ClickListener {
override fun invoke(p1: View) { override fun invoke(p1: View) {
attributes.threadCallback?.onThreadSummaryClicked(attributes.informationData.eventId, attributes.threadDetails?.isRootThread ?: false) attributes.threadCallback?.onThreadSummaryClicked(attributes.informationData.eventId, attributes.threadDetails?.isRootThread ?: false)
@ -95,7 +89,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder>(
holder.memberNameView.isVisible = true holder.memberNameView.isVisible = true
holder.memberNameView.text = attributes.informationData.memberName holder.memberNameView.text = attributes.informationData.memberName
holder.memberNameView.setTextColor(attributes.getMemberNameColor()) holder.memberNameView.setTextColor(attributes.getMemberNameColor())
holder.memberNameView.onClick(_memberNameClickListener) holder.memberNameView.onClick(attributes.memberClickListener)
holder.memberNameView.setOnLongClickListener(attributes.itemLongClickListener) holder.memberNameView.setOnLongClickListener(attributes.itemLongClickListener)
} else { } else {
holder.memberNameView.setOnClickListener(null) holder.memberNameView.setOnClickListener(null)