From 64d116d4acb378f2502f4558f28ed63cec02cb25 Mon Sep 17 00:00:00 2001 From: yostyle Date: Thu, 19 Jan 2023 01:14:48 +0100 Subject: [PATCH 1/9] Pause voice broadcast listening on new VB recording --- changelog.d/7830.misc | 1 + .../app/features/home/room/detail/TimelineViewModel.kt | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 changelog.d/7830.misc diff --git a/changelog.d/7830.misc b/changelog.d/7830.misc new file mode 100644 index 0000000000..51053ef05d --- /dev/null +++ b/changelog.d/7830.misc @@ -0,0 +1 @@ +Pause voice broadcast listening on new VB recording diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt index ff24872ab8..c2a4f4b956 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt @@ -626,13 +626,17 @@ class TimelineViewModel @AssistedInject constructor( viewModelScope.launch { when (action) { VoiceBroadcastAction.Recording.Start -> { + voiceBroadcastHelper.pausePlayback() voiceBroadcastHelper.startVoiceBroadcast(room.roomId).fold( { _viewEvents.post(RoomDetailViewEvents.ActionSuccess(action)) }, { _viewEvents.post(RoomDetailViewEvents.ActionFailure(action, it)) }, ) } VoiceBroadcastAction.Recording.Pause -> voiceBroadcastHelper.pauseVoiceBroadcast(room.roomId) - VoiceBroadcastAction.Recording.Resume -> voiceBroadcastHelper.resumeVoiceBroadcast(room.roomId) + VoiceBroadcastAction.Recording.Resume -> { + voiceBroadcastHelper.pausePlayback() + voiceBroadcastHelper.resumeVoiceBroadcast(room.roomId) + } VoiceBroadcastAction.Recording.Stop -> _viewEvents.post(RoomDetailViewEvents.DisplayPromptToStopVoiceBroadcast) VoiceBroadcastAction.Recording.StopConfirmed -> voiceBroadcastHelper.stopVoiceBroadcast(room.roomId) is VoiceBroadcastAction.Listening.PlayOrResume -> voiceBroadcastHelper.playOrResumePlayback(action.voiceBroadcast) From ba9720416a4748b9b57c1d637fd725c90694340a Mon Sep 17 00:00:00 2001 From: yostyle Date: Thu, 19 Jan 2023 08:44:53 +0100 Subject: [PATCH 2/9] Send voice message should not be allowed during a voice broadcast recording --- changelog.d/7895.bugfix | 1 + .../ui-strings/src/main/res/values/strings.xml | 2 ++ .../im/vector/app/core/error/ErrorFormatter.kt | 1 + .../detail/composer/MessageComposerFragment.kt | 10 ++++++++++ .../detail/composer/MessageComposerViewModel.kt | 15 +++++++++++---- .../im/vector/app/features/voice/VoiceFailure.kt | 1 + 6 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 changelog.d/7895.bugfix diff --git a/changelog.d/7895.bugfix b/changelog.d/7895.bugfix new file mode 100644 index 0000000000..ccde7a554f --- /dev/null +++ b/changelog.d/7895.bugfix @@ -0,0 +1 @@ +Send voice message should not be allowed during a voice broadcast recording diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 38aecaf215..8b51a6f95b 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3097,6 +3097,8 @@ Cannot play this voice message Cannot record a voice message Cannot reply or edit while voice message is active + Cannot start voice message + You can’t start a voice message as you are currently recording a live broadcast. Please end your live broadcast in order to start recording a voice message Voice Message (%1$s) %1$s, %2$s, %3$s diff --git a/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt b/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt index c1e201cfc4..13f8997452 100644 --- a/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt +++ b/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt @@ -151,6 +151,7 @@ class DefaultErrorFormatter @Inject constructor( return when (throwable) { is VoiceFailure.UnableToPlay -> stringProvider.getString(R.string.error_voice_message_unable_to_play) is VoiceFailure.UnableToRecord -> stringProvider.getString(R.string.error_voice_message_unable_to_record) + is VoiceFailure.VoiceBroadcastInProgress -> stringProvider.getString(R.string.error_voice_message_broadcast_in_progress) } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerFragment.kt index 4849e20b6d..28c8757e6c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerFragment.kt @@ -191,6 +191,8 @@ class MessageComposerFragment : VectorBaseFragment(), A is MessageComposerViewEvents.VoicePlaybackOrRecordingFailure -> { if (it.throwable is VoiceFailure.UnableToRecord) { onCannotRecord() + } else if (it.throwable is VoiceFailure.VoiceBroadcastInProgress) { + displayErrorVoiceBroadcastInProgress() } showErrorInSnackbar(it.throwable) } @@ -526,6 +528,14 @@ class MessageComposerFragment : VectorBaseFragment(), A messageComposerViewModel.handle(MessageComposerAction.OnVoiceRecordingUiStateChanged(VoiceMessageRecorderView.RecordingUiState.Idle)) } + private fun displayErrorVoiceBroadcastInProgress() { + MaterialAlertDialogBuilder(requireActivity()) + .setTitle(R.string.error_voice_message_broadcast_in_progress) + .setMessage(getString(R.string.error_voice_message_broadcast_in_progress_message)) + .setPositiveButton(android.R.string.ok, null) + .show() + } + private fun handleJoinedToAnotherRoom(action: MessageComposerViewEvents.JoinRoomCommandSuccess) { composer.setTextIfDifferent("") lockSendButton = false diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt index 56ee9ffb5a..9dc9f35d6c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt @@ -19,6 +19,7 @@ package im.vector.app.features.home.room.detail.composer import android.text.SpannableString import androidx.lifecycle.asFlow import com.airbnb.mvrx.MavericksViewModelFactory +import com.airbnb.mvrx.withState import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -42,6 +43,7 @@ import im.vector.app.features.home.room.detail.toMessageType import im.vector.app.features.powerlevel.PowerLevelsFlowFactory import im.vector.app.features.session.coroutineScope import im.vector.app.features.settings.VectorPreferences +import im.vector.app.features.voice.VoiceFailure import im.vector.app.features.voicebroadcast.VoiceBroadcastConstants import im.vector.app.features.voicebroadcast.VoiceBroadcastHelper import im.vector.app.features.voicebroadcast.model.asVoiceBroadcastEvent @@ -916,10 +918,15 @@ class MessageComposerViewModel @AssistedInject constructor( } private fun handleStartRecordingVoiceMessage(room: Room) { - try { - audioMessageHelper.startRecording(room.roomId) - } catch (failure: Throwable) { - _viewEvents.post(MessageComposerViewEvents.VoicePlaybackOrRecordingFailure(failure)) + val isRecordingVoiceBroadcast = withState(this) { it.isRecordingVoiceBroadcast } + if (isRecordingVoiceBroadcast) { + _viewEvents.post(MessageComposerViewEvents.VoicePlaybackOrRecordingFailure(VoiceFailure.VoiceBroadcastInProgress)) + } else { + try { + audioMessageHelper.startRecording(room.roomId) + } catch (failure: Throwable) { + _viewEvents.post(MessageComposerViewEvents.VoicePlaybackOrRecordingFailure(failure)) + } } } diff --git a/vector/src/main/java/im/vector/app/features/voice/VoiceFailure.kt b/vector/src/main/java/im/vector/app/features/voice/VoiceFailure.kt index 9c4b345dc4..0a837581fd 100644 --- a/vector/src/main/java/im/vector/app/features/voice/VoiceFailure.kt +++ b/vector/src/main/java/im/vector/app/features/voice/VoiceFailure.kt @@ -19,4 +19,5 @@ package im.vector.app.features.voice sealed class VoiceFailure(cause: Throwable? = null) : Throwable(cause = cause) { data class UnableToPlay(val throwable: Throwable) : VoiceFailure(throwable) data class UnableToRecord(val throwable: Throwable) : VoiceFailure(throwable) + object VoiceBroadcastInProgress : VoiceFailure() } From e4d03942347e0a6e1f04eb32d33b8c4000f3cd4e Mon Sep 17 00:00:00 2001 From: yostyle Date: Thu, 19 Jan 2023 11:27:52 +0100 Subject: [PATCH 3/9] Support reactions on Voice Broadcast --- changelog.d/7807.misc | 1 + .../main/java/im/vector/app/core/extensions/TimelineEvent.kt | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 changelog.d/7807.misc diff --git a/changelog.d/7807.misc b/changelog.d/7807.misc new file mode 100644 index 0000000000..bc25a2a3d9 --- /dev/null +++ b/changelog.d/7807.misc @@ -0,0 +1 @@ +Support reactions on Voice Broadcast diff --git a/vector/src/main/java/im/vector/app/core/extensions/TimelineEvent.kt b/vector/src/main/java/im/vector/app/core/extensions/TimelineEvent.kt index 89bd28fc93..cacec4cc79 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/TimelineEvent.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/TimelineEvent.kt @@ -27,7 +27,8 @@ import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent fun TimelineEvent.canReact(): Boolean { // Only event of type EventType.MESSAGE, EventType.STICKER and EventType.POLL_START are supported for the moment - return root.getClearType() in listOf(EventType.MESSAGE, EventType.STICKER) + EventType.POLL_START.values + EventType.POLL_END.values && + return root.getClearType() in listOf(EventType.MESSAGE, EventType.STICKER, VoiceBroadcastConstants.STATE_ROOM_VOICE_BROADCAST_INFO) + + EventType.POLL_START.values + EventType.POLL_END.values && root.sendState == SendState.SYNCED && !root.isRedacted() } From 31eaa9e2cfbcc3b96b0f653b8336994b9a90a646 Mon Sep 17 00:00:00 2001 From: yostyle Date: Thu, 19 Jan 2023 12:11:16 +0100 Subject: [PATCH 4/9] Update reaction condition on voicebroadcast --- .../java/im/vector/app/core/extensions/TimelineEvent.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/extensions/TimelineEvent.kt b/vector/src/main/java/im/vector/app/core/extensions/TimelineEvent.kt index cacec4cc79..f2ee93cc6d 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/TimelineEvent.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/TimelineEvent.kt @@ -18,6 +18,8 @@ package im.vector.app.core.extensions import im.vector.app.features.voicebroadcast.VoiceBroadcastConstants import im.vector.app.features.voicebroadcast.model.MessageVoiceBroadcastInfoContent +import im.vector.app.features.voicebroadcast.model.VoiceBroadcastState +import im.vector.app.features.voicebroadcast.model.asVoiceBroadcastEvent import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.message.MessageContent @@ -26,9 +28,10 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent fun TimelineEvent.canReact(): Boolean { - // Only event of type EventType.MESSAGE, EventType.STICKER and EventType.POLL_START are supported for the moment - return root.getClearType() in listOf(EventType.MESSAGE, EventType.STICKER, VoiceBroadcastConstants.STATE_ROOM_VOICE_BROADCAST_INFO) + - EventType.POLL_START.values + EventType.POLL_END.values && + // Only event of type EventType.MESSAGE, EventType.STICKER and EventType.POLL_START, and started voice broadcast are supported for the moment + return (root.getClearType() in listOf(EventType.MESSAGE, EventType.STICKER) + EventType.POLL_START.values + EventType.POLL_END.values || + root.getClearType() == VoiceBroadcastConstants.STATE_ROOM_VOICE_BROADCAST_INFO && + root.asVoiceBroadcastEvent()?.content?.voiceBroadcastState == VoiceBroadcastState.STARTED) && root.sendState == SendState.SYNCED && !root.isRedacted() } From 8e77f90348d5b07d289488b7ef33eecce53de427 Mon Sep 17 00:00:00 2001 From: Michael Kaye <1917473+michaelkaye@users.noreply.github.com> Date: Thu, 19 Jan 2023 11:20:16 +0000 Subject: [PATCH 5/9] Use gradle build cache action rather than manual cache usage. (#7944) --- .github/workflows/build.yml | 20 ++++++-------------- .github/workflows/nightly.yml | 10 +++------- .github/workflows/post-pr.yml | 18 +++++++----------- .github/workflows/tests.yml | 10 +++------- 4 files changed, 19 insertions(+), 39 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index be175c0436..8832499c43 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,14 +25,10 @@ jobs: cancel-in-progress: true steps: - uses: actions/checkout@v3 - - uses: actions/cache@v3 + - name: Configure gradle + uses: gradle/gradle-build-action@v2 with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- + cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Assemble ${{ matrix.target }} debug apk run: ./gradlew assemble${{ matrix.target }}Debug $CI_GRADLE_ARG_PROPERTIES - name: Upload ${{ matrix.target }} debug APKs @@ -50,14 +46,10 @@ jobs: cancel-in-progress: ${{ github.ref != 'refs/head/main' }} steps: - uses: actions/checkout@v3 - - uses: actions/cache@v3 + - name: Configure gradle + uses: gradle/gradle-build-action@v2 with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- + cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Assemble GPlay unsigned apk run: ./gradlew clean assembleGplayRelease $CI_GRADLE_ARG_PROPERTIES - name: Upload Gplay unsigned APKs diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 51c1b32e82..2f53964ebb 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -19,14 +19,10 @@ jobs: uses: actions/setup-python@v4 with: python-version: 3.8 - - uses: actions/cache@v3 + - name: Configure gradle + uses: gradle/gradle-build-action@v2 with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- + cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Install towncrier run: | python3 -m pip install towncrier diff --git a/.github/workflows/post-pr.yml b/.github/workflows/post-pr.yml index af854bf371..0245fcdd34 100644 --- a/.github/workflows/post-pr.yml +++ b/.github/workflows/post-pr.yml @@ -44,14 +44,14 @@ jobs: uses: actions/setup-python@v4 with: python-version: 3.8 - - uses: actions/cache@v3 + - uses: actions/setup-java@v3 with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- + distribution: 'adopt' + java-version: '11' + - name: Configure gradle + uses: gradle/gradle-build-action@v2 + with: + cache-read-only: ${{ github.ref != 'refs/heads/develop' }} - name: Start synapse server uses: michaelkaye/setup-matrix-synapse@v1.0.4 with: @@ -59,10 +59,6 @@ jobs: httpPort: 8080 disableRateLimiting: true public_baseurl: "http://10.0.2.2:8080/" - - uses: actions/setup-java@v3 - with: - distribution: 'adopt' - java-version: '11' - name: Run sanity tests on API ${{ matrix.api-level }} uses: reactivecircus/android-emulator-runner@v2 with: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 931ec2da45..d9ae49a5f0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -139,14 +139,10 @@ jobs: # with: # distribution: 'adopt' # java-version: 11 -# - uses: actions/cache@v3 +# - name: Configure gradle +# uses: gradle/gradle-build-action@v2 # with: -# path: | -# ~/.gradle/caches -# ~/.gradle/wrapper -# key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} -# restore-keys: | -# ${{ runner.os }}-gradle- +# cache-read-only: ${{ github.ref != 'refs/heads/develop' }} # - name: Build Android Tests # run: ./gradlew clean assembleAndroidTest $CI_GRADLE_ARG_PROPERTIES From ca28c2481877b96a37a1921eafe755a9da67cb65 Mon Sep 17 00:00:00 2001 From: yostyle Date: Thu, 19 Jan 2023 12:35:53 +0100 Subject: [PATCH 6/9] Update fastBackward and fastForward button sizes --- changelog.d/7929.misc | 1 + ...item_timeline_event_voice_broadcast_listening_stub.xml | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 changelog.d/7929.misc diff --git a/changelog.d/7929.misc b/changelog.d/7929.misc new file mode 100644 index 0000000000..c0d32ad6b2 --- /dev/null +++ b/changelog.d/7929.misc @@ -0,0 +1 @@ +Tapping slightly left or right of the 30s buttons highlights the whole cell instead of registering as button presses diff --git a/vector/src/main/res/layout/item_timeline_event_voice_broadcast_listening_stub.xml b/vector/src/main/res/layout/item_timeline_event_voice_broadcast_listening_stub.xml index deec85e2ed..98a9ccaa2d 100644 --- a/vector/src/main/res/layout/item_timeline_event_voice_broadcast_listening_stub.xml +++ b/vector/src/main/res/layout/item_timeline_event_voice_broadcast_listening_stub.xml @@ -105,8 +105,8 @@ Date: Fri, 20 Jan 2023 08:12:37 +0100 Subject: [PATCH 7/9] Bump google-services from 4.3.14 to 4.3.15 (#7983) Bumps google-services from 4.3.14 to 4.3.15. --- updated-dependencies: - dependency-name: com.google.gms:google-services dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 850a4143c9..7c2ec1748e 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ buildscript { classpath libs.gradle.kotlinPlugin classpath libs.gradle.hiltPlugin classpath 'com.google.firebase:firebase-appdistribution-gradle:3.1.1' - classpath 'com.google.gms:google-services:4.3.14' + classpath 'com.google.gms:google-services:4.3.15' classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.5.0.2730' classpath 'com.google.android.gms:oss-licenses-plugin:0.10.6' classpath "com.likethesalad.android:stem-plugin:2.3.0" From cdbf247734dd64b507b9ad832824dc783bc53d3d Mon Sep 17 00:00:00 2001 From: yostyle Date: Fri, 20 Jan 2023 08:49:05 +0100 Subject: [PATCH 8/9] Fix PR comment --- .../src/main/java/im/vector/app/core/extensions/TimelineEvent.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/core/extensions/TimelineEvent.kt b/vector/src/main/java/im/vector/app/core/extensions/TimelineEvent.kt index f2ee93cc6d..16e8405887 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/TimelineEvent.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/TimelineEvent.kt @@ -30,7 +30,6 @@ import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent fun TimelineEvent.canReact(): Boolean { // Only event of type EventType.MESSAGE, EventType.STICKER and EventType.POLL_START, and started voice broadcast are supported for the moment return (root.getClearType() in listOf(EventType.MESSAGE, EventType.STICKER) + EventType.POLL_START.values + EventType.POLL_END.values || - root.getClearType() == VoiceBroadcastConstants.STATE_ROOM_VOICE_BROADCAST_INFO && root.asVoiceBroadcastEvent()?.content?.voiceBroadcastState == VoiceBroadcastState.STARTED) && root.sendState == SendState.SYNCED && !root.isRedacted() From 0a60d0306e14b3066bec7c84a43821aed7f706f0 Mon Sep 17 00:00:00 2001 From: yostyle Date: Fri, 20 Jan 2023 15:26:17 +0100 Subject: [PATCH 9/9] Fix PR comments --- .../composer/MessageComposerViewModel.kt | 24 +++++++++++++++---- .../composer/voice/VoiceRecorderFragment.kt | 1 - 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt index 9dc9f35d6c..fc79c069fe 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt @@ -29,6 +29,7 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.extensions.getVectorLastMessageContent import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider +import im.vector.app.core.time.Clock import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.analytics.extensions.toAnalyticsComposer import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom @@ -46,10 +47,16 @@ import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.voice.VoiceFailure import im.vector.app.features.voicebroadcast.VoiceBroadcastConstants import im.vector.app.features.voicebroadcast.VoiceBroadcastHelper +import im.vector.app.features.voicebroadcast.model.VoiceBroadcast +import im.vector.app.features.voicebroadcast.model.VoiceBroadcastState import im.vector.app.features.voicebroadcast.model.asVoiceBroadcastEvent +import im.vector.app.features.voicebroadcast.usecase.GetVoiceBroadcastStateEventLiveUseCase +import im.vector.app.features.voicebroadcast.voiceBroadcastId import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session @@ -76,6 +83,7 @@ import org.matrix.android.sdk.api.session.room.send.UserDraft import org.matrix.android.sdk.api.session.room.timeline.getRelationContent import org.matrix.android.sdk.api.session.room.timeline.getTextEditableContent import org.matrix.android.sdk.api.session.space.CreateSpaceParams +import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.flow.unwrap import timber.log.Timber @@ -90,6 +98,8 @@ class MessageComposerViewModel @AssistedInject constructor( private val audioMessageHelper: AudioMessageHelper, private val analyticsTracker: AnalyticsTracker, private val voiceBroadcastHelper: VoiceBroadcastHelper, + private val clock: Clock, + private val getVoiceBroadcastStateEventLiveUseCase: GetVoiceBroadcastStateEventLiveUseCase, ) : VectorViewModel(initialState) { private val room = session.getRoom(initialState.roomId) @@ -205,8 +215,11 @@ class MessageComposerViewModel @AssistedInject constructor( private fun observeVoiceBroadcast(room: Room) { room.stateService().getStateEventLive(VoiceBroadcastConstants.STATE_ROOM_VOICE_BROADCAST_INFO, QueryStringValue.Equals(session.myUserId)) .asFlow() - .unwrap() - .mapNotNull { it.asVoiceBroadcastEvent()?.content?.voiceBroadcastState } + .map { it.getOrNull()?.asVoiceBroadcastEvent()?.voiceBroadcastId } + .flatMapLatest { voiceBroadcastId -> + voiceBroadcastId?.let { getVoiceBroadcastStateEventLiveUseCase.execute(VoiceBroadcast(it, room.roomId)) } ?: flowOf(Optional.empty()) + } + .map { it.getOrNull()?.content?.voiceBroadcastState } .setOnEach { copy(voiceBroadcastState = it) } @@ -918,12 +931,13 @@ class MessageComposerViewModel @AssistedInject constructor( } private fun handleStartRecordingVoiceMessage(room: Room) { - val isRecordingVoiceBroadcast = withState(this) { it.isRecordingVoiceBroadcast } - if (isRecordingVoiceBroadcast) { + val voiceBroadcastState = withState(this) { it.voiceBroadcastState } + if (voiceBroadcastState != null && voiceBroadcastState != VoiceBroadcastState.STOPPED) { _viewEvents.post(MessageComposerViewEvents.VoicePlaybackOrRecordingFailure(VoiceFailure.VoiceBroadcastInProgress)) } else { try { audioMessageHelper.startRecording(room.roomId) + setState { copy(voiceRecordingUiState = VoiceMessageRecorderView.RecordingUiState.Recording(clock.epochMillis())) } } catch (failure: Throwable) { _viewEvents.post(MessageComposerViewEvents.VoicePlaybackOrRecordingFailure(failure)) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceRecorderFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceRecorderFragment.kt index 25764f3654..90b813d347 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceRecorderFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceRecorderFragment.kt @@ -125,7 +125,6 @@ class VoiceRecorderFragment : VectorBaseFragment() if (checkPermissions(PERMISSIONS_FOR_VOICE_MESSAGE, requireActivity(), permissionVoiceMessageLauncher)) { messageComposerViewModel.handle(MessageComposerAction.StartRecordingVoiceMessage) vibrate(requireContext()) - updateRecordingUiState(VoiceMessageRecorderView.RecordingUiState.Recording(clock.epochMillis())) } }