Add several voice broadcast actions
This commit is contained in:
parent
d08cfe1147
commit
bcc84c8025
|
@ -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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue