Merge branch 'develop' into feature/bca/rust_flavor
This commit is contained in:
commit
4ee53ad9d0
|
@ -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 }}KotlinCryptoDebug $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 assembleGplayKotlinCryptoRelease $CI_GRADLE_ARG_PROPERTIES
|
||||
- name: Upload Gplay unsigned APKs
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Support reactions on Voice Broadcast
|
|
@ -0,0 +1 @@
|
|||
Pause voice broadcast listening on new VB recording
|
|
@ -0,0 +1 @@
|
|||
Send voice message should not be allowed during a voice broadcast recording
|
|
@ -0,0 +1 @@
|
|||
Tapping slightly left or right of the 30s buttons highlights the whole cell instead of registering as button presses
|
|
@ -3108,6 +3108,8 @@
|
|||
<string name="error_voice_message_unable_to_play">Cannot play this voice message</string>
|
||||
<string name="error_voice_message_unable_to_record">Cannot record a voice message</string>
|
||||
<string name="error_voice_message_cannot_reply_or_edit">Cannot reply or edit while voice message is active</string>
|
||||
<string name="error_voice_message_broadcast_in_progress">Cannot start voice message</string>
|
||||
<string name="error_voice_message_broadcast_in_progress_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</string>
|
||||
<string name="voice_message_reply_content">Voice Message (%1$s)</string>
|
||||
|
||||
<string name="a11y_audio_message_item">%1$s, %2$s, %3$s</string> <!-- filename, duration, file size -->
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,8 +28,9 @@ 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) + 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.asVoiceBroadcastEvent()?.content?.voiceBroadcastState == VoiceBroadcastState.STARTED) &&
|
||||
root.sendState == SendState.SYNCED &&
|
||||
!root.isRedacted()
|
||||
}
|
||||
|
|
|
@ -627,13 +627,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)
|
||||
|
|
|
@ -191,6 +191,8 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), 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<FragmentComposerBinding>(), 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
|
||||
|
|
|
@ -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
|
||||
|
@ -28,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
|
||||
|
@ -42,12 +44,19 @@ 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.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
|
||||
|
@ -74,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
|
||||
|
@ -88,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<MessageComposerViewState, MessageComposerAction, MessageComposerViewEvents>(initialState) {
|
||||
|
||||
private val room = session.getRoom(initialState.roomId)
|
||||
|
@ -203,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)
|
||||
}
|
||||
|
@ -916,10 +931,16 @@ class MessageComposerViewModel @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private fun handleStartRecordingVoiceMessage(room: Room) {
|
||||
try {
|
||||
audioMessageHelper.startRecording(room.roomId)
|
||||
} catch (failure: Throwable) {
|
||||
_viewEvents.post(MessageComposerViewEvents.VoicePlaybackOrRecordingFailure(failure))
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -125,7 +125,6 @@ class VoiceRecorderFragment : VectorBaseFragment<FragmentVoiceRecorderBinding>()
|
|||
if (checkPermissions(PERMISSIONS_FOR_VOICE_MESSAGE, requireActivity(), permissionVoiceMessageLauncher)) {
|
||||
messageComposerViewModel.handle(MessageComposerAction.StartRecordingVoiceMessage)
|
||||
vibrate(requireContext())
|
||||
updateRecordingUiState(VoiceMessageRecorderView.RecordingUiState.Recording(clock.epochMillis()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -105,8 +105,8 @@
|
|||
|
||||
<ImageButton
|
||||
android:id="@+id/fastBackwardButton"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_width="@dimen/voice_broadcast_player_button_size"
|
||||
android:layout_height="@dimen/voice_broadcast_player_button_size"
|
||||
android:background="@drawable/bg_rounded_button"
|
||||
android:contentDescription="@string/a11y_voice_broadcast_fast_backward"
|
||||
android:src="@drawable/ic_player_backward_30"
|
||||
|
@ -126,8 +126,8 @@
|
|||
|
||||
<ImageButton
|
||||
android:id="@+id/fastForwardButton"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_width="@dimen/voice_broadcast_player_button_size"
|
||||
android:layout_height="@dimen/voice_broadcast_player_button_size"
|
||||
android:background="@drawable/bg_rounded_button"
|
||||
android:contentDescription="@string/a11y_voice_broadcast_fast_forward"
|
||||
android:src="@drawable/ic_player_forward_30"
|
||||
|
|
Loading…
Reference in New Issue