From ad0f2d479066804b3cc3874be30ea469078d6f70 Mon Sep 17 00:00:00 2001 From: Laurent Date: Fri, 17 Feb 2023 11:27:47 +0100 Subject: [PATCH] Adds duration next to sound --- LaunchIntents/IntentHandler.swift | 2 +- LeCountdown.xcodeproj/project.pbxproj | 24 ++-- LeCountdown/Conductor.swift | 9 +- LeCountdown/LeCountdownApp.swift | 2 + LeCountdown/Model/Fakes.swift | 35 ++++++ LeCountdown/Model/Model+Extensions.swift | 57 --------- .../Model/Model+SharedExtensions.swift | 39 ++++++ LeCountdown/Sound/Sound.swift | 27 +++-- LeCountdown/Sound/SoundPlayer.swift | 6 +- LeCountdown/Utils/Preferences.swift | 6 + .../Views/Components/SoundSelectionView.swift | 113 ++++++++---------- 11 files changed, 172 insertions(+), 148 deletions(-) create mode 100644 LeCountdown/Model/Fakes.swift create mode 100644 LeCountdown/Model/Model+SharedExtensions.swift diff --git a/LaunchIntents/IntentHandler.swift b/LaunchIntents/IntentHandler.swift index 9208bad..e70ac28 100644 --- a/LaunchIntents/IntentHandler.swift +++ b/LaunchIntents/IntentHandler.swift @@ -37,7 +37,7 @@ class IntentHandler: INExtension, SelectTimerIntentHandling { } break case let stopwatch as Stopwatch: - displayName = stopwatch.name ?? "no name" + displayName = stopwatch.activity?.name ?? "no name" default: displayName = "no name" } diff --git a/LeCountdown.xcodeproj/project.pbxproj b/LeCountdown.xcodeproj/project.pbxproj index 0629ba6..f47ca07 100644 --- a/LeCountdown.xcodeproj/project.pbxproj +++ b/LeCountdown.xcodeproj/project.pbxproj @@ -48,7 +48,6 @@ C438C81129829EAF00BF3EF9 /* PropertyWrappers.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C81029829EAF00BF3EF9 /* PropertyWrappers.swift */; }; C438C8152982BD9000BF3EF9 /* IntentDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C7FE2981300500BF3EF9 /* IntentDataProvider.swift */; }; C438C8162982BE1E00BF3EF9 /* LeCountdown.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = C4060DCA297AE73D003FAB80 /* LeCountdown.xcdatamodeld */; }; - C438C8172982BE9C00BF3EF9 /* Model+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C806298195E600BF3EF9 /* Model+Extensions.swift */; }; C438C8182982BFC100BF3EF9 /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4060DC8297AE73D003FAB80 /* Persistence.swift */; }; C438C8192982BFDB00BF3EF9 /* NSManagedContext+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C7C4298024E900BF3EF9 /* NSManagedContext+Extensions.swift */; }; C438C81A2982BFF100BF3EF9 /* NSManagedContext+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C7C4298024E900BF3EF9 /* NSManagedContext+Extensions.swift */; }; @@ -57,7 +56,6 @@ C445FA882984487F0054D761 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C4060DC3297AE73D003FAB80 /* Assets.xcassets */; }; C445FA8F2987B83B0054D761 /* SoundPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C445FA8E2987B83B0054D761 /* SoundPlayer.swift */; }; C445FA922987CC8A0054D761 /* Sound.swift in Sources */ = {isa = PBXBuildFile; fileRef = C445FA912987CC8A0054D761 /* Sound.swift */; }; - C445FA932987CF280054D761 /* Sound.swift in Sources */ = {isa = PBXBuildFile; fileRef = C445FA912987CC8A0054D761 /* Sound.swift */; }; C445FA952987D01C0054D761 /* train_horn.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C445FA942987D01C0054D761 /* train_horn.mp3 */; }; C4742B5729840F6400D5D950 /* CoolPic.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4742B5629840F6400D5D950 /* CoolPic.swift */; }; C4742B59298411E800D5D950 /* CountdownFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4742B58298411E800D5D950 /* CountdownFormView.swift */; }; @@ -111,6 +109,12 @@ C4BA2B2D299E2DEE00CB4FBA /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B2C299E2DEE00CB4FBA /* Preferences.swift */; }; C4BA2B2F299E69A000CB4FBA /* View+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B2E299E69A000CB4FBA /* View+Extension.swift */; }; C4BA2B32299F75DE00CB4FBA /* DefaultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B30299F759700CB4FBA /* DefaultView.swift */; }; + C4BA2B36299F82FB00CB4FBA /* Fakes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B35299F82FB00CB4FBA /* Fakes.swift */; }; + C4BA2B37299F82FF00CB4FBA /* Fakes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B35299F82FB00CB4FBA /* Fakes.swift */; }; + C4BA2B38299F82FF00CB4FBA /* Fakes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B35299F82FB00CB4FBA /* Fakes.swift */; }; + C4BA2B3A299F838000CB4FBA /* Model+SharedExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B39299F838000CB4FBA /* Model+SharedExtensions.swift */; }; + C4BA2B3B299F838000CB4FBA /* Model+SharedExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B39299F838000CB4FBA /* Model+SharedExtensions.swift */; }; + C4BA2B3C299F838000CB4FBA /* Model+SharedExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B39299F838000CB4FBA /* Model+SharedExtensions.swift */; }; C4F8B1532987FE6F005C86A5 /* LaunchWidgetLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C7D72981216200BF3EF9 /* LaunchWidgetLiveActivity.swift */; }; C4F8B15729891271005C86A5 /* Conductor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8B15629891271005C86A5 /* Conductor.swift */; }; C4F8B15929891528005C86A5 /* forest_stream.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C4F8B15829891528005C86A5 /* forest_stream.mp3 */; }; @@ -157,8 +161,6 @@ C4F8B1B8298AC81D005C86A5 /* CountdownDialView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8B1B7298AC81D005C86A5 /* CountdownDialView.swift */; }; C4F8B1BD298AC8DE005C86A5 /* AlarmDialView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8B1BC298AC8DE005C86A5 /* AlarmDialView.swift */; }; C4F8B1BF298ACA0B005C86A5 /* StopwatchDialView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8B1BE298ACA0B005C86A5 /* StopwatchDialView.swift */; }; - C4F8B1C0298ACA61005C86A5 /* Model+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C806298195E600BF3EF9 /* Model+Extensions.swift */; }; - C4F8B1C3298ACBDB005C86A5 /* Sound.swift in Sources */ = {isa = PBXBuildFile; fileRef = C445FA912987CC8A0054D761 /* Sound.swift */; }; C4F8B1C6298ACC1F005C86A5 /* SoundPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C445FA8E2987B83B0054D761 /* SoundPlayer.swift */; }; C4F8B1D0298BF2E2005C86A5 /* DialView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8B1CF298BF2E2005C86A5 /* DialView.swift */; }; C4F8B1D2298BF646005C86A5 /* PermissionAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8B1D1298BF646005C86A5 /* PermissionAlertView.swift */; }; @@ -295,6 +297,8 @@ C4BA2B2C299E2DEE00CB4FBA /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; }; C4BA2B2E299E69A000CB4FBA /* View+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extension.swift"; sourceTree = ""; }; C4BA2B30299F759700CB4FBA /* DefaultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultView.swift; sourceTree = ""; }; + C4BA2B35299F82FB00CB4FBA /* Fakes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fakes.swift; sourceTree = ""; }; + C4BA2B39299F838000CB4FBA /* Model+SharedExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Model+SharedExtensions.swift"; sourceTree = ""; }; C4F8B15629891271005C86A5 /* Conductor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Conductor.swift; sourceTree = ""; }; C4F8B15829891528005C86A5 /* forest_stream.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = forest_stream.mp3; sourceTree = ""; }; C4F8B15E298961A7005C86A5 /* ReorderableForEach.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReorderableForEach.swift; sourceTree = ""; }; @@ -489,8 +493,10 @@ C438C80C2982847300BF3EF9 /* CoreDataRequests.swift */, C498E5A0298D543900E90DE0 /* LiveTimer.swift */, C438C806298195E600BF3EF9 /* Model+Extensions.swift */, + C4BA2B39299F838000CB4FBA /* Model+SharedExtensions.swift */, C438C7C4298024E900BF3EF9 /* NSManagedContext+Extensions.swift */, C4060DC8297AE73D003FAB80 /* Persistence.swift */, + C4BA2B35299F82FB00CB4FBA /* Fakes.swift */, ); path = Model; sourceTree = ""; @@ -835,6 +841,7 @@ files = ( C4F8B1D2298BF646005C86A5 /* PermissionAlertView.swift in Sources */, C4060DC9297AE73D003FAB80 /* Persistence.swift in Sources */, + C4BA2B36299F82FB00CB4FBA /* Fakes.swift in Sources */, C498E5A1298D543900E90DE0 /* LiveTimer.swift in Sources */, C438C80F29828B8600BF3EF9 /* RecordsView.swift in Sources */, C4F8B187298AC234005C86A5 /* Activity+CoreDataProperties.swift in Sources */, @@ -858,6 +865,7 @@ C4BA2B11299BE61E00CB4FBA /* IntervalGroup+CoreDataClass.swift in Sources */, C4BA2AFD299A3A3700CB4FBA /* AppleMusicPlayer.swift in Sources */, C4BA2B12299BE61E00CB4FBA /* IntervalGroup+CoreDataProperties.swift in Sources */, + C4BA2B3A299F838000CB4FBA /* Model+SharedExtensions.swift in Sources */, C4BA2AF32996A11900CB4FBA /* AbstractSoundTimer+CoreDataProperties.swift in Sources */, C4742B59298411E800D5D950 /* CountdownFormView.swift in Sources */, C4BA2B25299D35C100CB4FBA /* HomeView.swift in Sources */, @@ -926,8 +934,8 @@ buildActionMask = 2147483647; files = ( C4BA2B15299BE6A000CB4FBA /* Interval+CoreDataProperties.swift in Sources */, - C445FA932987CF280054D761 /* Sound.swift in Sources */, C498E5A6299152C600E90DE0 /* GreenCheckmarkView.swift in Sources */, + C4BA2B3B299F838000CB4FBA /* Model+SharedExtensions.swift in Sources */, C438C7EB2981266F00BF3EF9 /* SingleTimerView.swift in Sources */, C438C7D62981216200BF3EF9 /* LaunchWidgetBundle.swift in Sources */, C4BA2B16299BE6A000CB4FBA /* IntervalGroup+CoreDataClass.swift in Sources */, @@ -939,13 +947,13 @@ C4BA2AF72996A4EF00CB4FBA /* CustomSound+CoreDataClass.swift in Sources */, C4F8B1AD298AC451005C86A5 /* AbstractSoundTimer+CoreDataClass.swift in Sources */, C445FA87298448730054D761 /* CoolPic.swift in Sources */, - C438C8172982BE9C00BF3EF9 /* Model+Extensions.swift in Sources */, C438C8162982BE1E00BF3EF9 /* LeCountdown.xcdatamodeld in Sources */, C4F8B194298AC288005C86A5 /* Record+CoreDataProperties.swift in Sources */, C438C8152982BD9000BF3EF9 /* IntentDataProvider.swift in Sources */, C438C7DF2981216300BF3EF9 /* LaunchWidget.intentdefinition in Sources */, C4F8B15B29892D40005C86A5 /* SoundPlayer.swift in Sources */, C438C7E82981255D00BF3EF9 /* TimeInterval+Extensions.swift in Sources */, + C4BA2B37299F82FF00CB4FBA /* Fakes.swift in Sources */, C4F8B18F298AC288005C86A5 /* AbstractTimer+CoreDataClass.swift in Sources */, C4BA2B19299BE6A000CB4FBA /* Countdown+CoreDataProperties.swift in Sources */, C438C7D82981216200BF3EF9 /* LaunchWidgetLiveActivity.swift in Sources */, @@ -973,13 +981,12 @@ C4F8B1B2298AC451005C86A5 /* Alarm+CoreDataProperties.swift in Sources */, C4BA2AF92996A4F000CB4FBA /* CustomSound+CoreDataClass.swift in Sources */, C4F8B1A1298AC288005C86A5 /* Countdown+CoreDataClass.swift in Sources */, + C4BA2B38299F82FF00CB4FBA /* Fakes.swift in Sources */, C438C7F529812BB200BF3EF9 /* IntentHandler.swift in Sources */, C4F8B19C298AC288005C86A5 /* AbstractTimer+CoreDataProperties.swift in Sources */, C4BA2B1C299BE6A100CB4FBA /* IntervalGroup+CoreDataClass.swift in Sources */, - C4F8B1C0298ACA61005C86A5 /* Model+Extensions.swift in Sources */, C4BA2B1F299BE6A100CB4FBA /* Countdown+CoreDataProperties.swift in Sources */, C4F8B1A3298AC288005C86A5 /* Activity+CoreDataClass.swift in Sources */, - C4F8B1C3298ACBDB005C86A5 /* Sound.swift in Sources */, C4F8B19A298AC288005C86A5 /* Alarm+CoreDataClass.swift in Sources */, C438C80529813FB400BF3EF9 /* TimeInterval+Extensions.swift in Sources */, C4BA2B1B299BE6A100CB4FBA /* Interval+CoreDataProperties.swift in Sources */, @@ -988,6 +995,7 @@ C4F8B1A0298AC288005C86A5 /* Activity+CoreDataProperties.swift in Sources */, C438C81A2982BFF100BF3EF9 /* NSManagedContext+Extensions.swift in Sources */, C4F8B19D298AC288005C86A5 /* AbstractTimer+CoreDataClass.swift in Sources */, + C4BA2B3C299F838000CB4FBA /* Model+SharedExtensions.swift in Sources */, C4BA2AF82996A4F000CB4FBA /* CustomSound+CoreDataProperties.swift in Sources */, C4F8B199298AC288005C86A5 /* Record+CoreDataClass.swift in Sources */, C438C8012981327600BF3EF9 /* Persistence.swift in Sources */, diff --git a/LeCountdown/Conductor.swift b/LeCountdown/Conductor.swift index 0d1ff7c..3d72b66 100644 --- a/LeCountdown/Conductor.swift +++ b/LeCountdown/Conductor.swift @@ -10,19 +10,14 @@ import ActivityKit import BackgroundTasks import SwiftUI -enum Key: String { - case countdowns - case stopwatches -} - class Conductor: ObservableObject { static let maestro: Conductor = Conductor() @Published var soundPlayer: SoundPlayer? = nil - @UserDefault(Key.countdowns.rawValue, defaultValue: [:]) static var savedCountdowns: [String : DateInterval] - @UserDefault(Key.stopwatches.rawValue, defaultValue: [:]) static var savedStopwatches: [String : Date] + @UserDefault(PreferenceKey.countdowns.rawValue, defaultValue: [:]) static var savedCountdowns: [String : DateInterval] + @UserDefault(PreferenceKey.stopwatches.rawValue, defaultValue: [:]) static var savedStopwatches: [String : Date] @Published private (set) var liveTimers: [LiveTimer] = [] diff --git a/LeCountdown/LeCountdownApp.swift b/LeCountdown/LeCountdownApp.swift index aa94556..d7d3d4d 100644 --- a/LeCountdown/LeCountdownApp.swift +++ b/LeCountdown/LeCountdownApp.swift @@ -67,6 +67,8 @@ struct LeCountdownApp: App { fileprivate func _onAppear() { + Sound.computeSoundDurationsIfNecessary() + // let voices = AVSpeechSynthesisVoice.speechVoices() // let grouped = Dictionary(grouping: voices, by: { $0.language }) // for language in grouped.keys { diff --git a/LeCountdown/Model/Fakes.swift b/LeCountdown/Model/Fakes.swift new file mode 100644 index 0000000..73c92bf --- /dev/null +++ b/LeCountdown/Model/Fakes.swift @@ -0,0 +1,35 @@ +// +// Fakes.swift +// LeCountdown +// +// Created by Laurent Morvillier on 17/02/2023. +// + +import Foundation +import CoreData + +extension Countdown { + + static func fake(context: NSManagedObjectContext) -> Countdown { + let cd = Countdown(context: context) + cd.duration = 4 * 60.0 + let activity = Activity(context: context) + activity.name = "Tea" + cd.activity = activity + return cd + } + +} + +extension Alarm { + + static func fake(context: NSManagedObjectContext) -> Alarm { + let alarm = Alarm(context: context) + alarm.fireDate = Date() + let activity = Activity(context: context) + activity.name = "Wakeup" + alarm.activity = activity + return alarm + } + +} diff --git a/LeCountdown/Model/Model+Extensions.swift b/LeCountdown/Model/Model+Extensions.swift index 73cd652..64555e5 100644 --- a/LeCountdown/Model/Model+Extensions.swift +++ b/LeCountdown/Model/Model+Extensions.swift @@ -13,37 +13,6 @@ enum TimerError: Error { case notificationAuthorizationMissing } -extension AbstractTimer { - - var displayName: String { - return self.name ?? self.coolpic.emoji - } - - var name: String? { - return self.activity?.name - } - - var url: URL { - if let url = URL(string: self.stringId) { - return url - } else { - fatalError("Can't produce url with \(self.stringId)") - } - } - - var coolpic: CoolPic { - if let image, let coolpic = CoolPic(rawValue: image) { - return coolpic - } - return CoolPic.allCases[0] - } - - var imageName: String { - return self.coolpic.rawValue - } - -} - extension AbstractSoundTimer { var sounds: Set { @@ -80,32 +49,6 @@ extension AbstractSoundTimer { } -extension Countdown { - - static func fake(context: NSManagedObjectContext) -> Countdown { - let cd = Countdown(context: context) - cd.duration = 4 * 60.0 - let activity = Activity(context: context) - activity.name = "Tea" - cd.activity = activity - return cd - } - -} - -extension Alarm { - - static func fake(context: NSManagedObjectContext) -> Alarm { - let alarm = Alarm(context: context) - alarm.fireDate = Date() - let activity = Activity(context: context) - activity.name = "Wakeup" - alarm.activity = activity - return alarm - } - -} - extension Stopwatch { var coolSound: Sound? { diff --git a/LeCountdown/Model/Model+SharedExtensions.swift b/LeCountdown/Model/Model+SharedExtensions.swift new file mode 100644 index 0000000..7fcb5a4 --- /dev/null +++ b/LeCountdown/Model/Model+SharedExtensions.swift @@ -0,0 +1,39 @@ +// +// Model+SharedExtensions.swift +// LeCountdown +// +// Created by Laurent Morvillier on 17/02/2023. +// + +import Foundation + +extension AbstractTimer { + + var displayName: String { + return self.name ?? self.coolpic.emoji + } + + var name: String? { + return self.activity?.name + } + + var url: URL { + if let url = URL(string: self.stringId) { + return url + } else { + fatalError("Can't produce url with \(self.stringId)") + } + } + + var coolpic: CoolPic { + if let image, let coolpic = CoolPic(rawValue: image) { + return coolpic + } + return CoolPic.allCases[0] + } + + var imageName: String { + return self.coolpic.rawValue + } + +} diff --git a/LeCountdown/Sound/Sound.swift b/LeCountdown/Sound/Sound.swift index 3f63300..adfa63d 100644 --- a/LeCountdown/Sound/Sound.swift +++ b/LeCountdown/Sound/Sound.swift @@ -109,13 +109,6 @@ enum Sound: Int, CaseIterable, Identifiable, Localized { } } -// var duration: TimeInterval { -// switch self { -// case .trainhorn: return 7.8 -// case .forestStream: return 300.1 -// } -// } - var url: URL? { let components = self.soundName.components(separatedBy: ".") @@ -144,4 +137,24 @@ enum Sound: Int, CaseIterable, Identifiable, Localized { return CMTimeGetSeconds(duration) } + static func computeSoundDurationsIfNecessary() { + Task { + for sound in Sound.allCases { + if Preferences.soundDurations[sound.rawValue] == nil { + if let duration = try? await sound.duration() { + Preferences.soundDurations[sound.rawValue] = duration + } + } + } + } + } + + var formattedDuration: String { + if let duration = Preferences.soundDurations[self.rawValue] { + return duration.minuteSecond + } else { + return "" + } + } + } diff --git a/LeCountdown/Sound/SoundPlayer.swift b/LeCountdown/Sound/SoundPlayer.swift index 1751c61..3948729 100644 --- a/LeCountdown/Sound/SoundPlayer.swift +++ b/LeCountdown/Sound/SoundPlayer.swift @@ -42,9 +42,9 @@ enum SoundPlayerError : Error { throw SoundPlayerError.missingResourceError(file: soundFile) } - let audioSession: AVAudioSession = AVAudioSession.sharedInstance() - try audioSession.setCategory(.playback) - try audioSession.setActive(true) +// let audioSession: AVAudioSession = AVAudioSession.sharedInstance() +// try audioSession.setCategory(.playback) +// try audioSession.setActive(true) _player = try AVAudioPlayer(contentsOf: url) _player?.prepareToPlay() diff --git a/LeCountdown/Utils/Preferences.swift b/LeCountdown/Utils/Preferences.swift index a71da9b..a9d3fa1 100644 --- a/LeCountdown/Utils/Preferences.swift +++ b/LeCountdown/Utils/Preferences.swift @@ -8,11 +8,17 @@ import Foundation enum PreferenceKey: String { + case countdowns + case stopwatches case showSilentModeAlert + case soundDurations } class Preferences { + @UserDefault(PreferenceKey.countdowns.rawValue, defaultValue: [:]) static var savedCountdowns: [String : DateInterval] + @UserDefault(PreferenceKey.soundDurations.rawValue, defaultValue: [:]) static var soundDurations: [Int : TimeInterval] + static var hideSilentModeAlerts: Bool { return UserDefaults.standard.bool(forKey: PreferenceKey.showSilentModeAlert.rawValue) } diff --git a/LeCountdown/Views/Components/SoundSelectionView.swift b/LeCountdown/Views/Components/SoundSelectionView.swift index a297403..d5eb106 100644 --- a/LeCountdown/Views/Components/SoundSelectionView.swift +++ b/LeCountdown/Views/Components/SoundSelectionView.swift @@ -10,76 +10,19 @@ import SwiftUI struct PlaylistsView: View { @EnvironmentObject var model: TimerModel -// @Environment(\.managedObjectContext) private var viewContext - -// @FetchRequest( -// sortDescriptors: [NSSortDescriptor(keyPath: \CustomSound.text, ascending: true)], -// animation: .default) -// private var customSounds: FetchedResults -// -// @State private var showNewSound: Bool = false -// @State private var name = "" var body: some View { Form { -// if customSounds.count > 0 { -// -// Section(Playlist.custom.localizedString) { -// -// ForEach(self.customSounds) { customSound in -// ToggleRow(item: customSound, selected: .constant(false)) { selected in -// // todo -// } -// } -// } -// -// } - ForEach(Playlist.selectable) { playlist in PlaylistSectionView(playlist: playlist) .environmentObject(self.model) } } .navigationTitle("Sounds") - -// .alert("", isPresented: $showNewSound) { -// TextField("Enter your name", text: $name) -// Button("OK", action: _submit) -// } message: { -// Text("Xcode will print whatever you type.") -// } -// .toolbar { -// ToolbarItem(placement: .navigationBarTrailing) { -// Button { -// self.showNewSound = true -// } label: { -// Image(systemName: "plus") -// } -// } -// } } - -// fileprivate func _submit() { -// print("You entered \(name)") -// TextToSpeechRecorder.record(speech: self.name) { result in -// switch result { -// case .success(let file): -// -// let cs = CustomSound(context: viewContext) -// cs.text = self.name -// cs.file = file.fileName -// -// try! viewContext.save() // TODO -// -// case .failure(let failure): -// print("error = \(failure)") -// break -// } -// } -// } - + } struct PlaylistSectionView: View { @@ -92,11 +35,22 @@ struct PlaylistSectionView: View { Section { let sounds = SoundCatalog.main.sounds(for: self.playlist) + ForEach(sounds) { sound in - ImageToggleRow(item: sound, selected: self.model.binding(sound: sound)) { selected in - self.model.selectSound(sound, selected: selected) - }.onTapGesture { - self._playSound(sound) + HStack { + HStack { + Image(systemName: "play.circle") + .foregroundColor(Color.accentColor) + Text(sound.localizedString) + }.onTapGesture { + self._playSound(sound) + } + Spacer() + RightAlignToggleRow(item: sound, selected: self.model.binding(sound: sound), keyPath: \.formattedDuration) { selected in + self.model.selectSound(sound, selected: selected) + }.frame(width: 120.0) + .foregroundColor(.gray) + .font(.caption) } } } header: { @@ -119,23 +73,52 @@ struct ToggleRow: View { var handleSelection: (Bool) -> () var body: some View { - Toggle(item.localizedString, isOn: $selected) + Toggle(self.item.localizedString, isOn: $selected) .onChange(of: self.selected, perform: handleSelection) } + } -struct ImageToggleRow: View { +struct RightAlignToggleRow: View { var item: T @Binding var selected: Bool + var keyPath: KeyPath var handleSelection: (Bool) -> () var body: some View { + Toggle(isOn: $selected) { + HStack { + Spacer() + Text(self.item[keyPath: keyPath]) + } + }.onChange(of: self.selected, perform: handleSelection) + +// if let keyPath { +// +// +// Toggle(item[keyPath: keyPath], isOn: $selected) +// .onChange(of: self.selected, perform: handleSelection) +// } else { +// Toggle(item.localizedString, isOn: $selected) +// .onChange(of: self.selected, perform: handleSelection) +// } + } +} + +struct ImageToggleRow: View { + var item: T + @Binding var selected: Bool + var handleSelection: (Bool) -> () + + var body: some View { HStack { - Image(systemName: "play.circle").foregroundColor(Color.accentColor) + Image(systemName: "play.circle") + .foregroundColor(Color.accentColor) ToggleRow(item: item, selected: $selected, handleSelection: handleSelection) } } + } //struct PlaylistRow: View {