Adds sounds configuration to steps

splits
Laurent 2 years ago
parent 676fb0e97b
commit a5deb81cbc
  1. 8
      LeCountdown.xcodeproj/project.pbxproj
  2. 4
      LeCountdown/AppDelegate.swift
  3. 6
      LeCountdown/Conductor.swift
  4. 2
      LeCountdown/Model/Generation/Step+CoreDataProperties.swift
  5. 5
      LeCountdown/Model/Model+Extensions.swift
  6. 2
      LeCountdown/Sound/Sound.swift
  7. 3
      LeCountdown/Views/Countdown/CountdownFormView.swift
  8. 2
      LeCountdown/Views/Countdown/NewCountdownView.swift
  9. 52
      LeCountdown/Views/Countdown/StepFormView.swift
  10. 17
      LeCountdown/Views/Reusable/SoundFormView.swift
  11. 9
      LeCountdown/Views/TimerModel.swift

@ -142,7 +142,7 @@
C47C933629F01B6600C780E2 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4556F6E29E40BED00DEB40B /* FileUtils.swift */; }; C47C933629F01B6600C780E2 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4556F6E29E40BED00DEB40B /* FileUtils.swift */; };
C47C933729F01B7A00C780E2 /* Codable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4556F7029E40DCF00DEB40B /* Codable+Extensions.swift */; }; C47C933729F01B7A00C780E2 /* Codable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4556F7029E40DCF00DEB40B /* Codable+Extensions.swift */; };
C47C933929F13BD100C780E2 /* AppleMusicPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47C933829F13BD100C780E2 /* AppleMusicPickerView.swift */; }; C47C933929F13BD100C780E2 /* AppleMusicPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47C933829F13BD100C780E2 /* AppleMusicPickerView.swift */; };
C48920672B0E57C900F6F4D8 /* RangeFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48920662B0E57C900F6F4D8 /* RangeFormView.swift */; }; C48920672B0E57C900F6F4D8 /* StepFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48920662B0E57C900F6F4D8 /* StepFormView.swift */; };
C48940DE2AC307860086F4FA /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = C48940DD2AC307860086F4FA /* GoogleService-Info.plist */; }; C48940DE2AC307860086F4FA /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = C48940DD2AC307860086F4FA /* GoogleService-Info.plist */; };
C48940DF2AC307860086F4FA /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = C48940DD2AC307860086F4FA /* GoogleService-Info.plist */; }; C48940DF2AC307860086F4FA /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = C48940DD2AC307860086F4FA /* GoogleService-Info.plist */; };
C48940E02AC307860086F4FA /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = C48940DD2AC307860086F4FA /* GoogleService-Info.plist */; }; C48940E02AC307860086F4FA /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = C48940DD2AC307860086F4FA /* GoogleService-Info.plist */; };
@ -443,7 +443,7 @@
C47A9AF22AD1B32C00618A50 /* URLs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLs.swift; sourceTree = "<group>"; }; C47A9AF22AD1B32C00618A50 /* URLs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLs.swift; sourceTree = "<group>"; };
C47C933829F13BD100C780E2 /* AppleMusicPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleMusicPickerView.swift; sourceTree = "<group>"; }; C47C933829F13BD100C780E2 /* AppleMusicPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleMusicPickerView.swift; sourceTree = "<group>"; };
C47C933C29F13DBD00C780E2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; }; C47C933C29F13DBD00C780E2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
C48920662B0E57C900F6F4D8 /* RangeFormView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RangeFormView.swift; sourceTree = "<group>"; }; C48920662B0E57C900F6F4D8 /* StepFormView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepFormView.swift; sourceTree = "<group>"; };
C48940DD2AC307860086F4FA /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; }; C48940DD2AC307860086F4FA /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
C498E59E298D4DEA00E90DE0 /* LiveTimerListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTimerListView.swift; sourceTree = "<group>"; }; C498E59E298D4DEA00E90DE0 /* LiveTimerListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTimerListView.swift; sourceTree = "<group>"; };
C498E5A0298D543900E90DE0 /* LiveTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTimer.swift; sourceTree = "<group>"; }; C498E5A0298D543900E90DE0 /* LiveTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTimer.swift; sourceTree = "<group>"; };
@ -946,7 +946,7 @@
C4742B58298411E800D5D950 /* CountdownFormView.swift */, C4742B58298411E800D5D950 /* CountdownFormView.swift */,
C4F8B1B7298AC81D005C86A5 /* CountdownDialView.swift */, C4F8B1B7298AC81D005C86A5 /* CountdownDialView.swift */,
C4060DF6297AFEF2003FAB80 /* NewCountdownView.swift */, C4060DF6297AFEF2003FAB80 /* NewCountdownView.swift */,
C48920662B0E57C900F6F4D8 /* RangeFormView.swift */, C48920662B0E57C900F6F4D8 /* StepFormView.swift */,
); );
path = Countdown; path = Countdown;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1288,7 +1288,7 @@
C4BA2B36299F82FB00CB4FBA /* Fakes.swift in Sources */, C4BA2B36299F82FB00CB4FBA /* Fakes.swift in Sources */,
C4556F7629E411A400DEB40B /* LogsView.swift in Sources */, C4556F7629E411A400DEB40B /* LogsView.swift in Sources */,
C498E5A1298D543900E90DE0 /* LiveTimer.swift in Sources */, C498E5A1298D543900E90DE0 /* LiveTimer.swift in Sources */,
C48920672B0E57C900F6F4D8 /* RangeFormView.swift in Sources */, C48920672B0E57C900F6F4D8 /* StepFormView.swift in Sources */,
C4BA2B6329A3C34600CB4FBA /* Stat.swift in Sources */, C4BA2B6329A3C34600CB4FBA /* Stat.swift in Sources */,
C4C8266C2B0E41D20036C666 /* Countdown+CoreDataProperties.swift in Sources */, C4C8266C2B0E41D20036C666 /* Countdown+CoreDataProperties.swift in Sources */,
C415D3E229C0C0C20037B215 /* MailView.swift in Sources */, C415D3E229C0C0C20037B215 /* MailView.swift in Sources */,

@ -91,10 +91,10 @@ extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async { func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async {
print("didReceive notification") Logger.log("didReceive notification")
FileLogger.log("userNotificationCenter didReceive > cancelling sound player") FileLogger.log("userNotificationCenter didReceive > cancelling sound player")
if let timerId = self._timerId(notificationId: response.notification.request.identifier) { if let timerId = self._timerId(notificationId: response.notification.request.identifier) {
Conductor.maestro.cancelSoundPlayer(id: timerId) Conductor.maestro.cancelSoundPlayers(id: timerId)
} }
} }

@ -246,7 +246,7 @@ class Conductor: ObservableObject {
self.currentCountdowns.removeValue(forKey: id) self.currentCountdowns.removeValue(forKey: id)
self.removeLiveTimer(id: id) self.removeLiveTimer(id: id)
self.cancelSoundPlayer(id: id) self.cancelSoundPlayers(id: id)
self._recordAndRemoveCountdown(countdownId: id, cancel: true) self._recordAndRemoveCountdown(countdownId: id, cancel: true)
// self.pausedCountdowns.removeValue(forKey: id) // self.pausedCountdowns.removeValue(forKey: id)
@ -295,7 +295,7 @@ class Conductor: ObservableObject {
// cancel stuff // cancel stuff
self.cancelCurrentNotifications(countdownId: id) self.cancelCurrentNotifications(countdownId: id)
self.cancelSoundPlayer(id: id) self.cancelSoundPlayers(id: id)
self._endLiveActivity(timerId: id) self._endLiveActivity(timerId: id)
} }
@ -563,7 +563,7 @@ class Conductor: ObservableObject {
} }
} }
func cancelSoundPlayer(id: TimerID) { func cancelSoundPlayers(id: TimerID) {
let players = self._soundPlayers(id: id) let players = self._soundPlayers(id: id)
for (key, player) in players { for (key, player) in players {

@ -2,7 +2,7 @@
// Step+CoreDataProperties.swift // Step+CoreDataProperties.swift
// LeCountdown // LeCountdown
// //
// Created by Laurent Morvillier on 30/11/2023. // Created by Laurent Morvillier on 04/12/2023.
// //
// //

@ -9,14 +9,15 @@ import Foundation
import SwiftUI import SwiftUI
import CoreData import CoreData
protocol StoresSound: ManagedObject { protocol StoresSound {
var playableIds: String? { get } var playableIds: String? { get }
var stringId: String { get }
} }
extension StoresSound { extension StoresSound {
var playables: [any Playable] { var playables: [any Playable] {
return playables(idList: self.playableIds) return self.playables(idList: self.playableIds)
} }
func playables(idList: String?) -> [any Playable] { func playables(idList: String?) -> [any Playable] {

@ -56,7 +56,7 @@ enum Catalog {
var playlists: [Playlist] { var playlists: [Playlist] {
switch self { switch self {
case .ring: return [.stephanBodzin, .nature, .relax] case .ring: return [.stephanBodzin, .nature, .relax, .shorts]
case .confirmation: return [.shorts] case .confirmation: return [.shorts]
} }
} }

@ -99,9 +99,10 @@ struct CountdownFormView : View {
SoundFormView(model: self.model) SoundFormView(model: self.model)
} }
.sheet(item: self.$selectedStepItem, onDismiss: { .sheet(item: self.$selectedStepItem, onDismiss: {
// TODO: improve lag
self.model.objectWillChange.send() self.model.objectWillChange.send()
}) { item in }) { item in
RangeFormView(stepItem: item) StepFormView(stepItem: item)
} }
} }

@ -324,7 +324,7 @@ struct CountdownEditView : View {
fileprivate extension Step { fileprivate extension Step {
var item: StepItem { var item: StepItem {
return StepItem(name: self.name, duration: self.duration) return StepItem(name: self.name, duration: self.duration, playableIds: self.playableIds)
} }
} }

@ -7,7 +7,7 @@
import SwiftUI import SwiftUI
struct RangeFormView: View { struct StepFormView: View {
@Environment(\.dismiss) private var dismiss @Environment(\.dismiss) private var dismiss
@ -17,36 +17,49 @@ struct RangeFormView: View {
@State var name: String = "" @State var name: String = ""
@State var duration: TimeInterval = 0.0 @State var duration: TimeInterval = 0.0
var soundModel: SoundModel = SoundModel()
var body: some View { var body: some View {
Form { NavigationStack {
Section(header: Text("Name")) {
TextField(self.namePlaceholder, text: self.$name)
}
Section { Form {
TimePickerView(duration: self.$duration) Section(header: Text("Name")) {
} header: { TextField(self.namePlaceholder, text: self.$name)
LabeledContent("Duration", value: self.duration.hourMinuteSecond) }
.font(.footnote)
}
Section { Section {
Button { TimePickerView(duration: self.$duration)
self._doneHandler() } header: {
} label: { LabeledContent("Duration", value: self.duration.hourMinuteSecond)
HStack { .font(.footnote)
Spacer() }
Text("Done").fontWeight(.bold)
Spacer() Section {
SoundLightLinkView(soundModel: self.soundModel,
catalog: .ring,
title: NSLocalizedString("Sound", comment: "") )
}
Section {
Button {
self._doneHandler()
} label: {
HStack {
Spacer()
Text("Done").fontWeight(.bold)
Spacer()
}
} }
} }
} }
}.onAppear { }.onAppear {
if let name = self.stepItem.name, !name.isEmpty { if let name = self.stepItem.name, !name.isEmpty {
self.namePlaceholder = name self.namePlaceholder = name
} }
self.duration = self.stepItem.duration self.duration = self.stepItem.duration
self.soundModel.setPlayables(self.stepItem.playables)
} }
} }
@ -57,6 +70,7 @@ struct RangeFormView: View {
self.stepItem.name = self.name self.stepItem.name = self.name
} }
self.stepItem.duration = self.duration self.stepItem.duration = self.duration
self.stepItem.playableIds = self.soundModel.playableIds
self.dismiss() self.dismiss()
} }

@ -67,6 +67,23 @@ struct SoundLinkView: View {
} }
struct SoundLightLinkView: View {
@StateObject var soundModel: SoundModel
var catalog: Catalog
var title: String
var body: some View {
NavigationLink {
PlaylistsView(model: self.soundModel,
catalog: self.catalog)
} label: {
LabeledContent(self.title, value: self.soundModel.soundSelection())
}
}
}
struct SoundImageFormView_Previews: PreviewProvider { struct SoundImageFormView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {

@ -15,23 +15,28 @@ protocol SoundHolder {
func selectPlaylist(_ playlist: Playlist, selected: Bool) func selectPlaylist(_ playlist: Playlist, selected: Bool)
} }
class StepItem: Identifiable, ObservableObject { class StepItem: Identifiable, ObservableObject, StoresSound {
let id: String = UUID().uuidString let id: String = UUID().uuidString
var name: String? = nil var name: String? = nil
var duration: TimeInterval = 0.0 var duration: TimeInterval = 0.0
var playableIds: String? = nil
init(name: String? = nil, duration: TimeInterval = 0.0) { init(name: String? = nil, duration: TimeInterval = 0.0, playableIds: String? = nil) {
self.name = name self.name = name
self.duration = duration self.duration = duration
self.playableIds = playableIds
} }
func step(context: NSManagedObjectContext) -> Step { func step(context: NSManagedObjectContext) -> Step {
let step = Step(context: context) let step = Step(context: context)
step.name = self.name step.name = self.name
step.duration = self.duration step.duration = self.duration
step.playableIds = self.playableIds
return step return step
} }
var stringId: String { return self.id }
} }
class TimerModel: ObservableObject { class TimerModel: ObservableObject {

Loading…
Cancel
Save