I'm envisioning a solution that looks much like .changeEffect(.haptic(.success), value: someStateChanged), but instead of .haptic it would be .changeEffect(.sound(.plinkSound), value: someStateChanged).
I'm also including the complete solution if it can be of any help, or provide any more context, please let me know if there's any more information that would be helpful.
public enum SoundEffect {
case dataAsset(NSDataAsset)
case file(filename: String, `extension`: String)
}
public final class Sounds {
public enum Source: String {
case none
case headphones
case speakers
}
private var player: AVAudioPlayer?
public init() {}
public func playSound(effect: SoundEffect, source: Source) {
let shouldPlaySound: Bool
#if targetEnvironment(simulator)
shouldPlaySound = true
#else
switch source {
case .none:
shouldPlaySound = false
case .headphones:
shouldPlaySound = AVAudioSession.sharedInstance().currentRoute.outputs.map(\.portType).contains(where: { $0 == .headphones || $0 == .bluetoothA2DP })
case .speakers:
shouldPlaySound = true
}
#endif
if shouldPlaySound {
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers])
try AVAudioSession.sharedInstance().setActive(true)
switch effect {
case .dataAsset(let dataAsset):
self.player = try AVAudioPlayer(data: dataAsset.data)
case .file(let filename, let fileExtension):
guard let url = Bundle.module.url(forResource: filename, withExtension: fileExtension) else { return }
self.player = try AVAudioPlayer(contentsOf: url)
}
self.player?.play()
} catch let error {
print(error.localizedDescription)
}
}
}
}
private enum SoundEnvironmentKey: EnvironmentKey {
static let defaultValue = Sounds()
}
public extension EnvironmentValues {
var sounds: Sounds {
get { self[SoundEnvironmentKey.self] }
set { self[SoundEnvironmentKey.self] = newValue }
}
}
I really love the way that you've included a
.haptic
ChangeEffect, and was wondering if it'd be possible to do the same for playing a sound.Right now I have my own homegrown that I expose through the environment like so
And it's invoked by calling the
playSound
method like this.I'm envisioning a solution that looks much like
.changeEffect(.haptic(.success), value: someStateChanged)
, but instead of.haptic
it would be.changeEffect(.sound(.plinkSound), value: someStateChanged)
.I'm also including the complete solution if it can be of any help, or provide any more context, please let me know if there's any more information that would be helpful.