From 99ab0cd0a8cf8c861a47a28361a5aa0173f53567 Mon Sep 17 00:00:00 2001 From: Mariela Date: Wed, 19 Feb 2025 13:59:54 +0100 Subject: [PATCH 1/6] WIP: stopping sound when tapped again in widget --- App/IntentRunner.swift | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/App/IntentRunner.swift b/App/IntentRunner.swift index 025976f..f96bb52 100644 --- a/App/IntentRunner.swift +++ b/App/IntentRunner.swift @@ -11,19 +11,29 @@ import UIKit import MediaPlayer enum IntentRunner { + private static var player: AudioPlayer? + static func perform(intent: SoundIntent) async throws -> some IntentResult { + if let currentPlayer = player, currentPlayer.isPlaying { + print("Stopping sound \(intent.sound.title)") + currentPlayer.stop() + player = nil + return .result() + } + print("Start playing \(intent.sound.title)") - let player = try! AudioPlayer(url: intent.sound.file.fileURL!) + let newPlayer = try! AudioPlayer(url: intent.sound.file.fileURL!) + player = newPlayer print("Created sound for \(intent.sound.title)") - if intent.isFullBlast && player.isOnSpeaker { + if intent.isFullBlast && newPlayer.isOnSpeaker { await MPVolumeView.setVolume(1) } do { print("Playing sound \(intent.sound.title)") - try await player.playOnQueue() + try await newPlayer.playOnQueue() print("Sound \(intent.sound.title) stopped") } catch { print("Playing Sound fauled error:", error.localizedDescription) From df92b026b8965c080a7374ec621610d1673a98b0 Mon Sep 17 00:00:00 2001 From: Mariela Date: Wed, 19 Feb 2025 14:27:39 +0100 Subject: [PATCH 2/6] Playing more than one sound, stopping last one --- App/IntentRunner.swift | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/App/IntentRunner.swift b/App/IntentRunner.swift index f96bb52..e860c98 100644 --- a/App/IntentRunner.swift +++ b/App/IntentRunner.swift @@ -11,19 +11,20 @@ import UIKit import MediaPlayer enum IntentRunner { - private static var player: AudioPlayer? + private static var currentPlayer: AudioPlayer? + private static var currentSoundTitle: String? static func perform(intent: SoundIntent) async throws -> some IntentResult { - if let currentPlayer = player, currentPlayer.isPlaying { + if let player = currentPlayer, player.isPlaying, currentSoundTitle == intent.sound.title { print("Stopping sound \(intent.sound.title)") - currentPlayer.stop() - player = nil + player.stop() + currentPlayer = nil + currentSoundTitle = nil return .result() } print("Start playing \(intent.sound.title)") let newPlayer = try! AudioPlayer(url: intent.sound.file.fileURL!) - player = newPlayer print("Created sound for \(intent.sound.title)") @@ -31,12 +32,22 @@ enum IntentRunner { await MPVolumeView.setVolume(1) } + currentPlayer = newPlayer + currentSoundTitle = intent.sound.title + do { print("Playing sound \(intent.sound.title)") try await newPlayer.playOnQueue() print("Sound \(intent.sound.title) stopped") + + if currentSoundTitle == intent.sound.title { + currentPlayer = nil + currentSoundTitle = nil + } } catch { - print("Playing Sound fauled error:", error.localizedDescription) + print("Playing Sound failed error:", error.localizedDescription) + currentPlayer = nil + currentSoundTitle = nil } return .result() } From b2ac6e75002618e272057e222038b23f2fa18f74 Mon Sep 17 00:00:00 2001 From: Mariela Date: Wed, 19 Feb 2025 14:44:03 +0100 Subject: [PATCH 3/6] Play multiple sounds and stops when tapped again --- App/IntentRunner.swift | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/App/IntentRunner.swift b/App/IntentRunner.swift index e860c98..606a2af 100644 --- a/App/IntentRunner.swift +++ b/App/IntentRunner.swift @@ -11,15 +11,15 @@ import UIKit import MediaPlayer enum IntentRunner { - private static var currentPlayer: AudioPlayer? - private static var currentSoundTitle: String? + private static var activePlayer: [String: AudioPlayer] = [:] static func perform(intent: SoundIntent) async throws -> some IntentResult { - if let player = currentPlayer, player.isPlaying, currentSoundTitle == intent.sound.title { + let soundTitle = intent.sound.title + + if let player = activePlayer[soundTitle], player.isPlaying { print("Stopping sound \(intent.sound.title)") player.stop() - currentPlayer = nil - currentSoundTitle = nil + activePlayer[soundTitle] = nil return .result() } @@ -32,22 +32,17 @@ enum IntentRunner { await MPVolumeView.setVolume(1) } - currentPlayer = newPlayer - currentSoundTitle = intent.sound.title + activePlayer[soundTitle] = newPlayer do { print("Playing sound \(intent.sound.title)") try await newPlayer.playOnQueue() print("Sound \(intent.sound.title) stopped") - if currentSoundTitle == intent.sound.title { - currentPlayer = nil - currentSoundTitle = nil - } + activePlayer[intent.sound.title] = nil } catch { print("Playing Sound failed error:", error.localizedDescription) - currentPlayer = nil - currentSoundTitle = nil + activePlayer[intent.sound.title] = nil } return .result() } From 39e80d721a69a638b9b3903046b58b30e0909c15 Mon Sep 17 00:00:00 2001 From: Mariela Date: Wed, 19 Feb 2025 15:04:03 +0100 Subject: [PATCH 4/6] Use sound id instead of title --- App/IntentRunner.swift | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/App/IntentRunner.swift b/App/IntentRunner.swift index 606a2af..646d036 100644 --- a/App/IntentRunner.swift +++ b/App/IntentRunner.swift @@ -11,20 +11,23 @@ import UIKit import MediaPlayer enum IntentRunner { - private static var activePlayer: [String: AudioPlayer] = [:] + private static var activePlayer: [UUID: AudioPlayer] = [:] static func perform(intent: SoundIntent) async throws -> some IntentResult { - let soundTitle = intent.sound.title + let soundID = intent.sound.id - if let player = activePlayer[soundTitle], player.isPlaying { + if let player = activePlayer[soundID], player.isPlaying { print("Stopping sound \(intent.sound.title)") player.stop() - activePlayer[soundTitle] = nil + activePlayer[soundID] = nil return .result() } + guard let fileURL = intent.sound.file.fileURL, let newPlayer = try? AudioPlayer(url: fileURL) else { + print("Failed to create player for \(intent.sound.title)") + return .result() + } print("Start playing \(intent.sound.title)") - let newPlayer = try! AudioPlayer(url: intent.sound.file.fileURL!) print("Created sound for \(intent.sound.title)") @@ -32,17 +35,17 @@ enum IntentRunner { await MPVolumeView.setVolume(1) } - activePlayer[soundTitle] = newPlayer + activePlayer[soundID] = newPlayer do { print("Playing sound \(intent.sound.title)") try await newPlayer.playOnQueue() print("Sound \(intent.sound.title) stopped") - activePlayer[intent.sound.title] = nil + activePlayer[intent.sound.id] = nil } catch { print("Playing Sound failed error:", error.localizedDescription) - activePlayer[intent.sound.title] = nil + activePlayer[intent.sound.id] = nil } return .result() } From 032f0c06a54cab46a178518a47e248fb7ef62199 Mon Sep 17 00:00:00 2001 From: Mariela Date: Tue, 25 Feb 2025 09:54:17 +0100 Subject: [PATCH 5/6] Add Widget error and defer activePlayer to nil --- App/IntentRunner.swift | 18 +++++++++++++----- App/Views/MainView.swift | 13 ++++++++++++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/App/IntentRunner.swift b/App/IntentRunner.swift index 646d036..e56525a 100644 --- a/App/IntentRunner.swift +++ b/App/IntentRunner.swift @@ -24,7 +24,12 @@ enum IntentRunner { } guard let fileURL = intent.sound.file.fileURL, let newPlayer = try? AudioPlayer(url: fileURL) else { - print("Failed to create player for \(intent.sound.title)") + let errorMessage = "There was a error in the Widget" + print(errorMessage) + DispatchQueue.main.async { + AudioErrorManager.errorManager.errorMessage = errorMessage + AudioErrorManager.errorManager.showWidgetError = true + } return .result() } print("Start playing \(intent.sound.title)") @@ -39,13 +44,16 @@ enum IntentRunner { do { print("Playing sound \(intent.sound.title)") + defer { activePlayer[soundID] = nil } try await newPlayer.playOnQueue() print("Sound \(intent.sound.title) stopped") - - activePlayer[intent.sound.id] = nil } catch { - print("Playing Sound failed error:", error.localizedDescription) - activePlayer[intent.sound.id] = nil + let errorMessage = "There was a error playing sound in the Widget" + print(errorMessage) + DispatchQueue.main.async { + AudioErrorManager.errorManager.errorMessage = errorMessage + AudioErrorManager.errorManager.showWidgetError = true + } } return .result() } diff --git a/App/Views/MainView.swift b/App/Views/MainView.swift index 65ee25a..a238b44 100644 --- a/App/Views/MainView.swift +++ b/App/Views/MainView.swift @@ -39,6 +39,8 @@ struct MainView: View { @ScaledMetric(relativeTo: .headline) var minimumWidth: CGFloat = 130 + @StateObject private var errorManager = AudioErrorManager.errorManager + var body: some View { NavigationSplitView(preferredCompactColumn: $preferredCompactColumn, sidebar: { ScrollView(.vertical) { @@ -144,7 +146,11 @@ struct MainView: View { GalleryBoard.animals.save() } } - + .alert("Error", isPresented: $errorManager.showWidgetError) { + Button("OK") { } + } message: { + Text(errorManager.errorMessage ?? "Unknown error") + } } } @@ -171,6 +177,11 @@ extension Array { } } +class AudioErrorManager: ObservableObject { + static let errorManager = AudioErrorManager() + @Published var errorMessage: String? + @Published var showWidgetError: Bool = false +} #Preview { MainView() From 3948880c1b2c86f6e823504085ff2279ccd26be4 Mon Sep 17 00:00:00 2001 From: Mariela Date: Tue, 25 Feb 2025 10:16:03 +0100 Subject: [PATCH 6/6] Add error message function --- App/IntentRunner.swift | 18 +++--------------- App/Views/MainView.swift | 7 +++++++ 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/App/IntentRunner.swift b/App/IntentRunner.swift index e56525a..09570d3 100644 --- a/App/IntentRunner.swift +++ b/App/IntentRunner.swift @@ -24,36 +24,24 @@ enum IntentRunner { } guard let fileURL = intent.sound.file.fileURL, let newPlayer = try? AudioPlayer(url: fileURL) else { - let errorMessage = "There was a error in the Widget" - print(errorMessage) - DispatchQueue.main.async { - AudioErrorManager.errorManager.errorMessage = errorMessage - AudioErrorManager.errorManager.showWidgetError = true - } + AudioErrorManager.errorManager.reportError("There was a error in the Widget") return .result() } - print("Start playing \(intent.sound.title)") + activePlayer[soundID] = newPlayer print("Created sound for \(intent.sound.title)") if intent.isFullBlast && newPlayer.isOnSpeaker { await MPVolumeView.setVolume(1) } - activePlayer[soundID] = newPlayer - do { print("Playing sound \(intent.sound.title)") defer { activePlayer[soundID] = nil } try await newPlayer.playOnQueue() print("Sound \(intent.sound.title) stopped") } catch { - let errorMessage = "There was a error playing sound in the Widget" - print(errorMessage) - DispatchQueue.main.async { - AudioErrorManager.errorManager.errorMessage = errorMessage - AudioErrorManager.errorManager.showWidgetError = true - } + AudioErrorManager.errorManager.reportError("There was a error playing sound in the Widget") } return .result() } diff --git a/App/Views/MainView.swift b/App/Views/MainView.swift index a238b44..5a8b5a3 100644 --- a/App/Views/MainView.swift +++ b/App/Views/MainView.swift @@ -181,6 +181,13 @@ class AudioErrorManager: ObservableObject { static let errorManager = AudioErrorManager() @Published var errorMessage: String? @Published var showWidgetError: Bool = false + + func reportError(_ message: String) { + DispatchQueue.main.async { + self.errorMessage = message + self.showWidgetError = true + } + } } #Preview {