mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-21 09:02:44 +02:00
Add Voice Broadcast left time countdown
This commit is contained in:
+39
-1
@@ -34,7 +34,13 @@ class VoiceBroadcastRecorderService: VoiceBroadcastRecorderServiceProtocol {
|
||||
private var chunkFile: AVAudioFile! = nil
|
||||
private var chunkFrames: AVAudioFrameCount = 0
|
||||
private var chunkFileNumber: Int = 0
|
||||
|
||||
|
||||
private var currentElapsedTime: UInt = 0 // Time in seconds.
|
||||
private var currentRemainingTime: UInt { // Time in seconds.
|
||||
BuildSettings.voiceBroadcastMaxLength - currentElapsedTime
|
||||
}
|
||||
private var elapsedTimeTimer: Timer?
|
||||
|
||||
// MARK: Public
|
||||
|
||||
weak var serviceDelegate: VoiceBroadcastRecorderServiceDelegate?
|
||||
@@ -67,12 +73,14 @@ class VoiceBroadcastRecorderService: VoiceBroadcastRecorderServiceProtocol {
|
||||
}
|
||||
|
||||
try audioEngine.start()
|
||||
startTimer()
|
||||
|
||||
// Disable the sleep mode during the recording until we are able to handle it
|
||||
UIApplication.shared.isIdleTimerDisabled = true
|
||||
} catch {
|
||||
MXLog.debug("[VoiceBroadcastRecorderService] startRecordingVoiceBroadcast error", context: error)
|
||||
stopRecordingVoiceBroadcast()
|
||||
invalidateTimer()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +89,7 @@ class VoiceBroadcastRecorderService: VoiceBroadcastRecorderServiceProtocol {
|
||||
audioEngine.stop()
|
||||
audioEngine.inputNode.removeTap(onBus: audioNodeBus)
|
||||
UIApplication.shared.isIdleTimerDisabled = false
|
||||
invalidateTimer()
|
||||
|
||||
voiceBroadcastService?.stopVoiceBroadcast(success: { [weak self] _ in
|
||||
MXLog.debug("[VoiceBroadcastRecorderService] Stopped")
|
||||
@@ -110,6 +119,7 @@ class VoiceBroadcastRecorderService: VoiceBroadcastRecorderServiceProtocol {
|
||||
func pauseRecordingVoiceBroadcast() {
|
||||
audioEngine.pause()
|
||||
UIApplication.shared.isIdleTimerDisabled = false
|
||||
invalidateTimer()
|
||||
|
||||
voiceBroadcastService?.pauseVoiceBroadcast(success: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
@@ -126,6 +136,7 @@ class VoiceBroadcastRecorderService: VoiceBroadcastRecorderServiceProtocol {
|
||||
|
||||
func resumeRecordingVoiceBroadcast() {
|
||||
try? audioEngine.start()
|
||||
startTimer()
|
||||
|
||||
voiceBroadcastService?.resumeVoiceBroadcast(success: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
@@ -143,12 +154,14 @@ class VoiceBroadcastRecorderService: VoiceBroadcastRecorderServiceProtocol {
|
||||
private func resetValues() {
|
||||
chunkFrames = 0
|
||||
chunkFileNumber = 0
|
||||
currentElapsedTime = 0
|
||||
}
|
||||
|
||||
/// Release the service
|
||||
private func tearDownVoiceBroadcastService() {
|
||||
resetValues()
|
||||
session.tearDownVoiceBroadcastService()
|
||||
invalidateTimer()
|
||||
|
||||
do {
|
||||
try AVAudioSession.sharedInstance().setActive(false)
|
||||
@@ -157,6 +170,31 @@ class VoiceBroadcastRecorderService: VoiceBroadcastRecorderServiceProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
/// Start ElapsedTimeTimer.
|
||||
private func startTimer() {
|
||||
elapsedTimeTimer = Timer.scheduledTimer(timeInterval: 1.0,
|
||||
target: self,
|
||||
selector: #selector(updateCurrentElapsedTimeValue),
|
||||
userInfo: nil,
|
||||
repeats: true)
|
||||
}
|
||||
|
||||
/// Invalidate ElapsedTimeTimer.
|
||||
private func invalidateTimer() {
|
||||
elapsedTimeTimer?.invalidate()
|
||||
elapsedTimeTimer = nil
|
||||
}
|
||||
|
||||
/// Update currentElapsedTime value.
|
||||
@objc private func updateCurrentElapsedTimeValue() {
|
||||
guard currentRemainingTime > 0 else {
|
||||
stopRecordingVoiceBroadcast()
|
||||
return
|
||||
}
|
||||
currentElapsedTime += 1
|
||||
serviceDelegate?.voiceBroadcastRecorderService(self, didUpdateRemainingTime: self.currentRemainingTime)
|
||||
}
|
||||
|
||||
/// Write audio buffer to chunk file.
|
||||
private func writeBuffer(_ buffer: AVAudioPCMBuffer) {
|
||||
let sampleRate = buffer.format.sampleRate
|
||||
|
||||
+1
@@ -18,6 +18,7 @@ import Foundation
|
||||
|
||||
protocol VoiceBroadcastRecorderServiceDelegate: AnyObject {
|
||||
func voiceBroadcastRecorderService(_ service: VoiceBroadcastRecorderServiceProtocol, didUpdateState state: VoiceBroadcastRecorderState)
|
||||
func voiceBroadcastRecorderService(_ service: VoiceBroadcastRecorderServiceProtocol, didUpdateRemainingTime remainingTime: UInt)
|
||||
}
|
||||
|
||||
protocol VoiceBroadcastRecorderServiceProtocol {
|
||||
|
||||
@@ -53,6 +53,16 @@ struct VoiceBroadcastRecorderView: View {
|
||||
} icon: {
|
||||
Image(uiImage: Asset.Images.voiceBroadcastTileLive.image)
|
||||
}
|
||||
|
||||
if let remainingTimeLabel = viewModel.viewState.currentRecordingState.remainingTimeLabel {
|
||||
Label {
|
||||
Text(remainingTimeLabel)
|
||||
.foregroundColor(theme.colors.secondaryContent)
|
||||
.font(theme.fonts.caption1)
|
||||
} icon: {
|
||||
Image(uiImage: Asset.Images.voiceBroadcastTimeLeft.image)
|
||||
}
|
||||
}
|
||||
}.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
Label {
|
||||
|
||||
@@ -35,9 +35,15 @@ struct VoiceBroadcastRecorderDetails {
|
||||
let avatarData: AvatarInputProtocol
|
||||
}
|
||||
|
||||
struct VoiceBroadcastRecordingState {
|
||||
var remainingTime: UInt
|
||||
var remainingTimeLabel: String?
|
||||
}
|
||||
|
||||
struct VoiceBroadcastRecorderViewState: BindableState {
|
||||
var details: VoiceBroadcastRecorderDetails
|
||||
var recordingState: VoiceBroadcastRecorderState
|
||||
var currentRecordingState: VoiceBroadcastRecordingState
|
||||
var bindings: VoiceBroadcastRecorderViewStateBindings
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -32,7 +32,8 @@ enum MockVoiceBroadcastRecorderScreenState: MockScreenState, CaseIterable {
|
||||
|
||||
var screenView: ([Any], AnyView) {
|
||||
let details = VoiceBroadcastRecorderDetails(senderDisplayName: "", avatarData: AvatarInput(mxContentUri: "", matrixItemId: "!fakeroomid:matrix.org", displayName: "The name of the room"))
|
||||
let viewModel = MockVoiceBroadcastRecorderViewModel(initialViewState: VoiceBroadcastRecorderViewState(details: details, recordingState: .started, bindings: VoiceBroadcastRecorderViewStateBindings()))
|
||||
let recordingState = VoiceBroadcastRecordingState(remainingTime: BuildSettings.voiceBroadcastMaxLength)
|
||||
let viewModel = MockVoiceBroadcastRecorderViewModel(initialViewState: VoiceBroadcastRecorderViewState(details: details, recordingState: .started, currentRecordingState: recordingState, bindings: VoiceBroadcastRecorderViewStateBindings()))
|
||||
|
||||
return (
|
||||
[false, viewModel],
|
||||
|
||||
@@ -34,8 +34,10 @@ class VoiceBroadcastRecorderViewModel: VoiceBroadcastRecorderViewModelType, Voic
|
||||
init(details: VoiceBroadcastRecorderDetails,
|
||||
recorderService: VoiceBroadcastRecorderServiceProtocol) {
|
||||
self.voiceBroadcastRecorderService = recorderService
|
||||
let currentRecordingState = VoiceBroadcastRecordingState(remainingTime: BuildSettings.voiceBroadcastMaxLength)
|
||||
super.init(initialViewState: VoiceBroadcastRecorderViewState(details: details,
|
||||
recordingState: .stopped,
|
||||
currentRecordingState: currentRecordingState,
|
||||
bindings: VoiceBroadcastRecorderViewStateBindings()))
|
||||
|
||||
self.voiceBroadcastRecorderService.serviceDelegate = self
|
||||
@@ -77,10 +79,23 @@ class VoiceBroadcastRecorderViewModel: VoiceBroadcastRecorderViewModelType, Voic
|
||||
self.state.recordingState = .resumed
|
||||
voiceBroadcastRecorderService.resumeRecordingVoiceBroadcast()
|
||||
}
|
||||
|
||||
private func updateRemainingTime(_ remainingTime: UInt) {
|
||||
let time = TimeInterval(Double(remainingTime))
|
||||
let formatter = DateComponentsFormatter()
|
||||
formatter.unitsStyle = .abbreviated
|
||||
|
||||
state.currentRecordingState.remainingTime = remainingTime
|
||||
state.currentRecordingState.remainingTimeLabel = VectorL10n.voiceBroadcastTimeLeft(formatter.string(from: time) ?? "0s")
|
||||
}
|
||||
}
|
||||
|
||||
extension VoiceBroadcastRecorderViewModel: VoiceBroadcastRecorderServiceDelegate {
|
||||
func voiceBroadcastRecorderService(_ service: VoiceBroadcastRecorderServiceProtocol, didUpdateState state: VoiceBroadcastRecorderState) {
|
||||
self.state.recordingState = state
|
||||
}
|
||||
|
||||
func voiceBroadcastRecorderService(_ service: VoiceBroadcastRecorderServiceProtocol, didUpdateRemainingTime remainingTime: UInt) {
|
||||
self.updateRemainingTime(remainingTime)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user