From 604e167faa74c29cfb162665746f80121db6b211 Mon Sep 17 00:00:00 2001 From: Laurent Date: Mon, 13 Mar 2023 10:06:07 +0100 Subject: [PATCH] Fixes issue when running multiple countdowns at the same time --- LeCountdown/Conductor.swift | 25 ++++++++++++++++------- LeCountdown/Intent/StartTimerIntent.swift | 2 +- LeCountdown/Intent/TimerShortcuts.swift | 2 +- LeCountdown/LeCountdownApp.swift | 2 +- LeCountdown/Sound/DelaySoundPlayer.swift | 10 +-------- LeCountdown/Views/LiveTimerListView.swift | 2 +- 6 files changed, 23 insertions(+), 20 deletions(-) diff --git a/LeCountdown/Conductor.swift b/LeCountdown/Conductor.swift index d3010ec..ba82b68 100644 --- a/LeCountdown/Conductor.swift +++ b/LeCountdown/Conductor.swift @@ -20,14 +20,16 @@ fileprivate enum Const: String { case confirmationSound = "PVP_Stab_Oneshot_Bleep_Em.wav" } +typealias TimerID = String + class Conductor: ObservableObject { static let maestro: Conductor = Conductor() @Published var soundPlayer: SoundPlayer? = nil - var delaySoundPlayer: DelaySoundPlayer? = nil - + var delayedSoundPlayers: [TimerID : DelaySoundPlayer] = [:] + @UserDefault(PreferenceKey.countdowns.rawValue, defaultValue: [:]) static var savedCountdowns: [String : DateInterval] @UserDefault(PreferenceKey.stopwatches.rawValue, defaultValue: [:]) static var savedStopwatches: [String : Date] @@ -138,9 +140,9 @@ class Conductor: ObservableObject { // } } - func cancelCountdown(id: String) { + func cancelCountdown(id: TimerID) { CountdownScheduler.master.cancelCurrentNotifications(countdownId: id) - self.stopSoundIfPossible() + self.cancelSoundPlayer(id: id) self.cancelledCountdowns.append(id) self._endCountdown(countdownId: id, cancel: true) } @@ -163,7 +165,9 @@ class Conductor: ObservableObject { let soundFile = try SoundFile(fullName: countdown.soundName) let soundPlayer = DelaySoundPlayer(soundFile: soundFile) - self.delaySoundPlayer = soundPlayer + + self.delayedSoundPlayers[countdown.stringId] = soundPlayer + try soundPlayer.start(in: countdown.duration, repeatCount: Int(countdown.repeatCount)) @@ -221,7 +225,7 @@ class Conductor: ObservableObject { fileprivate func _cleanupCountdowns() { let now = Date() for (key, value) in self.currentCountdowns { - if value.end < now { + if value.end < now || self.cancelledCountdowns.contains(key) { self._endCountdown(countdownId: key, cancel: false) } } @@ -268,7 +272,14 @@ class Conductor: ObservableObject { } } - func stopSoundIfPossible() { + func cancelSoundPlayer(id: TimerID) { + if let soundPlayer = self.delayedSoundPlayers[id] { + soundPlayer.stop() + self.delayedSoundPlayers.removeValue(forKey: id) + } + } + + func stopMainPlayersIfPossible() { self.soundPlayer?.stop() self.soundPlayer = nil } diff --git a/LeCountdown/Intent/StartTimerIntent.swift b/LeCountdown/Intent/StartTimerIntent.swift index 8fecd74..9541955 100644 --- a/LeCountdown/Intent/StartTimerIntent.swift +++ b/LeCountdown/Intent/StartTimerIntent.swift @@ -20,7 +20,7 @@ struct StartTimerIntent: AppIntent, CustomIntentMigratedAppIntent { var timer: TimerIdentifierAppEntity? static var parameterSummary: some ParameterSummary { - Summary() + Summary("") } func perform() async throws -> some IntentResult & ProvidesDialog & ShowsSnippetView { diff --git a/LeCountdown/Intent/TimerShortcuts.swift b/LeCountdown/Intent/TimerShortcuts.swift index 3a7615d..40ec406 100644 --- a/LeCountdown/Intent/TimerShortcuts.swift +++ b/LeCountdown/Intent/TimerShortcuts.swift @@ -11,8 +11,8 @@ struct TimerShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut(intent: StartTimerIntent(), phrases: [ - "\(.applicationName) \(\.$timer)", "Start \(\.$timer) with \(.applicationName)", + "\(.applicationName) \(\.$timer)", "Launch \(\.$timer) with \(.applicationName)", "Start \(.applicationName)", "Launch \(.applicationName)" diff --git a/LeCountdown/LeCountdownApp.swift b/LeCountdown/LeCountdownApp.swift index 642b6df..d12b44f 100644 --- a/LeCountdown/LeCountdownApp.swift +++ b/LeCountdown/LeCountdownApp.swift @@ -68,7 +68,7 @@ struct LeCountdownApp: App { .onChange(of: scenePhase) { newPhase in switch newPhase { case .inactive: - Conductor.maestro.stopSoundIfPossible() + Conductor.maestro.stopMainPlayersIfPossible() case .active: Logger.log("onChange(of: scenePhase) active") Logger.log(Conductor.maestro.currentCountdowns.count) diff --git a/LeCountdown/Sound/DelaySoundPlayer.swift b/LeCountdown/Sound/DelaySoundPlayer.swift index bac0388..79beedf 100644 --- a/LeCountdown/Sound/DelaySoundPlayer.swift +++ b/LeCountdown/Sound/DelaySoundPlayer.swift @@ -46,15 +46,7 @@ import AVFoundation // MARK: - Delegate func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { - - let audioSession: AVAudioSession = AVAudioSession.sharedInstance() - do { - self.stop() - try audioSession.setActive(false) - } catch { - Logger.error(error) - } - + self.stop() Logger.log("audioPlayerDidFinishPlaying: successfully = \(flag)") } diff --git a/LeCountdown/Views/LiveTimerListView.swift b/LeCountdown/Views/LiveTimerListView.swift index e7799c2..3188b57 100644 --- a/LeCountdown/Views/LiveTimerListView.swift +++ b/LeCountdown/Views/LiveTimerListView.swift @@ -121,7 +121,7 @@ struct LiveCountdownView: View { HStack { let running = self.date > context.date - let cancelled = conductor.cancelledCountdowns.contains(where: { $0 == self.countdown.stringId }) + let cancelled = self.conductor.cancelledCountdowns.contains(where: { $0 == self.countdown.stringId }) VStack(alignment: .leading) {