update sound selection

release
Laurent 3 years ago
parent 9fda00f4df
commit de9d14ae8d
  1. 4
      LeCountdown.xcodeproj/project.pbxproj
  2. 19
      LeCountdown/Model/Model+Extensions.swift
  3. 102
      LeCountdown/Sound/Sound.swift
  4. 4
      LeCountdown/Views/Alarm/NewAlarmView.swift
  5. 18
      LeCountdown/Views/Components/SoundImageFormView.swift
  6. 149
      LeCountdown/Views/Components/SoundSelectionView.swift
  7. 84
      LeCountdown/Views/Components/TimerModel.swift
  8. 10
      LeCountdown/Views/ContentView.swift
  9. 23
      LeCountdown/Views/Countdown/CountdownFormView.swift
  10. 33
      LeCountdown/Views/Countdown/NewCountdownView.swift
  11. 62
      LeCountdown/Views/Stopwatch/NewStopwatchView.swift
  12. 16
      LeCountdown/Views/Stopwatch/StopwatchFormView.swift

@ -69,6 +69,7 @@
C498E5A5299152B400E90DE0 /* GreenCheckmarkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C498E5A4299152B400E90DE0 /* GreenCheckmarkView.swift */; };
C498E5A6299152C600E90DE0 /* GreenCheckmarkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C498E5A4299152B400E90DE0 /* GreenCheckmarkView.swift */; };
C4BA2AD62993F62700CB4FBA /* SoundSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2AD52993F62700CB4FBA /* SoundSelectionView.swift */; };
C4BA2ADB299549BC00CB4FBA /* TimerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2ADA299549BC00CB4FBA /* TimerModel.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 */; };
@ -235,6 +236,7 @@
C498E5A4299152B400E90DE0 /* GreenCheckmarkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GreenCheckmarkView.swift; sourceTree = "<group>"; };
C4BA2AD52993F62700CB4FBA /* SoundSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoundSelectionView.swift; sourceTree = "<group>"; };
C4BA2AD72993F7D200CB4FBA /* LeCountdown.0.5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = LeCountdown.0.5.xcdatamodel; sourceTree = "<group>"; };
C4BA2ADA299549BC00CB4FBA /* TimerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerModel.swift; sourceTree = "<group>"; };
C4F8B15629891271005C86A5 /* Conductor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Conductor.swift; sourceTree = "<group>"; };
C4F8B15829891528005C86A5 /* forest_stream.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = forest_stream.mp3; sourceTree = "<group>"; };
C4F8B15E298961A7005C86A5 /* ReorderableForEach.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReorderableForEach.swift; sourceTree = "<group>"; };
@ -542,6 +544,7 @@
C4F8B1D1298BF646005C86A5 /* PermissionAlertView.swift */,
C4F8B165298A9ABB005C86A5 /* SoundImageFormView.swift */,
C4BA2AD52993F62700CB4FBA /* SoundSelectionView.swift */,
C4BA2ADA299549BC00CB4FBA /* TimerModel.swift */,
);
path = Components;
sourceTree = "<group>";
@ -774,6 +777,7 @@
C4F8B1BD298AC8DE005C86A5 /* AlarmDialView.swift in Sources */,
C4F8B1532987FE6F005C86A5 /* LaunchWidgetLiveActivity.swift in Sources */,
C4F8B182298AC234005C86A5 /* Stopwatch+CoreDataClass.swift in Sources */,
C4BA2ADB299549BC00CB4FBA /* TimerModel.swift in Sources */,
C4F8B16B298AA240005C86A5 /* NewStopwatchView.swift in Sources */,
C4060DF5297AE9A7003FAB80 /* TimeInterval+Extensions.swift in Sources */,
C4F8B166298A9ABB005C86A5 /* SoundImageFormView.swift in Sources */,

@ -53,25 +53,24 @@ extension AbstractSoundTimer {
return []
}
var playlists: [Playlist] {
if let playlistList {
return playlistList.enumItems()
}
return []
}
// var playlists: [Playlist] {
// if let playlistList {
// return playlistList.enumItems()
// }
// return []
// }
func setSounds(_ sounds: [Sound]) {
self.soundList = sounds.stringRepresentation
}
func setPlaylists(_ playlists: [Playlist]) {
self.playlistList = playlists.stringRepresentation
}
// func setPlaylists(_ playlists: [Playlist]) {
// self.playlistList = playlists.stringRepresentation
// }
var coolSound: Sound {
var allSounds: [Sound] = []
allSounds.append(contentsOf: self.sounds)
allSounds.append(contentsOf: self.playlists.reduce([], { $0 + $1.sounds }))
return allSounds.randomElement() ?? Sound.allCases[0]
}

@ -8,56 +8,27 @@
import Foundation
import AVFoundation
struct PlaylistSelection: Identifiable {
var id: Int { return self.playlist.id }
var playlist: Playlist
var selected: Bool {
didSet {
if selected {
self.sounds = playlist.sounds
} else {
self.sounds = []
}
}
}
protocol Localized {
var localizedString: String { get }
}
class SoundCatalog {
fileprivate var _sounds: [Sound] = []
var sounds: [Sound] {
set {
_sounds = newValue
if !selected && (newValue.count == self.playlist.sounds.count) {
self.selected = true
} else if selected && (newValue.count != self.playlist.sounds.count) {
self.selected = false
}
}
get {
return _sounds
}
static let main: SoundCatalog = SoundCatalog()
fileprivate var _soundsByPlaylist: [Playlist : [Sound]] = [:]
init() {
self._soundsByPlaylist = Dictionary(grouping: Sound.allCases) { $0.playlist }
}
static func allPlaylists() -> [PlaylistSelection] {
var playlistSelections: [PlaylistSelection] = []
for playlist in Playlist.allCases {
let playlistSelection = PlaylistSelection(playlist: playlist, selected: false)
playlistSelections.append(playlistSelection)
}
return playlistSelections
func sounds(for playlist: Playlist) -> [Sound] {
return self._soundsByPlaylist[playlist] ?? []
}
}
struct SoundSelection: Identifiable {
var id: Int { return self.sound.id }
var sound: Sound
var selected: Bool
}
enum Playlist: Int, CaseIterable, Identifiable {
enum Playlist: Int, CaseIterable, Identifiable, Localized {
var id: Int { return self.rawValue }
@ -65,17 +36,17 @@ enum Playlist: Int, CaseIterable, Identifiable {
case fun
case stephanBodzin
var sounds: [Sound] {
switch self {
case .nature:
return Sound.allCases
case .fun:
return Sound.allCases
case .stephanBodzin:
return Sound.allCases
}
}
// var sounds: [Sound] {
// switch self {
// case .nature:
// return Sound.allCases
// case .fun:
// return Sound.allCases
// case .stephanBodzin:
// return Sound.allCases
// }
// }
//
var localizedString: String {
switch self {
case .nature:
@ -89,17 +60,21 @@ enum Playlist: Int, CaseIterable, Identifiable {
}
// Sound id are stored thus case order should not be changed
enum Sound: Int, CaseIterable, Identifiable {
enum Sound: Int, CaseIterable, Identifiable, Localized {
var id: Int { return self.rawValue }
case trainhorn = 1 // default
case forestStream
case sb1
case sb2
var localizedString: String {
switch self {
case .trainhorn: return NSLocalizedString("Train horn", comment: "")
case .forestStream: return NSLocalizedString("Forest stream", comment: "")
case .sb1: return "sb1"
case .sb2: return "sb2"
}
}
@ -107,16 +82,27 @@ enum Sound: Int, CaseIterable, Identifiable {
switch self {
case .trainhorn: return "train_horn.mp3"
case .forestStream: return "forest_stream.mp3"
case .sb1: return "forest_stream.mp3"
case .sb2: return "forest_stream.mp3"
}
}
var duration: TimeInterval {
var playlist: Playlist {
switch self {
case .trainhorn: return 7.8
case .forestStream: return 300.1
case .trainhorn: return .fun
case .forestStream: return .nature
case .sb1, .sb2: return .stephanBodzin
}
}
// var duration: TimeInterval {
// switch self {
// case .trainhorn: return 7.8
// case .forestStream: return 300.1
// }
// }
var url: URL? {
let components = self.soundName.components(separatedBy: ".")

@ -153,7 +153,7 @@ struct AlarmEditView: View {
}
self.sounds = alarm.sounds
self.playlists = alarm.playlists
// self.playlists = alarm.playlists
if let image = alarm.image, let coolpic = CoolPic(rawValue: image) {
self.image = coolpic
@ -184,7 +184,7 @@ struct AlarmEditView: View {
a.image = self.image.rawValue
a.setSounds(self.sounds)
a.setPlaylists(self.playlists)
// a.setPlaylists(self.playlists)
a.repeatCount = self.soundRepeatCount

@ -11,7 +11,7 @@ struct SoundImageFormView : View {
var imageBinding: Binding<CoolPic>
var playlistBinding: Binding<[PlaylistSelection]>
@EnvironmentObject var model: TimerModel
var repeatCountBinding: Binding<Int16>? = nil
var optionalSound: Binding<Bool>? = nil
@ -30,7 +30,10 @@ struct SoundImageFormView : View {
if self.optionalSound?.wrappedValue == true {
NavigationLink {
SoundSelectionView(playlistBinding: playlistBinding)
PlaylistsView().environmentObject(self.model)
// SoundSelectionView(playlistBinding: playlistBinding)
} label: {
Text("Sound")
}
@ -55,7 +58,7 @@ struct SoundImageFormView : View {
}
NavigationLink {
SoundSelectionView(playlistBinding: playlistBinding)
PlaylistsView().environmentObject(self.model)
} label: {
Text("Sound")
}
@ -99,12 +102,19 @@ struct SoundImageFormView : View {
struct SoundImageFormView_Previews: PreviewProvider {
static func soundBinding(sound: Sound) -> Binding<Bool> {
return .constant(true)
}
static func playlistBinding(playlist: Playlist) -> Binding<Bool> {
return .constant(true)
}
static var previews: some View {
Form {
SoundImageFormView(
imageBinding: .constant(.pic1),
playlistBinding: .constant([]),
repeatCountBinding: .constant(2))
.environmentObject(SoundHolderPlaceholder())
}
}
}

@ -7,57 +7,142 @@
import SwiftUI
struct SoundRow: View {
var sound: Sound
@State var selected: Bool
var handleSelection: (Bool) -> ()
struct PlaylistsView: View {
@EnvironmentObject var model: TimerModel
var body: some View {
Toggle(sound.localizedString, isOn: $selected)
.onChange(of: selected, perform: handleSelection)
Form {
ForEach(Playlist.allCases) { playlist in
PlaylistSectionView(playlist: playlist)
.environmentObject(self.model)
}
}
}
}
struct SoundSelectionView: View {
struct PlaylistSectionView: View {
@Binding var playlistBinding: [PlaylistSelection]
@EnvironmentObject var model: TimerModel
var playlist: Playlist
var body: some View {
Section {
let sounds = SoundCatalog.main.sounds(for: self.playlist)
List(sounds) { sound in
ToggleRow(item: sound, selected: self.model.isSelected(sound: sound)) { selected in
self.model.selectSound(sound, selected: selected)
}
}
} header: {
ToggleRow(item: self.playlist, selected: self.model.isSelected(playlist: self.playlist)) { selected in
self.model.selectPlaylist(self.playlist, selected: selected)
}
}
}
}
struct ToggleRow<T : Localized>: View {
var item: T
@State var selected: Bool
var handleSelection: (Bool) -> ()
var body: some View {
Toggle(item.localizedString, isOn: $selected)
.onChange(of: self.selected, perform: handleSelection)
}
}
//struct PlaylistRow: View {
// var playlist: Playlist
// @State var selected: Bool
// var handleSelection: (Bool) -> ()
//
// var body: some View {
// Toggle(playlist.localizedString, isOn: $selected)
// .onChange(of: selected, perform: handleSelection)
// }
//}
//
//struct SoundRow: View {
// var sound: Sound
// @State var selected: Bool
// var handleSelection: (Bool) -> ()
//
// var body: some View {
// Toggle(sound.localizedString, isOn: $selected)
// .onChange(of: selected, perform: handleSelection)
// }
//}
struct SoundSelectionView: View {
var body: some View {
Form {
ForEach($playlistBinding, id: \.id) { $ps in
// List(selection: <#T##Binding<_?>?#>) {
// <#code#>
// PlaylistsView()
// ForEach($playlistBinding, id: \.id) { $ps in
//
//
// Section {
// ForEach(ps.playlist.sounds) { sound in
//
// SoundRow(sound: sound, selected: ps.sounds.contains(sound)) { selected in
// if selected {
// ps.sounds.append(sound)
// } else {
// ps.sounds.removeAll(where: { $0 == sound })
// }
// }
// }
// } header: {
// Toggle(ps.playlist.localizedString, isOn: $ps.selected)
// }
Section {
ForEach(ps.playlist.sounds) { sound in
SoundRow(sound: sound, selected: ps.sounds.contains(sound)) { selected in
if selected {
ps.sounds.append(sound)
} else {
ps.sounds.removeAll(where: { $0 == sound })
}
}
}
} header: {
Toggle(ps.playlist.localizedString, isOn: $ps.selected)
}
}.navigationTitle("Sounds")
// }.navigationTitle("Sounds")
}
}
}
struct SoundSelectionView_Previews: PreviewProvider {
struct PlaylistsView_Previews: PreviewProvider {
static func soundBinding(sound: Sound) -> Binding<Bool> {
return .constant(true)
}
static func playlistBinding(playlist: Playlist) -> Binding<Bool> {
return .constant(true)
}
static var previews: some View {
PlaylistsView()
.environmentObject(SoundHolderPlaceholder())
}
}
struct PlaylistSectionView_Previews: PreviewProvider {
static func soundBinding(sound: Sound) -> Binding<Bool> {
return .constant(true)
}
static func playlistBinding(playlist: Playlist) -> Binding<Bool> {
return .constant(true)
}
static var previews: some View {
SoundSelectionView(
playlistBinding: .constant([]))
Form {
PlaylistSectionView(playlist: .stephanBodzin)
.environmentObject(SoundHolderPlaceholder())
}
}
}

@ -0,0 +1,84 @@
//
// SoundHolder.swift
// LeCountdown
//
// Created by Laurent Morvillier on 09/02/2023.
//
import Foundation
protocol SoundHolder {
func selectSound(_ sound: Sound, selected: Bool)
func selectPlaylist(_ playlist: Playlist, selected: Bool)
func isSelected(sound: Sound) -> Bool
func isSelected(playlist: Playlist) -> Bool
}
class TimerModel : ObservableObject, SoundHolder {
@Published var playlists: Set<Playlist> = []
@Published var sounds: Set<Sound> = []
// MARK: - SoundHolder
func selectSound(_ sound: Sound, selected: Bool) {
print("selectSound")
if selected {
self.sounds.insert(sound)
} else {
self.sounds.remove(sound)
}
// toggle playlist if necessary
let playlist = sound.playlist
let playlistSounds: [Sound] = SoundCatalog.main.sounds(for: playlist)
if self.sounds.isSuperset(of: playlistSounds) {
self.playlists.insert(playlist)
} else {
self.playlists.remove(playlist)
}
}
func selectPlaylist(_ playlist: Playlist, selected: Bool) {
print("selectPlaylist")
if selected {
self.playlists.insert(playlist)
} else {
self.playlists.remove(playlist)
}
let sounds: [Sound] = SoundCatalog.main.sounds(for: playlist)
self.sounds.formSymmetricDifference(sounds)
print("sounds = \(self.sounds.count)")
}
func isSelected(sound: Sound) -> Bool {
self.sounds.contains(sound)
}
func isSelected(playlist: Playlist) -> Bool {
self.playlists.contains(playlist)
}
}
class SoundHolderPlaceholder : ObservableObject, SoundHolder {
func selectSound(_ sound: Sound, selected: Bool) {
}
func selectPlaylist(_ playlist: Playlist, selected: Bool) {
}
func isSelected(sound: Sound) -> Bool {
return false
}
func isSelected(playlist: Playlist) -> Bool {
return false
}
}

@ -59,7 +59,8 @@ struct ContentView<T : AbstractTimer>: View {
ReorderableForEach(items: timersArray) { timer in
DialView(timer: timer, isEditingBinding: self.$isEditing, frameSize: width) .environment(\.managedObjectContext, viewContext)
DialView(timer: timer, isEditingBinding: self.$isEditing, frameSize: width)
.environment(\.managedObjectContext, viewContext)
.environmentObject(Conductor.maestro)
.environmentObject(boringContext)
@ -70,7 +71,8 @@ struct ContentView<T : AbstractTimer>: View {
}.padding(.horizontal, itemSpacing)
if !conductor.liveTimers.isEmpty {
LiveTimerListView() .environment(\.managedObjectContext, viewContext)
LiveTimerListView()
.environment(\.managedObjectContext, viewContext)
.environmentObject(conductor)
.background(Color(white: 0.9))
.cornerRadius(16.0, corners: [.topRight, .topLeft])
@ -118,6 +120,8 @@ struct ContentView<T : AbstractTimer>: View {
}
// MARK: - Subviews
@ViewBuilder
fileprivate func _newView(isPresented: Binding<Bool>) -> some View {
switch T.self {
@ -132,6 +136,8 @@ struct ContentView<T : AbstractTimer>: View {
}
}
// MARK: - Business
fileprivate func _reorder(from: IndexSet, to: Int) {
var timers: [AbstractTimer] = self.timersArray

@ -10,12 +10,14 @@ import SwiftUI
struct CountdownFormView : View {
@EnvironmentObject var model: TimerModel
var secondsBinding: Binding<String>
var minutesBinding: Binding<String>
var nameBinding: Binding<String>
var imageBinding: Binding<CoolPic>
var playlistBinding: Binding<[PlaylistSelection]>
var repeatCountBinding: Binding<Int16>
var textFieldIsFocused: FocusState<Bool>.Binding
@ -37,8 +39,8 @@ struct CountdownFormView : View {
SoundImageFormView(
imageBinding: imageBinding,
playlistBinding: playlistBinding,
repeatCountBinding: repeatCountBinding)
.environmentObject(self.model)
}
}
@ -49,8 +51,21 @@ struct CountdownFormView_Previews: PreviewProvider {
@FocusState static var textFieldIsFocused: Bool
static func soundBinding(sound: Sound) -> Binding<Bool> {
return .constant(true)
}
static func playlistBinding(playlist: Playlist) -> Binding<Bool> {
return .constant(true)
}
static var previews: some View {
CountdownFormView(secondsBinding: .constant(""), minutesBinding: .constant(""),
nameBinding: .constant(""), imageBinding: .constant(.pic3), playlistBinding: .constant([]), repeatCountBinding: .constant(2), textFieldIsFocused: $textFieldIsFocused)
CountdownFormView(
secondsBinding: .constant(""),
minutesBinding: .constant(""),
nameBinding: .constant(""),
imageBinding: .constant(.pic3),
repeatCountBinding: .constant(2),
textFieldIsFocused: $textFieldIsFocused)
.environmentObject(SoundHolderPlaceholder())
}
}

@ -28,6 +28,8 @@ struct CountdownEditView : View {
@Environment(\.managedObjectContext) private var viewContext
@Environment(\.dismiss) private var dismiss
@StateObject var model: TimerModel = TimerModel()
var countdown: Countdown? = nil
@Binding var isPresented: Bool
@ -36,8 +38,9 @@ struct CountdownEditView : View {
@State var minutesString: String = ""
@State var nameString: String = ""
// @State var sounds: [SoundSelection] = []
@State var playlists: [PlaylistSelection] = []
@State var playlists: Set<Playlist> = []
@State var sounds: Set<Sound> = []
@State var soundRepeatCount: Int16 = 0
@State var image: CoolPic = .pic1
@ -71,9 +74,9 @@ struct CountdownEditView : View {
minutesBinding: $minutesString,
nameBinding: $nameString,
imageBinding: $image,
playlistBinding: $playlists,
repeatCountBinding: $soundRepeatCount,
textFieldIsFocused: $textFieldIsFocused)
.environmentObject(self.model)
.onAppear {
self._onAppear()
}
@ -137,9 +140,31 @@ struct CountdownEditView : View {
}
// MARK: - Bindings
func playlistBinding(playlist: Playlist) -> Binding<Bool> {
Binding<Bool>(
get: { self.playlists.contains(playlist) },
set: { if $0 { self.playlists.insert(playlist) }
else { self.playlists.remove(playlist) }
}
)
}
func soundBinding(sound: Sound) -> Binding<Bool> {
Binding<Bool>(
get: { self.sounds.contains(sound) },
set: { if $0 { self.sounds.insert(sound) }
else { self.sounds.remove(sound) }
}
)
}
// MARK: - Business
fileprivate func _onAppear() {
self.playlists = PlaylistSelection.allPlaylists()
// self.playlists = PlaylistSelection.allPlaylists()
self._isAdding = (self.countdown == nil)

@ -28,6 +28,8 @@ struct StopwatchEditView: View {
@Environment(\.managedObjectContext) private var viewContext
@Environment(\.dismiss) private var dismiss
@StateObject var model: TimerModel = TimerModel()
var stopwatch: Stopwatch? = nil
@Binding var isPresented: Bool
@ -37,7 +39,7 @@ struct StopwatchEditView: View {
@State var nameString: String = ""
@State var playSound: Bool = false
@State var playlists: [PlaylistSelection] = []
@State var image: CoolPic = .pic1
@State var deleteConfirmationShown: Bool = false
@ -68,9 +70,8 @@ struct StopwatchEditView: View {
StopwatchFormView(nameBinding: self.$nameString,
imageBinding: self.$image,
playSoundBinding: self.$playSound,
playlistBinding: self.$playlists,
textFieldIsFocused: $textFieldIsFocused)
.onAppear {
textFieldIsFocused: $textFieldIsFocused).environmentObject(self.model)
.onAppear {
self._onAppear()
}
.confirmationDialog("", isPresented: $deleteConfirmationShown, actions: {
@ -133,6 +134,59 @@ struct StopwatchEditView: View {
}
// MARK: - Bindings
// func playlistBinding(playlist: Playlist) -> Binding<Bool> {
// Binding<Bool>(
// get: { self.playlists.contains(playlist) },
// set: { self._playlistChange(playlist, selected: $0) }
// )
// }
//
// fileprivate func _playlistChange(_ playlist: Playlist, selected: Bool) {
//
// print("_playlistChange")
//
// let sounds: [Sound] = SoundCatalog.main.sounds(for: playlist)
// if selected {
// self.playlists.insert(playlist)
// self.sounds.formUnion(sounds)
// } else {
// self.playlists.remove(playlist)
// self.sounds.formIntersection(sounds)
// }
// }
//
// func soundBinding(sound: Sound) -> Binding<Bool> {
// Binding<Bool>(
// get: { self.sounds.contains(sound) },
// set: { self._soundChange(sound, selected: $0) }
// )
// }
//
// fileprivate func _soundChange(_ sound: Sound, selected: Bool) {
//
// print("_soundChange")
//
// if selected {
// self.sounds.insert(sound)
// } else {
// self.sounds.remove(sound)
// }
//
// // toggle playlist if necessary
// let playlist = sound.playlist
// let playlistSounds: [Sound] = SoundCatalog.main.sounds(for: playlist)
// if self.sounds.isSuperset(of: playlistSounds) {
// self.playlists.insert(playlist)
// } else {
// self.playlists.remove(playlist)
// }
//
// }
// MARK: - Business
fileprivate func _onAppear() {
self._isAdding = (self.stopwatch == nil)

@ -13,7 +13,7 @@ struct StopwatchFormView: View {
var imageBinding: Binding<CoolPic>
var playSoundBinding: Binding<Bool>
var playlistBinding: Binding<[PlaylistSelection]>
@EnvironmentObject var model: TimerModel
var textFieldIsFocused: FocusState<Bool>.Binding
@ -26,8 +26,8 @@ struct StopwatchFormView: View {
}
SoundImageFormView(imageBinding: imageBinding,
playlistBinding: playlistBinding,
optionalSound: playSoundBinding)
.environmentObject(self.model)
}
}
@ -36,11 +36,13 @@ struct StopwatchFormView: View {
struct StopwatchFormView_Previews: PreviewProvider {
@FocusState static var textFieldIsFocused: Bool
static var previews: some View {
StopwatchFormView(nameBinding: .constant(""),
imageBinding: .constant(.pic1),
playSoundBinding: .constant(true),
playlistBinding: .constant([]), textFieldIsFocused: $textFieldIsFocused)
StopwatchFormView(
nameBinding: .constant(""),
imageBinding: .constant(.pic1),
playSoundBinding: .constant(true),
textFieldIsFocused: $textFieldIsFocused)
.environmentObject(SoundHolderPlaceholder())
}
}

Loading…
Cancel
Save