Add several voice broadcast actions

This commit is contained in:
Florian Renaud 2022-09-23 08:53:21 +02:00
parent d08cfe1147
commit bcc84c8025
5 changed files with 70 additions and 7 deletions

View File

@ -79,7 +79,6 @@ sealed class RoomDetailAction : VectorViewModelAction {
data class ReRequestKeys(val eventId: String) : RoomDetailAction() data class ReRequestKeys(val eventId: String) : RoomDetailAction()
object SelectStickerAttachment : RoomDetailAction() object SelectStickerAttachment : RoomDetailAction()
object StartVoiceBroadcast : RoomDetailAction()
object OpenIntegrationManager : RoomDetailAction() object OpenIntegrationManager : RoomDetailAction()
object ManageIntegrations : RoomDetailAction() object ManageIntegrations : RoomDetailAction()
data class AddJitsiWidget(val withVideo: Boolean) : RoomDetailAction() data class AddJitsiWidget(val withVideo: Boolean) : RoomDetailAction()
@ -120,4 +119,11 @@ sealed class RoomDetailAction : VectorViewModelAction {
object StopLiveLocationSharing : RoomDetailAction() object StopLiveLocationSharing : RoomDetailAction()
object OpenElementCallWidget : RoomDetailAction() object OpenElementCallWidget : RoomDetailAction()
sealed class VoiceBroadcastAction : RoomDetailAction() {
object Start : VoiceBroadcastAction()
object Pause : VoiceBroadcastAction()
object Resume : VoiceBroadcastAction()
object Stop : VoiceBroadcastAction()
}
} }

View File

@ -65,6 +65,7 @@ import im.vector.app.features.raw.wellknown.withElementWellKnown
import im.vector.app.features.session.coroutineScope import im.vector.app.features.session.coroutineScope
import im.vector.app.features.settings.VectorDataStore import im.vector.app.features.settings.VectorDataStore
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.voicebroadcast.VoiceBroadcastHelper
import im.vector.lib.core.utils.flow.chunk import im.vector.lib.core.utils.flow.chunk
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
@ -149,6 +150,7 @@ class TimelineViewModel @AssistedInject constructor(
buildMeta: BuildMeta, buildMeta: BuildMeta,
timelineFactory: TimelineFactory, timelineFactory: TimelineFactory,
private val spaceStateHandler: SpaceStateHandler, private val spaceStateHandler: SpaceStateHandler,
private val voiceBroadcastHelper: VoiceBroadcastHelper,
) : VectorViewModel<RoomDetailViewState, RoomDetailAction, RoomDetailViewEvents>(initialState), ) : VectorViewModel<RoomDetailViewState, RoomDetailAction, RoomDetailViewEvents>(initialState),
Timeline.Listener, ChatEffectManager.Delegate, CallProtocolsChecker.Listener, LocationSharingServiceConnection.Callback { Timeline.Listener, ChatEffectManager.Delegate, CallProtocolsChecker.Listener, LocationSharingServiceConnection.Callback {
@ -456,7 +458,7 @@ class TimelineViewModel @AssistedInject constructor(
is RoomDetailAction.ReRequestKeys -> handleReRequestKeys(action) is RoomDetailAction.ReRequestKeys -> handleReRequestKeys(action)
is RoomDetailAction.TapOnFailedToDecrypt -> handleTapOnFailedToDecrypt(action) is RoomDetailAction.TapOnFailedToDecrypt -> handleTapOnFailedToDecrypt(action)
is RoomDetailAction.SelectStickerAttachment -> handleSelectStickerAttachment() is RoomDetailAction.SelectStickerAttachment -> handleSelectStickerAttachment()
is RoomDetailAction.StartVoiceBroadcast -> handleStartVoiceBroadcast() is RoomDetailAction.VoiceBroadcastAction -> handleVoiceBroadcastAction(action)
is RoomDetailAction.OpenIntegrationManager -> handleOpenIntegrationManager() is RoomDetailAction.OpenIntegrationManager -> handleOpenIntegrationManager()
is RoomDetailAction.StartCall -> handleStartCall(action) is RoomDetailAction.StartCall -> handleStartCall(action)
is RoomDetailAction.AcceptCall -> handleAcceptCall(action) is RoomDetailAction.AcceptCall -> handleAcceptCall(action)
@ -598,9 +600,16 @@ class TimelineViewModel @AssistedInject constructor(
} }
} }
private fun handleStartVoiceBroadcast() { private fun handleVoiceBroadcastAction(action: RoomDetailAction.VoiceBroadcastAction) {
// Todo implement start voice broadcast action if (room == null) return
Timber.d("Start voice broadcast clicked") viewModelScope.launch {
when (action) {
RoomDetailAction.VoiceBroadcastAction.Pause -> voiceBroadcastHelper.pauseVoiceBroadcast(room.roomId)
RoomDetailAction.VoiceBroadcastAction.Resume -> voiceBroadcastHelper.resumeVoiceBroadcast(room.roomId)
RoomDetailAction.VoiceBroadcastAction.Start -> voiceBroadcastHelper.startVoiceBroadcast(room.roomId)
RoomDetailAction.VoiceBroadcastAction.Stop -> voiceBroadcastHelper.stopVoiceBroadcast(room.roomId)
}
}
} }
private fun handleOpenIntegrationManager() { private fun handleOpenIntegrationManager() {

View File

@ -73,6 +73,7 @@ import im.vector.app.features.command.ParsedCommand
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.AutoCompleter import im.vector.app.features.home.room.detail.AutoCompleter
import im.vector.app.features.home.room.detail.RoomDetailAction import im.vector.app.features.home.room.detail.RoomDetailAction
import im.vector.app.features.home.room.detail.RoomDetailAction.VoiceBroadcastAction
import im.vector.app.features.home.room.detail.TimelineViewModel import im.vector.app.features.home.room.detail.TimelineViewModel
import im.vector.app.features.home.room.detail.composer.voice.VoiceMessageRecorderView import im.vector.app.features.home.room.detail.composer.voice.VoiceMessageRecorderView
import im.vector.app.features.home.room.detail.timeline.action.MessageSharedActionViewModel import im.vector.app.features.home.room.detail.timeline.action.MessageSharedActionViewModel
@ -653,7 +654,7 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
locationOwnerId = session.myUserId locationOwnerId = session.myUserId
) )
} }
AttachmentTypeSelectorView.Type.VOICE_BROADCAST -> timelineViewModel.handle(RoomDetailAction.StartVoiceBroadcast) AttachmentTypeSelectorView.Type.VOICE_BROADCAST -> timelineViewModel.handle(VoiceBroadcastAction.Start)
} }
} }

View File

@ -77,6 +77,8 @@ import im.vector.app.features.media.ImageContentRenderer
import im.vector.app.features.media.VideoContentRenderer import im.vector.app.features.media.VideoContentRenderer
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.voice.AudioWaveformView import im.vector.app.features.voice.AudioWaveformView
import im.vector.app.features.voicebroadcast.STATE_ROOM_VOICE_BROADCAST_INFO
import im.vector.app.features.voicebroadcast.model.MessageVoiceBroadcastInfoContent
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
import me.gujun.android.span.span import me.gujun.android.span.span
import org.matrix.android.sdk.api.MatrixUrls.isMxcUrl import org.matrix.android.sdk.api.MatrixUrls.isMxcUrl
@ -102,6 +104,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageVerification
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
import org.matrix.android.sdk.api.session.room.model.message.getThumbnailUrl import org.matrix.android.sdk.api.session.room.model.message.getThumbnailUrl
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.settings.LightweightSettingsStorage import org.matrix.android.sdk.api.settings.LightweightSettingsStorage
import org.matrix.android.sdk.api.util.MimeTypes import org.matrix.android.sdk.api.util.MimeTypes
@ -163,7 +166,7 @@ class MessageItemFactory @Inject constructor(
return buildRedactedItem(attributes, highlight) return buildRedactedItem(attributes, highlight)
} }
val messageContent = event.getLastMessageContent() val messageContent = getLastMessageContent(event)
if (messageContent == null) { if (messageContent == null) {
val malformedText = stringProvider.getString(R.string.malformed_message) val malformedText = stringProvider.getString(R.string.malformed_message)
return defaultItemFactory.create(malformedText, informationData, highlight, callback) return defaultItemFactory.create(malformedText, informationData, highlight, callback)
@ -197,6 +200,7 @@ class MessageItemFactory @Inject constructor(
is MessagePollContent -> buildPollItem(messageContent, informationData, highlight, callback, attributes) is MessagePollContent -> buildPollItem(messageContent, informationData, highlight, callback, attributes)
is MessageLocationContent -> buildLocationItem(messageContent, informationData, highlight, attributes) is MessageLocationContent -> buildLocationItem(messageContent, informationData, highlight, attributes)
is MessageBeaconInfoContent -> liveLocationShareMessageItemFactory.create(params.event, highlight, attributes) is MessageBeaconInfoContent -> liveLocationShareMessageItemFactory.create(params.event, highlight, attributes)
is MessageVoiceBroadcastInfoContent -> buildVoiceBroadcastItem(messageContent, informationData, highlight, callback, attributes)
else -> buildNotHandledMessageItem(messageContent, informationData, highlight, callback, attributes) else -> buildNotHandledMessageItem(messageContent, informationData, highlight, callback, attributes)
} }
return messageItem?.apply { return messageItem?.apply {
@ -204,6 +208,17 @@ class MessageItemFactory @Inject constructor(
} }
} }
private fun getLastMessageContent(event: TimelineEvent): MessageContent? {
return with(event) {
// Iterate on event types which are not part of the matrix sdk, otherwise fallback to the sdk method
when (root.getClearType()) {
STATE_ROOM_VOICE_BROADCAST_INFO ->
(annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessageVoiceBroadcastInfoContent>()
else -> event.getLastMessageContent()
}
}
}
private fun buildLocationItem( private fun buildLocationItem(
locationContent: MessageLocationContent, locationContent: MessageLocationContent,
informationData: MessageInformationData, informationData: MessageInformationData,
@ -706,6 +721,36 @@ class MessageItemFactory @Inject constructor(
.highlighted(highlight) .highlighted(highlight)
} }
private fun buildVoiceBroadcastItem(
messageContent: MessageVoiceBroadcastInfoContent,
@Suppress("UNUSED_PARAMETER")
informationData: MessageInformationData,
highlight: Boolean,
callback: TimelineEventController.Callback?,
attributes: AbsMessageItem.Attributes,
): MessageTextItem? {
val htmlBody = "voice broadcast state: ${messageContent.voiceBroadcastState}"
val formattedBody = span {
text = htmlBody
textColor = colorProvider.getColorFromAttribute(R.attr.vctr_content_secondary)
textStyle = "italic"
}
val bindingOptions = spanUtils.getBindingOptions(htmlBody)
val message = formattedBody.linkify(callback)
return MessageTextItem_()
.leftGuideline(avatarSizeProvider.leftGuideline)
.previewUrlRetriever(callback?.getPreviewUrlRetriever())
.imageContentRenderer(imageContentRenderer)
.previewUrlCallback(callback)
.attributes(attributes)
.message(message.toEpoxyCharSequence())
.bindingOptions(bindingOptions)
.highlighted(highlight)
.movementMethod(createLinkMovementMethod(callback))
}
private fun List<Int?>?.toFft(): List<Int>? { private fun List<Int?>?.toFft(): List<Int>? {
return this return this
?.filterNotNull() ?.filterNotNull()

View File

@ -21,6 +21,7 @@ import im.vector.app.core.epoxy.TimelineEmptyItem_
import im.vector.app.core.epoxy.VectorEpoxyModel import im.vector.app.core.epoxy.VectorEpoxyModel
import im.vector.app.features.analytics.DecryptionFailureTracker import im.vector.app.features.analytics.DecryptionFailureTracker
import im.vector.app.features.home.room.detail.timeline.helper.TimelineEventVisibilityHelper import im.vector.app.features.home.room.detail.timeline.helper.TimelineEventVisibilityHelper
import im.vector.app.features.voicebroadcast.STATE_ROOM_VOICE_BROADCAST_INFO
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import timber.log.Timber import timber.log.Timber
@ -88,6 +89,7 @@ class TimelineItemFactory @Inject constructor(
// State room create // State room create
EventType.STATE_ROOM_CREATE -> roomCreateItemFactory.create(params) EventType.STATE_ROOM_CREATE -> roomCreateItemFactory.create(params)
in EventType.STATE_ROOM_BEACON_INFO -> messageItemFactory.create(params) in EventType.STATE_ROOM_BEACON_INFO -> messageItemFactory.create(params)
STATE_ROOM_VOICE_BROADCAST_INFO -> messageItemFactory.create(params)
// Unhandled state event types // Unhandled state event types
else -> { else -> {
// Should only happen when shouldShowHiddenEvents() settings is ON // Should only happen when shouldShowHiddenEvents() settings is ON