- Fix remaining conflicts with develop

- Disable thread awareness when threads are enabled
This commit is contained in:
ariskotsomitopoulos 2021-12-15 14:38:08 +02:00
parent cd95fc41e4
commit 20357ce5c4
16 changed files with 140 additions and 111 deletions

View File

@ -36,7 +36,6 @@ import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
import org.matrix.android.sdk.internal.di.MoshiProvider import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.session.presence.model.PresenceContent import org.matrix.android.sdk.internal.session.presence.model.PresenceContent
import org.matrix.android.sdk.internal.session.room.send.removeInReplyFallbacks
import timber.log.Timber import timber.log.Timber
typealias Content = JsonDict typealias Content = JsonDict
@ -338,20 +337,22 @@ fun Event.isAttachmentMessage(): Boolean {
} }
} }
fun Event.isPoll(): Boolean = getClearType() == EventType.POLL_START || getClearType() == EventType.POLL_END
fun Event.isSticker(): Boolean = getClearType() == EventType.STICKER
fun Event.getRelationContent(): RelationDefaultContent? { fun Event.getRelationContent(): RelationDefaultContent? {
if(eventId?.contains("MgPN5Bqb") == true)
Timber.i(":D")
return if (isEncrypted()) { return if (isEncrypted()) {
content.toModel<EncryptedEventContent>()?.relatesTo content.toModel<EncryptedEventContent>()?.relatesTo
} else { } else {
content.toModel<MessageContent>()?.relatesTo ?: run{ content.toModel<MessageContent>()?.relatesTo ?: run {
// Special case to handle stickers, while there is only a local msgtype for stickers // Special case to handle stickers, while there is only a local msgtype for stickers
if (getClearType() == EventType.STICKER) { if (getClearType() == EventType.STICKER) {
getClearContent().toModel<MessageStickerContent>()?.relatesTo getClearContent().toModel<MessageStickerContent>()?.relatesTo
} else{ } else {
null null
}
} }
}
} }
} }

View File

@ -22,7 +22,9 @@ import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.RelationType import org.matrix.android.sdk.api.session.events.model.RelationType
import org.matrix.android.sdk.api.session.events.model.getRelationContent import org.matrix.android.sdk.api.session.events.model.getRelationContent
import org.matrix.android.sdk.api.session.events.model.isEdition import org.matrix.android.sdk.api.session.events.model.isEdition
import org.matrix.android.sdk.api.session.events.model.isPoll
import org.matrix.android.sdk.api.session.events.model.isReply import org.matrix.android.sdk.api.session.events.model.isReply
import org.matrix.android.sdk.api.session.events.model.isSticker
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary
import org.matrix.android.sdk.api.session.room.model.ReadReceipt import org.matrix.android.sdk.api.session.room.model.ReadReceipt
@ -145,6 +147,13 @@ fun TimelineEvent.isEdition(): Boolean {
return root.isEdition() return root.isEdition()
} }
fun TimelineEvent.isPoll(): Boolean =
root.isPoll()
fun TimelineEvent.isSticker(): Boolean {
return root.isSticker()
}
/** /**
* Get the latest message body, after a possible edition, stripping the reply prefix if necessary * Get the latest message body, after a possible edition, stripping the reply prefix if necessary
*/ */

View File

@ -177,9 +177,9 @@ internal class DefaultRelationService @AssistedInject constructor(
replyText = replyInThreadText, replyText = replyInThreadText,
autoMarkdown = autoMarkdown, autoMarkdown = autoMarkdown,
rootThreadEventId = rootThreadEventId) rootThreadEventId = rootThreadEventId)
// ?.also { ?.also {
// saveLocalEcho(it) saveLocalEcho(it)
// } }
?: return null ?: return null
} else { } else {
eventFactory.createThreadTextEvent( eventFactory.createThreadTextEvent(
@ -189,9 +189,9 @@ internal class DefaultRelationService @AssistedInject constructor(
msgType = msgType, msgType = msgType,
autoMarkdown = autoMarkdown, autoMarkdown = autoMarkdown,
formattedText = formattedText) formattedText = formattedText)
// .also { .also {
// saveLocalEcho(it) saveLocalEcho(it)
// } }
} }
return eventSenderProcessor.postEvent(event, cryptoSessionInfoProvider.isRoomEncrypted(roomId)) return eventSenderProcessor.postEvent(event, cryptoSessionInfoProvider.isRoomEncrypted(roomId))
} }

View File

@ -24,6 +24,7 @@ import io.realm.RealmQuery
import io.realm.RealmResults import io.realm.RealmResults
import io.realm.Sort import io.realm.Sort
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.matrix.android.sdk.BuildConfig
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.extensions.tryOrNull
@ -639,7 +640,9 @@ internal class DefaultTimeline(
}.map { }.map {
EventMapper.map(it) EventMapper.map(it)
} }
threadsAwarenessHandler.fetchRootThreadEventsIfNeeded(eventEntityList) if(!BuildConfig.THREADING_ENABLED) {
threadsAwarenessHandler.fetchRootThreadEventsIfNeeded(eventEntityList)
}
} }
private fun buildTimelineEvent(eventEntity: TimelineEventEntity): TimelineEvent { private fun buildTimelineEvent(eventEntity: TimelineEventEntity): TimelineEvent {

View File

@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.session.room.timeline
import io.realm.Realm import io.realm.Realm
import io.realm.RealmConfiguration import io.realm.RealmConfiguration
import org.matrix.android.sdk.BuildConfig
import org.matrix.android.sdk.api.session.crypto.CryptoService import org.matrix.android.sdk.api.session.crypto.CryptoService
import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.crypto.MXCryptoError
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
@ -114,11 +115,17 @@ internal class TimelineEventDecryptor @Inject constructor(
.findFirst() .findFirst()
eventEntity?.apply { eventEntity?.apply {
val decryptedPayload = threadsAwarenessHandler.handleIfNeededDuringDecryption(
it, val decryptedPayload =
roomId = event.roomId, if (!BuildConfig.THREADING_ENABLED) {
event, threadsAwarenessHandler.handleIfNeededDuringDecryption(
result) it,
roomId = event.roomId,
event,
result)
} else {
null
}
setDecryptionResult(result, decryptedPayload) setDecryptionResult(result, decryptedPayload)
} }
} }

View File

@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.sync
import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.ExistingPeriodicWorkPolicy
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.BuildConfig
import org.matrix.android.sdk.api.pushrules.PushRuleService import org.matrix.android.sdk.api.pushrules.PushRuleService
import org.matrix.android.sdk.api.pushrules.RuleScope import org.matrix.android.sdk.api.pushrules.RuleScope
import org.matrix.android.sdk.api.session.initsync.InitSyncStep import org.matrix.android.sdk.api.session.initsync.InitSyncStep
@ -101,7 +102,9 @@ internal class SyncResponseHandler @Inject constructor(
val aggregator = SyncResponsePostTreatmentAggregator() val aggregator = SyncResponsePostTreatmentAggregator()
// Prerequisite for thread events handling in RoomSyncHandler // Prerequisite for thread events handling in RoomSyncHandler
threadsAwarenessHandler.fetchRootThreadEventsIfNeeded(syncResponse) if(!BuildConfig.THREADING_ENABLED) {
threadsAwarenessHandler.fetchRootThreadEventsIfNeeded(syncResponse)
}
// Start one big transaction // Start one big transaction
monarchy.awaitTransaction { realm -> monarchy.awaitTransaction { realm ->

View File

@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.sync.handler.room
import io.realm.Realm import io.realm.Realm
import io.realm.kotlin.createObject import io.realm.kotlin.createObject
import org.matrix.android.sdk.BuildConfig
import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.crypto.MXCryptoError
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
@ -375,10 +376,12 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
decryptIfNeeded(event, roomId) decryptIfNeeded(event, roomId)
} }
threadsAwarenessHandler.handleIfNeeded( if(!BuildConfig.THREADING_ENABLED) {
realm = realm, threadsAwarenessHandler.handleIfNeeded(
roomId = roomId, realm = realm,
event = event) roomId = roomId,
event = event)
}
val ageLocalTs = event.unsignedData?.age?.let { syncLocalTimestampMillis - it } val ageLocalTs = event.unsignedData?.age?.let { syncLocalTimestampMillis - it }
val eventEntity = event.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm, insertType) val eventEntity = event.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm, insertType)

View File

@ -721,7 +721,7 @@ class TimelineFragment @Inject constructor(
} }
override fun onVoiceRecordingCancelled() { override fun onVoiceRecordingCancelled() {
messageComposerViewModel.handle(MessageComposerAction.EndRecordingVoiceMessage(isCancelled = true)) messageComposerViewModel.handle(MessageComposerAction.EndRecordingVoiceMessage(isCancelled = true, rootThreadEventId = getRootThreadEventId()))
vibrate(requireContext()) vibrate(requireContext())
updateRecordingUiState(RecordingUiState.Idle) updateRecordingUiState(RecordingUiState.Idle)
} }
@ -737,12 +737,12 @@ class TimelineFragment @Inject constructor(
} }
override fun onSendVoiceMessage() { override fun onSendVoiceMessage() {
messageComposerViewModel.handle(MessageComposerAction.EndRecordingVoiceMessage(isCancelled = false)) messageComposerViewModel.handle(MessageComposerAction.EndRecordingVoiceMessage(isCancelled = false, rootThreadEventId = getRootThreadEventId()))
updateRecordingUiState(RecordingUiState.Idle) updateRecordingUiState(RecordingUiState.Idle)
} }
override fun onDeleteVoiceMessage() { override fun onDeleteVoiceMessage() {
messageComposerViewModel.handle(MessageComposerAction.EndRecordingVoiceMessage(isCancelled = true)) messageComposerViewModel.handle(MessageComposerAction.EndRecordingVoiceMessage(isCancelled = true, rootThreadEventId = getRootThreadEventId()))
updateRecordingUiState(RecordingUiState.Idle) updateRecordingUiState(RecordingUiState.Idle)
} }
@ -1388,6 +1388,7 @@ class TimelineFragment @Inject constructor(
} }
private fun updateJumpToReadMarkerViewVisibility() { private fun updateJumpToReadMarkerViewVisibility() {
if(isThreadTimeLine()) return
viewLifecycleOwner.lifecycleScope.launchWhenResumed { viewLifecycleOwner.lifecycleScope.launchWhenResumed {
withState(roomDetailViewModel) { withState(roomDetailViewModel) {
val showJumpToUnreadBanner = when (it.unreadState) { val showJumpToUnreadBanner = when (it.unreadState) {
@ -1606,28 +1607,28 @@ class TimelineFragment @Inject constructor(
private fun renderSendMessageResult(sendMessageResult: MessageComposerViewEvents.SendMessageResult) { private fun renderSendMessageResult(sendMessageResult: MessageComposerViewEvents.SendMessageResult) {
when (sendMessageResult) { when (sendMessageResult) {
is MessageComposerViewEvents.SlashCommandLoading -> { is MessageComposerViewEvents.SlashCommandLoading -> {
showLoading(null) showLoading(null)
} }
is MessageComposerViewEvents.SlashCommandError -> { is MessageComposerViewEvents.SlashCommandError -> {
displayCommandError(getString(R.string.command_problem_with_parameters, sendMessageResult.command.command)) displayCommandError(getString(R.string.command_problem_with_parameters, sendMessageResult.command.command))
} }
is MessageComposerViewEvents.SlashCommandUnknown -> { is MessageComposerViewEvents.SlashCommandUnknown -> {
displayCommandError(getString(R.string.unrecognized_command, sendMessageResult.command)) displayCommandError(getString(R.string.unrecognized_command, sendMessageResult.command))
} }
is MessageComposerViewEvents.SlashCommandResultOk -> { is MessageComposerViewEvents.SlashCommandResultOk -> {
dismissLoadingDialog() dismissLoadingDialog()
views.composerLayout.setTextIfDifferent("") views.composerLayout.setTextIfDifferent("")
sendMessageResult.messageRes?.let { showSnackWithMessage(getString(it)) } sendMessageResult.messageRes?.let { showSnackWithMessage(getString(it)) }
} }
is MessageComposerViewEvents.SlashCommandResultError -> { is MessageComposerViewEvents.SlashCommandResultError -> {
dismissLoadingDialog() dismissLoadingDialog()
displayCommandError(errorFormatter.toHumanReadable(sendMessageResult.throwable)) displayCommandError(errorFormatter.toHumanReadable(sendMessageResult.throwable))
} }
is MessageComposerViewEvents.SlashCommandNotImplemented -> { is MessageComposerViewEvents.SlashCommandNotImplemented -> {
displayCommandError(getString(R.string.not_implemented)) displayCommandError(getString(R.string.not_implemented))
} }
is TextComposerViewEvents.SlashCommandNotSupportedInThreads -> { is MessageComposerViewEvents.SlashCommandNotSupportedInThreads -> {
displayCommandError(getString(R.string.command_not_supported_in_threads, sendMessageResult.command)) displayCommandError(getString(R.string.command_not_supported_in_threads, sendMessageResult.command))
} }
} // .exhaustive } // .exhaustive
@ -2145,14 +2146,14 @@ class TimelineFragment @Inject constructor(
} }
} }
is EventSharedAction.ReplyInThread -> { is EventSharedAction.ReplyInThread -> {
if (!views.voiceMessageRecorderView.isActive()) { if (withState(messageComposerViewModel) { it.isVoiceMessageIdle }) {
navigateToThreadTimeline(action.eventId) navigateToThreadTimeline(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)
} }
} }
is EventSharedAction.ViewInRoom -> { is EventSharedAction.ViewInRoom -> {
if (!views.voiceMessageRecorderView.isActive()) { if (withState(messageComposerViewModel) { it.isVoiceMessageIdle }) {
handleViewInRoomAction() handleViewInRoomAction()
} else { } else {
requireActivity().toast(R.string.error_voice_message_cannot_reply_or_edit) requireActivity().toast(R.string.error_voice_message_cannot_reply_or_edit)
@ -2386,7 +2387,7 @@ class TimelineFragment @Inject constructor(
AttachmentTypeSelectorView.Type.AUDIO -> attachmentsHelper.selectAudio(attachmentAudioActivityResultLauncher) AttachmentTypeSelectorView.Type.AUDIO -> attachmentsHelper.selectAudio(attachmentAudioActivityResultLauncher)
AttachmentTypeSelectorView.Type.CONTACT -> attachmentsHelper.selectContact(attachmentContactActivityResultLauncher) AttachmentTypeSelectorView.Type.CONTACT -> attachmentsHelper.selectContact(attachmentContactActivityResultLauncher)
AttachmentTypeSelectorView.Type.STICKER -> roomDetailViewModel.handle(RoomDetailAction.SelectStickerAttachment) AttachmentTypeSelectorView.Type.STICKER -> roomDetailViewModel.handle(RoomDetailAction.SelectStickerAttachment)
AttachmentTypeSelectorView.Type.POLL -> navigator.openCreatePoll(requireContext(), roomDetailArgs.roomId) AttachmentTypeSelectorView.Type.POLL -> navigator.openCreatePoll(requireContext(), timelineArgs.roomId)
}.exhaustive }.exhaustive
} }

View File

@ -35,7 +35,7 @@ sealed class MessageComposerAction : VectorViewModelAction {
data class InitializeVoiceRecorder(val attachmentData: ContentAttachmentData) : MessageComposerAction() data class InitializeVoiceRecorder(val attachmentData: ContentAttachmentData) : MessageComposerAction()
data class OnVoiceRecordingUiStateChanged(val uiState: VoiceMessageRecorderView.RecordingUiState) : MessageComposerAction() data class OnVoiceRecordingUiStateChanged(val uiState: VoiceMessageRecorderView.RecordingUiState) : MessageComposerAction()
object StartRecordingVoiceMessage : MessageComposerAction() object StartRecordingVoiceMessage : MessageComposerAction()
data class EndRecordingVoiceMessage(val isCancelled: Boolean) : MessageComposerAction() data class EndRecordingVoiceMessage(val isCancelled: Boolean,val rootThreadEventId: String?) : MessageComposerAction()
object PauseRecordingVoiceMessage : MessageComposerAction() object PauseRecordingVoiceMessage : MessageComposerAction()
data class PlayOrPauseVoicePlayback(val eventId: String, val messageAudioContent: MessageAudioContent) : MessageComposerAction() data class PlayOrPauseVoicePlayback(val eventId: String, val messageAudioContent: MessageAudioContent) : MessageComposerAction()
object PlayOrPauseRecordingPlayback : MessageComposerAction() object PlayOrPauseRecordingPlayback : MessageComposerAction()

View File

@ -93,7 +93,7 @@ class MessageComposerViewModel @AssistedInject constructor(
is MessageComposerAction.OnTextChanged -> handleOnTextChanged(action) is MessageComposerAction.OnTextChanged -> handleOnTextChanged(action)
is MessageComposerAction.OnVoiceRecordingUiStateChanged -> handleOnVoiceRecordingUiStateChanged(action) is MessageComposerAction.OnVoiceRecordingUiStateChanged -> handleOnVoiceRecordingUiStateChanged(action)
is MessageComposerAction.StartRecordingVoiceMessage -> handleStartRecordingVoiceMessage() is MessageComposerAction.StartRecordingVoiceMessage -> handleStartRecordingVoiceMessage()
is MessageComposerAction.EndRecordingVoiceMessage -> handleEndRecordingVoiceMessage(action.isCancelled) is MessageComposerAction.EndRecordingVoiceMessage -> handleEndRecordingVoiceMessage(action.isCancelled, action.rootThreadEventId)
is MessageComposerAction.PlayOrPauseVoicePlayback -> handlePlayOrPauseVoicePlayback(action) is MessageComposerAction.PlayOrPauseVoicePlayback -> handlePlayOrPauseVoicePlayback(action)
MessageComposerAction.PauseRecordingVoiceMessage -> handlePauseRecordingVoiceMessage() MessageComposerAction.PauseRecordingVoiceMessage -> handlePauseRecordingVoiceMessage()
MessageComposerAction.PlayOrPauseRecordingPlayback -> handlePlayOrPauseRecordingPlayback() MessageComposerAction.PlayOrPauseRecordingPlayback -> handlePlayOrPauseRecordingPlayback()
@ -188,7 +188,7 @@ class MessageComposerViewModel @AssistedInject constructor(
_viewEvents.post(MessageComposerViewEvents.SlashCommandUnknown(slashCommandResult.slashCommand)) _viewEvents.post(MessageComposerViewEvents.SlashCommandUnknown(slashCommandResult.slashCommand))
} }
is ParsedCommand.ErrorCommandNotSupportedInThreads -> { is ParsedCommand.ErrorCommandNotSupportedInThreads -> {
_viewEvents.post(TextComposerViewEvents.SlashCommandNotSupportedInThreads(slashCommandResult.slashCommand)) _viewEvents.post(MessageComposerViewEvents.SlashCommandNotSupportedInThreads(slashCommandResult.slashCommand))
} }
is ParsedCommand.SendPlainText -> { is ParsedCommand.SendPlainText -> {
// Send the text message to the room, without markdown // Send the text message to the room, without markdown
@ -491,7 +491,7 @@ class MessageComposerViewModel @AssistedInject constructor(
eventReplied = timelineEvent) eventReplied = timelineEvent)
} ?: room.replyToMessage(timelineEvent, action.text.toString(), action.autoMarkdown) } ?: room.replyToMessage(timelineEvent, action.text.toString(), action.autoMarkdown)
_viewEvents.post(TextComposerViewEvents.MessageSent) _viewEvents.post(MessageComposerViewEvents.MessageSent)
popDraft() popDraft()
} }
is SendMode.Voice -> { is SendMode.Voice -> {
@ -774,14 +774,18 @@ class MessageComposerViewModel @AssistedInject constructor(
} }
} }
private fun handleEndRecordingVoiceMessage(isCancelled: Boolean) { private fun handleEndRecordingVoiceMessage(isCancelled: Boolean, rootThreadEventId: String? = null) {
voiceMessageHelper.stopPlayback() voiceMessageHelper.stopPlayback()
if (isCancelled) { if (isCancelled) {
voiceMessageHelper.deleteRecording() voiceMessageHelper.deleteRecording()
} else { } else {
voiceMessageHelper.stopRecording(convertForSending = true)?.let { audioType -> voiceMessageHelper.stopRecording(convertForSending = true)?.let { audioType ->
if (audioType.duration > 1000) { if (audioType.duration > 1000) {
room.sendMedia(audioType.toContentAttachmentData(isVoiceMessage = true), false, emptySet()) room.sendMedia(
attachment = audioType.toContentAttachmentData(isVoiceMessage = true),
compressBeforeSending = false,
roomIds = emptySet(),
rootThreadEventId = rootThreadEventId)
} else { } else {
voiceMessageHelper.deleteRecording() voiceMessageHelper.deleteRecording()
} }

View File

@ -60,6 +60,8 @@ import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
import org.matrix.android.sdk.api.session.room.timeline.hasBeenEdited import org.matrix.android.sdk.api.session.room.timeline.hasBeenEdited
import org.matrix.android.sdk.api.session.room.timeline.isPoll
import org.matrix.android.sdk.api.session.room.timeline.isSticker
import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.flow.unwrap import org.matrix.android.sdk.flow.unwrap
@ -442,14 +444,14 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
* Determine whether or not the Reply In Thread bottom sheet setting will be visible * Determine whether or not the Reply In Thread bottom sheet setting will be visible
* to the user * to the user
*/ */
// TODO handle reply in thread for images etc
private fun canReplyInThread(event: TimelineEvent, private fun canReplyInThread(event: TimelineEvent,
messageContent: MessageContent?, messageContent: MessageContent?,
actionPermissions: ActionPermissions): Boolean { actionPermissions: ActionPermissions): Boolean {
// Only event of type EventType.MESSAGE are supported for the moment // Only event of type EventType.MESSAGE are supported for the moment
if (!BuildConfig.THREADING_ENABLED) return false if (!BuildConfig.THREADING_ENABLED) return false
if (initialState.isFromThreadTimeline) return false if (initialState.isFromThreadTimeline) return false
if (event.root.getClearType() != EventType.MESSAGE) return false if (event.root.getClearType() != EventType.MESSAGE &&
!event.isSticker() && !event.isPoll()) return false
if (!actionPermissions.canSendMessage) return false if (!actionPermissions.canSendMessage) return false
return when (messageContent?.msgType) { return when (messageContent?.msgType) {
MessageType.MSGTYPE_TEXT, MessageType.MSGTYPE_TEXT,
@ -458,8 +460,10 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
MessageType.MSGTYPE_IMAGE, MessageType.MSGTYPE_IMAGE,
MessageType.MSGTYPE_VIDEO, MessageType.MSGTYPE_VIDEO,
MessageType.MSGTYPE_AUDIO, MessageType.MSGTYPE_AUDIO,
MessageType.MSGTYPE_FILE -> true MessageType.MSGTYPE_FILE,
else -> false MessageType.MSGTYPE_POLL_START,
MessageType.MSGTYPE_STICKER_LOCAL -> true
else -> false
} }
} }
@ -468,12 +472,13 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
* a thread timeline * a thread timeline
*/ */
private fun canViewInRoom(event: TimelineEvent, private fun canViewInRoom(event: TimelineEvent,
messageContent: MessageContent?, messageContent: MessageContent?,
actionPermissions: ActionPermissions): Boolean { actionPermissions: ActionPermissions): Boolean {
// Only event of type EventType.MESSAGE are supported for the moment // Only event of type EventType.MESSAGE are supported for the moment
if (!BuildConfig.THREADING_ENABLED) return false if (!BuildConfig.THREADING_ENABLED) return false
if (!initialState.isFromThreadTimeline) return false if (!initialState.isFromThreadTimeline) return false
if (event.root.getClearType() != EventType.MESSAGE) return false if (event.root.getClearType() != EventType.MESSAGE &&
!event.isSticker() && !event.isPoll()) return false
if (!actionPermissions.canSendMessage) return false if (!actionPermissions.canSendMessage) return false
return when (messageContent?.msgType) { return when (messageContent?.msgType) {
@ -483,12 +488,13 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
MessageType.MSGTYPE_IMAGE, MessageType.MSGTYPE_IMAGE,
MessageType.MSGTYPE_VIDEO, MessageType.MSGTYPE_VIDEO,
MessageType.MSGTYPE_AUDIO, MessageType.MSGTYPE_AUDIO,
MessageType.MSGTYPE_FILE -> event.root.threadDetails?.isRootThread ?: false MessageType.MSGTYPE_FILE,
else -> false MessageType.MSGTYPE_POLL_START,
MessageType.MSGTYPE_STICKER_LOCAL -> event.root.threadDetails?.isRootThread ?: false
else -> false
} }
} }
private fun canQuote(event: TimelineEvent, messageContent: MessageContent?, actionPermissions: ActionPermissions): Boolean { private fun canQuote(event: TimelineEvent, messageContent: MessageContent?, actionPermissions: ActionPermissions): Boolean {
// Only event of type EventType.MESSAGE are supported for the moment // Only event of type EventType.MESSAGE are supported for the moment
if (event.root.getClearType() != EventType.MESSAGE) return false if (event.root.getClearType() != EventType.MESSAGE) return false

View File

@ -226,6 +226,18 @@ class MessageItemFactory @Inject constructor(
) )
} }
return PollItem_()
.attributes(attributes)
.eventId(informationData.eventId)
.pollQuestion(pollContent.pollCreationInfo?.question?.question ?: "")
.pollSent(isPollSent)
.totalVotesText(totalVotesText)
.optionViewStates(optionViewStates)
.highlighted(highlight)
.leftGuideline(avatarSizeProvider.leftGuideline)
.callback(callback)
}
private fun buildAudioMessageItem(messageContent: MessageAudioContent, private fun buildAudioMessageItem(messageContent: MessageAudioContent,
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
informationData: MessageInformationData, informationData: MessageInformationData,

View File

@ -19,15 +19,10 @@ package im.vector.app.features.home.room.threads
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.core.view.ViewCompat
import androidx.core.view.children
import androidx.fragment.app.FragmentTransaction import androidx.fragment.app.FragmentTransaction
import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.appbar.MaterialToolbar
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.extensions.addFragment
import im.vector.app.core.extensions.addFragmentToBackstack import im.vector.app.core.extensions.addFragmentToBackstack
import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.extensions.replaceFragment
import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.ToolbarConfigurable
@ -42,6 +37,7 @@ import im.vector.app.features.home.room.threads.list.views.ThreadListFragment
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint
class ThreadsActivity : VectorBaseActivity<ActivityThreadsBinding>(), ToolbarConfigurable { class ThreadsActivity : VectorBaseActivity<ActivityThreadsBinding>(), ToolbarConfigurable {
@Inject @Inject
@ -56,10 +52,6 @@ class ThreadsActivity : VectorBaseActivity<ActivityThreadsBinding>(), ToolbarCon
override fun getCoordinatorLayout() = views.coordinatorLayout override fun getCoordinatorLayout() = views.coordinatorLayout
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
initFragment() initFragment()
@ -83,14 +75,14 @@ class ThreadsActivity : VectorBaseActivity<ActivityThreadsBinding>(), ToolbarCon
private fun initThreadListFragment(threadListArgs: ThreadListArgs) { private fun initThreadListFragment(threadListArgs: ThreadListArgs) {
replaceFragment( replaceFragment(
R.id.threadsActivityFragmentContainer, views.threadsActivityFragmentContainer,
ThreadListFragment::class.java, ThreadListFragment::class.java,
threadListArgs) threadListArgs)
} }
private fun initThreadTimelineFragment(threadTimelineArgs: ThreadTimelineArgs) = private fun initThreadTimelineFragment(threadTimelineArgs: ThreadTimelineArgs) =
replaceFragment( replaceFragment(
R.id.threadsActivityFragmentContainer, views.threadsActivityFragmentContainer,
TimelineFragment::class.java, TimelineFragment::class.java,
TimelineArgs( TimelineArgs(
roomId = threadTimelineArgs.roomId, roomId = threadTimelineArgs.roomId,
@ -113,7 +105,7 @@ class ThreadsActivity : VectorBaseActivity<ActivityThreadsBinding>(), ToolbarCon
it.setCustomAnimations(R.anim.animation_slide_in_right, R.anim.animation_slide_out_left, R.anim.animation_slide_in_left, R.anim.animation_slide_out_right) it.setCustomAnimations(R.anim.animation_slide_in_right, R.anim.animation_slide_out_left, R.anim.animation_slide_in_left, R.anim.animation_slide_out_right)
} }
addFragmentToBackstack( addFragmentToBackstack(
frameId = R.id.threadsActivityFragmentContainer, container = views.threadsActivityFragmentContainer,
fragmentClass = TimelineFragment::class.java, fragmentClass = TimelineFragment::class.java,
params = TimelineArgs( params = TimelineArgs(
roomId = timelineEvent.roomId, roomId = timelineEvent.roomId,

View File

@ -39,7 +39,7 @@ class ThreadListBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetThr
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
threadListViewModel.subscribe(this) { threadListViewModel.onEach {
renderState(it) renderState(it)
} }
views.threadListModalAllThreads.views.bottomSheetActionClickableZone.debouncedClicks { views.threadListModalAllThreads.views.bottomSheetActionClickableZone.debouncedClicks {

View File

@ -35,6 +35,7 @@ import org.matrix.android.sdk.api.session.permalinks.PermalinkData
import org.matrix.android.sdk.api.session.permalinks.PermalinkParser import org.matrix.android.sdk.api.session.permalinks.PermalinkParser
import org.matrix.android.sdk.api.session.permalinks.PermalinkService import org.matrix.android.sdk.api.session.permalinks.PermalinkService
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.RoomType import org.matrix.android.sdk.api.session.room.model.RoomType
import javax.inject.Inject import javax.inject.Inject
@ -86,33 +87,17 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
val rootThreadEventId = permalinkData.eventId?.let { eventId -> val rootThreadEventId = permalinkData.eventId?.let { eventId ->
val room = roomId?.let { session?.getRoom(it) } val room = roomId?.let { session?.getRoom(it) }
// Root thread will be opened in timeline
// if(room?.getTimeLineEvent(eventId)?.root?.threadDetails?.isRootThread == true){
// room.getTimeLineEvent(eventId)?.root?.eventId
// }else{
room?.getTimeLineEvent(eventId)?.root?.getRootThreadEventId() room?.getTimeLineEvent(eventId)?.root?.getRootThreadEventId()
// }
}
// MERGE FROM DEVELOP CONFLICT A.K.
// openRoom(
// navigationInterceptor,
// context = context,
// roomId = roomId,
// permalinkData = permalinkData,
// rawLink = rawLink,
// buildTask = buildTask
// )
if (navigationInterceptor?.navToRoom(roomId, permalinkData.eventId, rawLink,rootThreadEventId) != true) {
openRoom(
context = context,
roomId = roomId,
permalinkData = permalinkData,
rawLink = rawLink,
buildTask = buildTask,
rootThreadEventId = rootThreadEventId
)
} }
openRoom(
navigationInterceptor,
context = context,
roomId = roomId,
permalinkData = permalinkData,
rawLink = rawLink,
buildTask = buildTask,
rootThreadEventId = rootThreadEventId
)
true true
} }
is PermalinkData.GroupLink -> { is PermalinkData.GroupLink -> {
@ -170,14 +155,13 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
* Open room either joined, or not * Open room either joined, or not
*/ */
private fun openRoom( private fun openRoom(
// A.K. conflict navigationInterceptor: NavigationInterceptor?,
// navigationInterceptor: NavigationInterceptor?,
context: Context, context: Context,
roomId: String?, roomId: String?,
permalinkData: PermalinkData.RoomLink, permalinkData: PermalinkData.RoomLink,
rawLink: Uri, rawLink: Uri,
buildTask: Boolean, buildTask: Boolean,
rootThreadEventId: String? =null rootThreadEventId: String? = null
) { ) {
val session = activeSessionHolder.getSafeActiveSession() ?: return val session = activeSessionHolder.getSafeActiveSession() ?: return
if (roomId == null) { if (roomId == null) {
@ -194,13 +178,7 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
membership?.isActive().orFalse() -> { membership?.isActive().orFalse() -> {
if (!isSpace && membership == Membership.JOIN) { if (!isSpace && membership == Membership.JOIN) {
// If it's a room you're in, let's just open it, you can tap back if needed // If it's a room you're in, let's just open it, you can tap back if needed
// A.K. Conflict navigationInterceptor.openJoinedRoomScreen(buildTask, roomId, eventId, rawLink, context, rootThreadEventId, roomSummary)
// navigationInterceptor.openJoinedRoomScreen(buildTask, roomId, eventId, rawLink, context)
rootThreadEventId?.let {
val threadTimelineArgs = ThreadTimelineArgs(roomId, displayName = roomSummary.displayName, roomSummary.avatarUrl, it)
navigator.openThread(context, threadTimelineArgs, eventId)
} ?: navigator.openRoom(context, roomId, eventId, buildTask)
} else { } else {
// maybe open space preview navigator.openSpacePreview(context, roomId)? if already joined? // maybe open space preview navigator.openSpacePreview(context, roomId)? if already joined?
navigator.openMatrixToBottomSheet(context, rawLink.toString()) navigator.openMatrixToBottomSheet(context, rawLink.toString())
@ -213,9 +191,19 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
} }
} }
private fun NavigationInterceptor?.openJoinedRoomScreen(buildTask: Boolean, roomId: String, eventId: String?, rawLink: Uri, context: Context) { private fun NavigationInterceptor?.openJoinedRoomScreen(buildTask: Boolean,
if (this?.navToRoom(roomId, eventId, rawLink) != true) { roomId: String,
navigator.openRoom(context, roomId, eventId, buildTask) eventId: String?,
rawLink: Uri,
context: Context,
rootThreadEventId: String?,
roomSummary: RoomSummary
) {
if (this?.navToRoom(roomId, eventId, rawLink, rootThreadEventId) != true) {
rootThreadEventId?.let {
val threadTimelineArgs = ThreadTimelineArgs(roomId, displayName = roomSummary.displayName, roomSummary.avatarUrl, it)
navigator.openThread(context, threadTimelineArgs, eventId)
} ?: navigator.openRoom(context, roomId, eventId, buildTask)
} }
} }

View File

@ -17,7 +17,7 @@
package im.vector.app.features.room package im.vector.app.features.room
import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.MavericksState
import im.vector.app.features.home.room.detail.RoomDetailArgs import im.vector.app.features.home.room.detail.arguments.TimelineArgs
import im.vector.app.features.roommemberprofile.RoomMemberProfileArgs import im.vector.app.features.roommemberprofile.RoomMemberProfileArgs
import im.vector.app.features.roomprofile.RoomProfileArgs import im.vector.app.features.roomprofile.RoomProfileArgs
@ -25,7 +25,7 @@ data class RequireActiveMembershipViewState(
val roomId: String? = null val roomId: String? = null
) : MavericksState { ) : MavericksState {
constructor(args: RoomDetailArgs) : this(roomId = args.roomId) constructor(args: TimelineArgs) : this(roomId = args.roomId)
constructor(args: RoomProfileArgs) : this(roomId = args.roomId) constructor(args: RoomProfileArgs) : this(roomId = args.roomId)