diff --git a/LeCountdown.xcodeproj/project.pbxproj b/LeCountdown.xcodeproj/project.pbxproj index 2ef7def..c201cdf 100644 --- a/LeCountdown.xcodeproj/project.pbxproj +++ b/LeCountdown.xcodeproj/project.pbxproj @@ -77,6 +77,14 @@ C4BA2AE62995AC3F00CB4FBA /* Loop_ToneSD_Boavista.wav in Resources */ = {isa = PBXBuildFile; fileRef = C4BA2AE52995AC3E00CB4FBA /* Loop_ToneSD_Boavista.wav */; }; C4BA2AE82995ACC200CB4FBA /* Clave_Loop_LLL.wav in Resources */ = {isa = PBXBuildFile; fileRef = C4BA2AE72995ACC200CB4FBA /* Clave_Loop_LLL.wav */; }; C4BA2AEA2995AD1C00CB4FBA /* SEM_Synths_Loop4_Nothing_Like_You.wav in Resources */ = {isa = PBXBuildFile; fileRef = C4BA2AE92995AD1C00CB4FBA /* SEM_Synths_Loop4_Nothing_Like_You.wav */; }; + C4BA2AF02996A11900CB4FBA /* Stopwatch+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2AEC2996A11900CB4FBA /* Stopwatch+CoreDataProperties.swift */; }; + C4BA2AF12996A11900CB4FBA /* CustomSound+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2AED2996A11900CB4FBA /* CustomSound+CoreDataClass.swift */; }; + C4BA2AF22996A11900CB4FBA /* CustomSound+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2AEE2996A11900CB4FBA /* CustomSound+CoreDataProperties.swift */; }; + C4BA2AF32996A11900CB4FBA /* AbstractSoundTimer+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2AEF2996A11900CB4FBA /* AbstractSoundTimer+CoreDataProperties.swift */; }; + C4BA2AF62996A4EF00CB4FBA /* CustomSound+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2AEE2996A11900CB4FBA /* CustomSound+CoreDataProperties.swift */; }; + C4BA2AF72996A4EF00CB4FBA /* CustomSound+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2AED2996A11900CB4FBA /* CustomSound+CoreDataClass.swift */; }; + C4BA2AF82996A4F000CB4FBA /* CustomSound+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2AEE2996A11900CB4FBA /* CustomSound+CoreDataProperties.swift */; }; + C4BA2AF92996A4F000CB4FBA /* CustomSound+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2AED2996A11900CB4FBA /* CustomSound+CoreDataClass.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 */; }; @@ -251,6 +259,11 @@ C4BA2AE52995AC3E00CB4FBA /* Loop_ToneSD_Boavista.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = Loop_ToneSD_Boavista.wav; sourceTree = ""; }; C4BA2AE72995ACC200CB4FBA /* Clave_Loop_LLL.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = Clave_Loop_LLL.wav; sourceTree = ""; }; C4BA2AE92995AD1C00CB4FBA /* SEM_Synths_Loop4_Nothing_Like_You.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = SEM_Synths_Loop4_Nothing_Like_You.wav; sourceTree = ""; }; + C4BA2AEB2996A09600CB4FBA /* LeCountdown.0.5.1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = LeCountdown.0.5.1.xcdatamodel; sourceTree = ""; }; + C4BA2AEC2996A11900CB4FBA /* Stopwatch+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Stopwatch+CoreDataProperties.swift"; sourceTree = ""; }; + C4BA2AED2996A11900CB4FBA /* CustomSound+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CustomSound+CoreDataClass.swift"; sourceTree = ""; }; + C4BA2AEE2996A11900CB4FBA /* CustomSound+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CustomSound+CoreDataProperties.swift"; sourceTree = ""; }; + C4BA2AEF2996A11900CB4FBA /* AbstractSoundTimer+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AbstractSoundTimer+CoreDataProperties.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 = ""; }; @@ -518,7 +531,7 @@ isa = PBXGroup; children = ( C4F8B1A5298AC2FC005C86A5 /* AbstractSoundTimer+CoreDataClass.swift */, - C4F8B1A6298AC2FC005C86A5 /* AbstractSoundTimer+CoreDataProperties.swift */, + C4BA2AEF2996A11900CB4FBA /* AbstractSoundTimer+CoreDataProperties.swift */, C4F8B176298AC234005C86A5 /* AbstractTimer+CoreDataClass.swift */, C4F8B177298AC234005C86A5 /* AbstractTimer+CoreDataProperties.swift */, C4F8B178298AC234005C86A5 /* Activity+CoreDataClass.swift */, @@ -527,9 +540,13 @@ C4F8B1AA298AC3A0005C86A5 /* Alarm+CoreDataProperties.swift */, C4F8B16C298AC234005C86A5 /* Countdown+CoreDataClass.swift */, C4F8B1A9298AC3A0005C86A5 /* Countdown+CoreDataProperties.swift */, + C4BA2AED2996A11900CB4FBA /* CustomSound+CoreDataClass.swift */, + C4BA2AEE2996A11900CB4FBA /* CustomSound+CoreDataProperties.swift */, C4F8B16E298AC234005C86A5 /* Record+CoreDataClass.swift */, C4F8B16F298AC234005C86A5 /* Record+CoreDataProperties.swift */, C4F8B174298AC234005C86A5 /* Stopwatch+CoreDataClass.swift */, + C4BA2AEC2996A11900CB4FBA /* Stopwatch+CoreDataProperties.swift */, + C4F8B1A6298AC2FC005C86A5 /* AbstractSoundTimer+CoreDataProperties.swift */, C4F8B175298AC234005C86A5 /* Stopwatch+CoreDataProperties.swift */, ); path = Generation; @@ -801,7 +818,9 @@ C4F8B1B8298AC81D005C86A5 /* CountdownDialView.swift in Sources */, C445FA922987CC8A0054D761 /* Sound.swift in Sources */, C4F8B1D0298BF2E2005C86A5 /* DialView.swift in Sources */, + C4BA2AF32996A11900CB4FBA /* AbstractSoundTimer+CoreDataProperties.swift in Sources */, C4742B59298411E800D5D950 /* CountdownFormView.swift in Sources */, + C4BA2AF12996A11900CB4FBA /* CustomSound+CoreDataClass.swift in Sources */, C4060DC2297AE73B003FAB80 /* ContentView.swift in Sources */, C438C7C12980228B00BF3EF9 /* CountdownScheduler.swift in Sources */, C498E5A3298D720600E90DE0 /* TestView.swift in Sources */, @@ -814,7 +833,9 @@ C4F8B1532987FE6F005C86A5 /* LaunchWidgetLiveActivity.swift in Sources */, C4F8B182298AC234005C86A5 /* Stopwatch+CoreDataClass.swift in Sources */, C4BA2ADB299549BC00CB4FBA /* TimerModel.swift in Sources */, + C4BA2AF02996A11900CB4FBA /* Stopwatch+CoreDataProperties.swift in Sources */, C4F8B16B298AA240005C86A5 /* NewStopwatchView.swift in Sources */, + C4BA2AF22996A11900CB4FBA /* CustomSound+CoreDataProperties.swift in Sources */, C4060DF5297AE9A7003FAB80 /* TimeInterval+Extensions.swift in Sources */, C4F8B166298A9ABB005C86A5 /* SoundImageFormView.swift in Sources */, C4F8B17D298AC234005C86A5 /* Record+CoreDataProperties.swift in Sources */, @@ -866,6 +887,7 @@ C4F8B18B298AC288005C86A5 /* Record+CoreDataClass.swift in Sources */, C4F8B195298AC288005C86A5 /* Activity+CoreDataClass.swift in Sources */, C4F8B193298AC288005C86A5 /* Countdown+CoreDataClass.swift in Sources */, + C4BA2AF72996A4EF00CB4FBA /* CustomSound+CoreDataClass.swift in Sources */, C4F8B1AD298AC451005C86A5 /* AbstractSoundTimer+CoreDataClass.swift in Sources */, C445FA87298448730054D761 /* CoolPic.swift in Sources */, C438C8172982BE9C00BF3EF9 /* Model+Extensions.swift in Sources */, @@ -882,6 +904,7 @@ C4F8B18C298AC288005C86A5 /* Alarm+CoreDataClass.swift in Sources */, C438C8192982BFDB00BF3EF9 /* NSManagedContext+Extensions.swift in Sources */, C438C7DA2981216200BF3EF9 /* LaunchWidget.swift in Sources */, + C4BA2AF62996A4EF00CB4FBA /* CustomSound+CoreDataProperties.swift in Sources */, C4F8B192298AC288005C86A5 /* Activity+CoreDataProperties.swift in Sources */, C4F8B18E298AC288005C86A5 /* AbstractTimer+CoreDataProperties.swift in Sources */, C4F8B1AE298AC451005C86A5 /* Alarm+CoreDataProperties.swift in Sources */, @@ -897,6 +920,7 @@ C4F8B1C6298ACC1F005C86A5 /* SoundPlayer.swift in Sources */, C4F8B1A2298AC288005C86A5 /* Record+CoreDataProperties.swift in Sources */, C4F8B1B2298AC451005C86A5 /* Alarm+CoreDataProperties.swift in Sources */, + C4BA2AF92996A4F000CB4FBA /* CustomSound+CoreDataClass.swift in Sources */, C4F8B1A1298AC288005C86A5 /* Countdown+CoreDataClass.swift in Sources */, C438C7F529812BB200BF3EF9 /* IntentHandler.swift in Sources */, C4F8B19C298AC288005C86A5 /* AbstractTimer+CoreDataProperties.swift in Sources */, @@ -912,6 +936,7 @@ C4F8B1A0298AC288005C86A5 /* Activity+CoreDataProperties.swift in Sources */, C438C81A2982BFF100BF3EF9 /* NSManagedContext+Extensions.swift in Sources */, C4F8B19D298AC288005C86A5 /* AbstractTimer+CoreDataClass.swift in Sources */, + C4BA2AF82996A4F000CB4FBA /* CustomSound+CoreDataProperties.swift in Sources */, C4F8B19E298AC288005C86A5 /* Stopwatch+CoreDataProperties.swift in Sources */, C4F8B199298AC288005C86A5 /* Record+CoreDataClass.swift in Sources */, C438C8012981327600BF3EF9 /* Persistence.swift in Sources */, @@ -1373,6 +1398,7 @@ C4060DCA297AE73D003FAB80 /* LeCountdown.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + C4BA2AEB2996A09600CB4FBA /* LeCountdown.0.5.1.xcdatamodel */, C4BA2AD72993F7D200CB4FBA /* LeCountdown.0.5.xcdatamodel */, C40FDB672993D5E80042A390 /* LeCountdown.0.4.xcdatamodel */, C4F8B160298A90E8005C86A5 /* LeCountdown.0.3.xcdatamodel */, @@ -1380,7 +1406,7 @@ C418A14F298428CB00C22230 /* LeCountdown.0.1.xcdatamodel */, C4060DCB297AE73D003FAB80 /* LeCountdown.xcdatamodel */, ); - currentVersion = C4BA2AD72993F7D200CB4FBA /* LeCountdown.0.5.xcdatamodel */; + currentVersion = C4BA2AEB2996A09600CB4FBA /* LeCountdown.0.5.1.xcdatamodel */; path = LeCountdown.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; diff --git a/LeCountdown/Model/Generation/AbstractSoundTimer+CoreDataProperties.swift b/LeCountdown/Model/Generation/AbstractSoundTimer+CoreDataProperties.swift index a113d0e..17605e3 100644 --- a/LeCountdown/Model/Generation/AbstractSoundTimer+CoreDataProperties.swift +++ b/LeCountdown/Model/Generation/AbstractSoundTimer+CoreDataProperties.swift @@ -2,7 +2,7 @@ // AbstractSoundTimer+CoreDataProperties.swift // LeCountdown // -// Created by Laurent Morvillier on 08/02/2023. +// Created by Laurent Morvillier on 10/02/2023. // // @@ -17,7 +17,6 @@ extension AbstractSoundTimer { } @NSManaged public var repeatCount: Int16 - @NSManaged public var playlistList: String? @NSManaged public var soundList: String? } diff --git a/LeCountdown/Model/Generation/CustomSound+CoreDataClass.swift b/LeCountdown/Model/Generation/CustomSound+CoreDataClass.swift new file mode 100644 index 0000000..b4a0a51 --- /dev/null +++ b/LeCountdown/Model/Generation/CustomSound+CoreDataClass.swift @@ -0,0 +1,15 @@ +// +// CustomSound+CoreDataClass.swift +// LeCountdown +// +// Created by Laurent Morvillier on 10/02/2023. +// +// + +import Foundation +import CoreData + +@objc(CustomSound) +public class CustomSound: NSManagedObject { + +} diff --git a/LeCountdown/Model/Generation/CustomSound+CoreDataProperties.swift b/LeCountdown/Model/Generation/CustomSound+CoreDataProperties.swift new file mode 100644 index 0000000..557f587 --- /dev/null +++ b/LeCountdown/Model/Generation/CustomSound+CoreDataProperties.swift @@ -0,0 +1,26 @@ +// +// CustomSound+CoreDataProperties.swift +// LeCountdown +// +// Created by Laurent Morvillier on 10/02/2023. +// +// + +import Foundation +import CoreData + + +extension CustomSound { + + @nonobjc public class func fetchRequest() -> NSFetchRequest { + return NSFetchRequest(entityName: "CustomSound") + } + + @NSManaged public var text: String? + @NSManaged public var file: String? + +} + +extension CustomSound : Identifiable { + +} diff --git a/LeCountdown/Model/Generation/Stopwatch+CoreDataProperties.swift b/LeCountdown/Model/Generation/Stopwatch+CoreDataProperties.swift index 8af9767..06dbc3d 100644 --- a/LeCountdown/Model/Generation/Stopwatch+CoreDataProperties.swift +++ b/LeCountdown/Model/Generation/Stopwatch+CoreDataProperties.swift @@ -2,7 +2,7 @@ // Stopwatch+CoreDataProperties.swift // LeCountdown // -// Created by Laurent Morvillier on 01/02/2023. +// Created by Laurent Morvillier on 10/02/2023. // // @@ -16,8 +16,8 @@ extension Stopwatch { return NSFetchRequest(entityName: "Stopwatch") } - @NSManaged public var start: Date? @NSManaged public var end: Date? @NSManaged public var sound: Int16 + @NSManaged public var start: Date? } diff --git a/LeCountdown/Model/LeCountdown.xcdatamodeld/.xccurrentversion b/LeCountdown/Model/LeCountdown.xcdatamodeld/.xccurrentversion index 154daa0..6dd84f4 100644 --- a/LeCountdown/Model/LeCountdown.xcdatamodeld/.xccurrentversion +++ b/LeCountdown/Model/LeCountdown.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - LeCountdown.0.5.xcdatamodel + LeCountdown.0.5.1.xcdatamodel diff --git a/LeCountdown/Model/LeCountdown.xcdatamodeld/LeCountdown.0.5.1.xcdatamodel/contents b/LeCountdown/Model/LeCountdown.xcdatamodeld/LeCountdown.0.5.1.xcdatamodel/contents new file mode 100644 index 0000000..0dc4ab8 --- /dev/null +++ b/LeCountdown/Model/LeCountdown.xcdatamodeld/LeCountdown.0.5.1.xcdatamodel/contents @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LeCountdown/Model/Model+Extensions.swift b/LeCountdown/Model/Model+Extensions.swift index d832d39..73cd652 100644 --- a/LeCountdown/Model/Model+Extensions.swift +++ b/LeCountdown/Model/Model+Extensions.swift @@ -145,6 +145,15 @@ extension Activity { } +extension CustomSound : Localized { + + var localizedString: String { + return self.text ?? "" + } + +} + + // MARK: - Storage convenience fileprivate let separator = "|" diff --git a/LeCountdown/Sound/Sound.swift b/LeCountdown/Sound/Sound.swift index 875ecc0..3f63300 100644 --- a/LeCountdown/Sound/Sound.swift +++ b/LeCountdown/Sound/Sound.swift @@ -32,21 +32,15 @@ enum Playlist: Int, CaseIterable, Identifiable, Localized { var id: Int { return self.rawValue } - case nature = 1 + case custom + case nature case fun case stephanBodzin -// var sounds: [Sound] { -// switch self { -// case .nature: -// return Sound.allCases -// case .fun: -// return Sound.allCases -// case .stephanBodzin: -// return Sound.allCases -// } -// } -// + static var selectable: [Playlist] { + return Playlist.allCases.filter { $0 != .custom } + } + var localizedString: String { switch self { case .nature: @@ -55,8 +49,11 @@ enum Playlist: Int, CaseIterable, Identifiable, Localized { return NSLocalizedString("Fun", comment: "") case .stephanBodzin: return "Stephan Bodzin" + case .custom: + return NSLocalizedString("Custom", comment: "") } } + } // Sound id are stored thus case order should not be changed diff --git a/LeCountdown/Utils/TextToSpeechRecorder.swift b/LeCountdown/Utils/TextToSpeechRecorder.swift index 7738071..15f4b23 100644 --- a/LeCountdown/Utils/TextToSpeechRecorder.swift +++ b/LeCountdown/Utils/TextToSpeechRecorder.swift @@ -18,8 +18,11 @@ class TextToSpeechRecorder { static func record(speech: String, handler: @escaping (Result) -> Void) { let synthesizer = AVSpeechSynthesizer() let utterance = AVSpeechUtterance(string: speech) + utterance.voice = AVSpeechSynthesisVoice(language: "fr-FR") + + synthesizer.speak(utterance) + return - utterance.voice = AVSpeechSynthesisVoice() var output: AVAudioFile? synthesizer.write(utterance) { buffer in diff --git a/LeCountdown/Views/Components/SoundSelectionView.swift b/LeCountdown/Views/Components/SoundSelectionView.swift index 3093ac1..3cc35f3 100644 --- a/LeCountdown/Views/Components/SoundSelectionView.swift +++ b/LeCountdown/Views/Components/SoundSelectionView.swift @@ -10,18 +10,76 @@ 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 { - ForEach(Playlist.allCases) { playlist in + +// 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") - + } + .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 {