mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-05 11:58:32 +00:00
Fix: Keep the progress indicator visible after pausing or scrubbing a voice message. (#1969)
This commit is contained in:
@@ -37,6 +37,7 @@ enum ComposerToolbarViewModelAction {
|
||||
case deleteVoiceMessageRecording
|
||||
case startVoiceMessagePlayback
|
||||
case pauseVoiceMessagePlayback
|
||||
case scrubVoiceMessagePlayback(scrubbing: Bool)
|
||||
case seekVoiceMessagePlayback(progress: Double)
|
||||
case sendVoiceMessage
|
||||
}
|
||||
@@ -61,6 +62,7 @@ enum ComposerToolbarViewAction {
|
||||
case deleteVoiceMessageRecording
|
||||
case startVoiceMessagePlayback
|
||||
case pauseVoiceMessagePlayback
|
||||
case scrubVoiceMessagePlayback(scrubbing: Bool)
|
||||
case seekVoiceMessagePlayback(progress: Double)
|
||||
}
|
||||
|
||||
|
||||
@@ -155,6 +155,8 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
|
||||
actionsSubject.send(.pauseVoiceMessagePlayback)
|
||||
case .seekVoiceMessagePlayback(let progress):
|
||||
actionsSubject.send(.seekVoiceMessagePlayback(progress: progress))
|
||||
case .scrubVoiceMessagePlayback(let scrubbing):
|
||||
actionsSubject.send(.scrubVoiceMessagePlayback(scrubbing: scrubbing))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -325,6 +325,8 @@ struct ComposerToolbar: View {
|
||||
context.send(viewAction: .pauseVoiceMessagePlayback)
|
||||
} onSeek: { progress in
|
||||
context.send(viewAction: .seekVoiceMessagePlayback(progress: progress))
|
||||
} onScrubbing: { isScrubbing in
|
||||
context.send(viewAction: .scrubVoiceMessagePlayback(scrubbing: isScrubbing))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ struct VoiceMessagePreviewComposer: View {
|
||||
let onPlay: () -> Void
|
||||
let onPause: () -> Void
|
||||
let onSeek: (Double) -> Void
|
||||
let onScrubbing: (Bool) -> Void
|
||||
|
||||
var timeLabelContent: String {
|
||||
// Display the duration if progress is 0.0
|
||||
@@ -39,10 +40,6 @@ struct VoiceMessagePreviewComposer: View {
|
||||
return DateFormatter.elapsedTimeFormatter.string(from: elapsed)
|
||||
}
|
||||
|
||||
var showWaveformCursor: Bool {
|
||||
playerState.playbackState == .playing || isDragging
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
HStack {
|
||||
@@ -60,9 +57,12 @@ struct VoiceMessagePreviewComposer: View {
|
||||
waveformView
|
||||
.waveformInteraction(isDragging: $isDragging,
|
||||
progress: playerState.progress,
|
||||
showCursor: showWaveformCursor,
|
||||
showCursor: playerState.showProgressIndicator,
|
||||
onSeek: onSeek)
|
||||
}
|
||||
.onChange(of: isDragging) { isDragging in
|
||||
onScrubbing(isDragging)
|
||||
}
|
||||
.padding(.vertical, 4.0)
|
||||
.padding(.horizontal, 6.0)
|
||||
.background {
|
||||
@@ -133,7 +133,7 @@ struct VoiceMessagePreviewComposer_Previews: PreviewProvider, TestablePreview {
|
||||
|
||||
static var previews: some View {
|
||||
VStack {
|
||||
VoiceMessagePreviewComposer(playerState: playerState, waveform: .data(waveformData), onPlay: { }, onPause: { }, onSeek: { _ in })
|
||||
VoiceMessagePreviewComposer(playerState: playerState, waveform: .data(waveformData), onPlay: { }, onPause: { }, onSeek: { _ in }, onScrubbing: { _ in })
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
private let actionsSubject: PassthroughSubject<RoomScreenViewModelAction, Never> = .init()
|
||||
private var canCurrentUserRedact = false
|
||||
private var paginateBackwardsTask: Task<Void, Never>?
|
||||
private var resumeVoiceMessagePlaybackAfterScrubbing = false
|
||||
|
||||
init(timelineController: RoomTimelineControllerProtocol,
|
||||
mediaProvider: MediaProviderProtocol,
|
||||
@@ -208,14 +209,13 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
case .sendVoiceMessage:
|
||||
Task { await sendCurrentVoiceMessage() }
|
||||
case .startVoiceMessagePlayback:
|
||||
Task {
|
||||
await mediaPlayerProvider.detachAllStates(except: voiceMessageRecorder.previewAudioPlayerState)
|
||||
await startPlayingRecordedVoiceMessage()
|
||||
}
|
||||
Task { await startPlayingRecordedVoiceMessage() }
|
||||
case .pauseVoiceMessagePlayback:
|
||||
pausePlayingRecordedVoiceMessage()
|
||||
case .seekVoiceMessagePlayback(let progress):
|
||||
Task { await seekRecordedVoiceMessage(to: progress) }
|
||||
case .scrubVoiceMessagePlayback(let scrubbing):
|
||||
Task { await scrubVoiceMessagePlayback(scrubbing: scrubbing) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
}
|
||||
|
||||
switch await timelineController.sendReadReceipt(for: eventItemID) {
|
||||
case .success():
|
||||
case .success:
|
||||
break
|
||||
case let .failure(error):
|
||||
MXLog.error("[TimelineViewController] Failed to send read receipt: \(error)")
|
||||
@@ -1015,6 +1015,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
}
|
||||
|
||||
private func startPlayingRecordedVoiceMessage() async {
|
||||
await mediaPlayerProvider.detachAllStates(except: voiceMessageRecorder.previewAudioPlayerState)
|
||||
if case .failure(let error) = await voiceMessageRecorder.startPlayback() {
|
||||
MXLog.error("failed to play recorded voice message. \(error)")
|
||||
}
|
||||
@@ -1025,9 +1026,27 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
}
|
||||
|
||||
private func seekRecordedVoiceMessage(to progress: Double) async {
|
||||
await mediaPlayerProvider.detachAllStates(except: voiceMessageRecorder.previewAudioPlayerState)
|
||||
await voiceMessageRecorder.seekPlayback(to: progress)
|
||||
}
|
||||
|
||||
private func scrubVoiceMessagePlayback(scrubbing: Bool) async {
|
||||
guard let audioPlayerState = voiceMessageRecorder.previewAudioPlayerState else {
|
||||
return
|
||||
}
|
||||
if scrubbing {
|
||||
if audioPlayerState.playbackState == .playing {
|
||||
resumeVoiceMessagePlaybackAfterScrubbing = true
|
||||
pausePlayingRecordedVoiceMessage()
|
||||
}
|
||||
} else {
|
||||
if resumeVoiceMessagePlaybackAfterScrubbing {
|
||||
resumeVoiceMessagePlaybackAfterScrubbing = false
|
||||
await startPlayingRecordedVoiceMessage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func openSystemSettings() {
|
||||
guard let url = URL(string: UIApplication.openSettingsURLString) else { return }
|
||||
application.open(url)
|
||||
|
||||
Reference in New Issue
Block a user