StartView integration

main
Laurent 3 years ago
parent e76429b7cb
commit 4eb74fe4d9
  1. 23
      LeCountdown/LeCountdownApp.swift
  2. 2
      LeCountdown/Sound/Sound.swift
  3. 2
      LeCountdown/Utils/Preferences.swift
  4. 52
      LeCountdown/Views/Countdown/NewCountdownView.swift
  5. 4
      LeCountdown/Views/PresetsView.swift
  6. 242
      LeCountdown/Views/StartView.swift

@ -19,7 +19,9 @@ struct LeCountdownApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@Environment(\.scenePhase) var scenePhase
@State var showStartView: Bool = false
init() {
UIPageControl.appearance().currentPageIndicatorTintColor = .systemPink
@ -34,13 +36,11 @@ struct LeCountdownApp: App {
var body: some Scene {
WindowGroup {
ZStack {
// StartView()
CompactHomeView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
}
CompactHomeView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
.fullScreenCover(isPresented: $showStartView) {
StartView(isPresented: $showStartView)
}
.onAppear {
self._onAppear()
}
@ -62,10 +62,17 @@ struct LeCountdownApp: App {
}
fileprivate func _shouldShowStartView() -> Bool {
let count = persistenceController.container.viewContext.count(entityName: "AbstractTimer")
return count == 0 && Preferences.hasShownStartView == false
}
fileprivate func _onAppear() {
Logger.log("preferredLanguages = \(String(describing: Locale.preferredLanguages))")
self.showStartView = self._shouldShowStartView()
self._patch()
let containerAvailable = self.isICloudContainerAvailable()
Logger.log("isICloudContainerAvailable = \(containerAvailable)")

@ -77,7 +77,7 @@ enum Playlist: String, CaseIterable, Identifiable, Localized {
case .nature:
return NSLocalizedString("Nature", comment: "")
case .stephanBodzin:
return "Stephan Bodzin"
return "Boavista"
case .custom:
return NSLocalizedString("Custom", comment: "")
case .relax:

@ -8,6 +8,7 @@
import Foundation
enum PreferenceKey: String {
case hasShownStartView
case installDate
case countdowns
case pausedCountdowns
@ -38,6 +39,7 @@ class Preferences {
@UserDefault(PreferenceKey.cloudKitSchemaInitialized.rawValue, defaultValue: false) static var cloudKitSchemaInitialized: Bool
@UserDefault(PreferenceKey.defaultVolume.rawValue, defaultValue: 0.5) static var defaultVolume: Float
@UserDefault(PreferenceKey.installDate.rawValue, defaultValue: nil) static var installDate: Date?
@UserDefault(PreferenceKey.hasShownStartView.rawValue, defaultValue: false) static var hasShownStartView: Bool
static var hideSilentModeAlerts: Bool {
return UserDefaults.standard.bool(forKey: PreferenceKey.showSilentModeAlert.rawValue)

@ -52,11 +52,6 @@ struct CountdownEditView : View {
@Binding var isPresented: Bool
@State var nameString: String = ""
// @State var secondsString: String = ""
// @State var minutesString: String = ""
// @State var hoursString: String = ""
@State var duration: TimeInterval = 0.0
@State var soundRepeatCount: Int16 = 0
@ -74,8 +69,6 @@ struct CountdownEditView : View {
@Environment(\.isPresented) var envIsPresented
@State var shouldScrollToTop: Bool = false
@FocusState private var focusedField: CountdownField?
init(isPresented: Binding<Bool>, countdown: Countdown? = nil) {
@ -88,8 +81,6 @@ struct CountdownEditView : View {
self.preset = preset
}
fileprivate var _formId = "formId"
var body: some View {
NavigationStack {
@ -103,24 +94,15 @@ struct CountdownEditView : View {
}
}
// Form {
// EmptyView().id("anchor")
CountdownFormView(
focusedField: _focusedField,
nameBinding: $nameString,
// secondsBinding: $secondsString,
// minutesBinding: $minutesString,
// hoursBinding: $hoursString,
durationBinding: $duration,
imageBinding: $image,
repeatCountBinding: $soundRepeatCount)
.environmentObject(self.model)
// BasePresetsView { preset in
// self._loadPreset(preset)
// }
// }
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
@ -129,22 +111,6 @@ struct CountdownEditView : View {
} label: {
Image(systemName: "keyboard.chevron.compact.down")
}
// Spacer()
// Button {
// self.focusPreviousField($focusedField)
// } label: {
// Image(systemName: "chevron.up")
// }
// Button {
// self.focusNextField($focusedField)
// } label: {
// Image(systemName: "chevron.down")
// }
}
}
.onChange(of: self.shouldScrollToTop) { newValue in
withAnimation {
reader.scrollTo("anchor")
}
}
@ -223,27 +189,9 @@ struct CountdownEditView : View {
fileprivate func _loadPreset(_ preset: Preset) {
self.nameString = preset.localizedName
self.duration = preset.duration
// let nf = NumberFormatter()
// let minutes = Int(preset.duration / 60.0)
// if minutes > 0 {
// self.minutesString = nf.string(from: NSNumber(value: minutes)) ?? ""
// } else {
// self.minutesString = ""
// }
//
// let seconds = Int(preset.duration) - minutes * 60
// if seconds > 0 {
// self.secondsString = nf.string(from: NSNumber(value: seconds)) ?? ""
// } else {
// self.secondsString = ""
// }
self.model.group = preset.intervalGroup
self.model.soundModel.loadPreset(preset)
self.shouldScrollToTop.toggle()
}
fileprivate func _loadCountdown(_ countdown: Countdown) {

@ -201,9 +201,9 @@ enum PresetSection: Int, Identifiable, CaseIterable {
// case workout
case mindfullness
case cooking
case tea
case move
case tea
case cooking
var presets: [Preset] {
switch self {

@ -7,16 +7,74 @@
import SwiftUI
struct StartView: View {
@StateObject var model: PresetSelectionModel = PresetSelectionModel()
@Binding var isPresented: Bool
@State var showAddScreen: Bool = false
var body: some View {
VStack(spacing: 0.5) {
PresetSelectionView(model: self.model).monospaced()
Button {
self.showAddScreen = true
} label: {
HStack {
Image(systemName: "plus.circle").font(.title)
Text("Create your own").font(.title3)
}
.padding()
.frame(maxWidth: .infinity)
.foregroundColor(.white)
.background(Color.accentColor)
}.sheet(isPresented: self.$showAddScreen) {
NewCountdownView(isPresented: $showAddScreen)
}
Button {
self._done()
} label: {
Text("Done")
.font(.title2).fontWeight(.semibold)
.padding()
.frame(maxWidth: .infinity)
.background(.white)
}
}.background(.gray)
}
fileprivate func _done() {
let customizations = self.model.customizations.values.filter { $0.added }
for custo in customizations {
let _ = custo.createTimer()
}
let context = PersistenceController.shared.container.viewContext
do {
try context.save()
} catch {
Logger.error(error)
}
Preferences.hasShownStartView = true
self.isPresented = false
}
}
class Customization: ObservableObject {
var preset: Preset
@Published var added: Bool = false
@Published var duration: Double = 0.0 {
didSet {
self.added = true
}
}
@Published var duration: Double = 0.0
@Published var timerModel: TimerModel = TimerModel()
init(preset: Preset) {
@ -34,6 +92,7 @@ class Customization: ObservableObject {
func createTimer() -> AbstractTimer {
let context = PersistenceController.shared.container.viewContext
let countdown = Countdown(context: context)
countdown.activity = CoreDataRequests.getOrCreateActivity(name: preset.localizedName)
countdown.duration = self.duration
countdown.playableIds = self.timerModel.soundModel.playableIds
return countdown
@ -43,11 +102,7 @@ class Customization: ObservableObject {
class PresetSelectionModel: ObservableObject {
// @Published var addedPresets: Set<Preset> = []
@Published var customizations: [Preset : Customization] = [:]
// @Published var expanded: Set<Preset> = []
// @Published var duration: [TimeInterval] = []
init() {
self.customizations = Preset.allCases.reduce(into: [Preset: Customization]()) { $0[$1] = Customization(preset: $1) }
@ -57,7 +112,7 @@ class PresetSelectionModel: ObservableObject {
struct DurationButtonView: View {
@StateObject var customization: Customization
@ObservedObject var customization: Customization
@State var showDurationSheet: Bool = false
var body: some View {
@ -68,8 +123,21 @@ struct DurationButtonView: View {
Text(customization.duration.hourMinuteSecond)
}
.sheet(isPresented: $showDurationSheet) {
TimePickerView(duration: self.$customization.duration)
.presentationDetents([.height(320.0)])
DurationSheetView(duration: self.$customization.duration)
}
}
}
struct DurationSheetView: View {
@Binding var duration: TimeInterval
var body: some View {
VStack(alignment: .leading) {
Text("Duration").padding([.leading, .top])
TimePickerView(duration: self.$duration)
.presentationDetents([.height(240.0)])
}
}
@ -77,7 +145,7 @@ struct DurationButtonView: View {
struct SoundButtonView: View {
@StateObject var soundModel: SoundModel
@ObservedObject var soundModel: SoundModel
@State var showSoundSheet: Bool = false
var body: some View {
@ -96,126 +164,71 @@ struct SoundButtonView: View {
}
struct PresetSelectionView: View {
struct CustomizationRowView: View {
@StateObject var model: PresetSelectionModel
var preset: Preset
@StateObject var customization: Customization
var body: some View {
List {
ForEach(PresetSection.allCases) { section in
Section(section.localizedName.uppercased()) {
ForEach(section.presets.indices, id: \.self) { i in
HStack {
let preset = section.presets[i]
let customization = self.model.customizations[preset]!
HStack {
Button {
self._addOrRemove(preset: preset)
} label: {
Button {
self.customization.toggleAdd()
} label: {
HStack {
HStack {
let added = customization.added
let image = added ? "checkmark.circle.fill" : "circle"
Image(systemName: image)
.padding(.trailing, 8.0)
.font(.title2)
.foregroundColor(Color.accentColor)
let image = self.customization.added ? "checkmark.circle.fill" : "circle"
Image(systemName: image)
.padding(.trailing, 8.0)
.font(.title2)
.foregroundColor(Color.accentColor)
Text(preset.localizedName)
Text(preset.localizedName)
Spacer()
VStack(alignment: .trailing) {
DurationButtonView(customization: customization)
SoundButtonView(soundModel: customization.timerModel.soundModel)
}.buttonStyle(.bordered)
}.font(.callout)
}
Spacer()
VStack(alignment: .trailing) {
DurationButtonView(customization: self.customization)
SoundButtonView(soundModel: self.customization.timerModel.soundModel)
}.buttonStyle(.bordered)
}.font(.callout)
}
}
}
.onChange(of: self.customization.duration) { _ in
self.customization.added = true
}
}
}
}
}.listStyle(.inset)
}
fileprivate func _addOrRemove(preset: Preset) {
self.model.customizations[preset]?.toggleAdd()
}
fileprivate func _added(preset: Preset) -> Bool {
return self.model.customizations[preset]?.added ?? false
}
fileprivate func _image(preset: Preset) -> String {
return self._added(preset: preset) ? "checkmark.circle.fill" : "circle"
}
}
struct StartView: View {
@StateObject var model: PresetSelectionModel = PresetSelectionModel()
struct PresetSelectionView: View {
@State var showAddScreen: Bool = false
@ObservedObject var model: PresetSelectionModel
var body: some View {
VStack(spacing: 0.5) {
PresetSelectionView(model: self.model).monospaced()
Button {
self.showAddScreen = true
} label: {
HStack {
Image(systemName: "plus.circle").font(.title)
Text("Create your own").font(.title3)
}
.padding()
.frame(maxWidth: .infinity)
.foregroundColor(.white)
.background(Color.accentColor)
}.sheet(isPresented: self.$showAddScreen) {
NewCountdownView(isPresented: $showAddScreen)
}
List {
ForEach(PresetSection.allCases) { section in
Section(section.localizedName.uppercased()) {
ForEach(section.presets.indices, id: \.self) { i in
Button {
self._done()
} label: {
Text("Done")
.font(.title2).fontWeight(.semibold)
.padding()
.frame(maxWidth: .infinity)
// .foregroundColor(.white)
.background(.white)
}
let preset = section.presets[i]
let customization = self.model.customizations[preset]!
CustomizationRowView(preset: preset, customization: customization)
}.background(.gray)
}
fileprivate func _done() {
let customizations = self.model.customizations.values.filter { $0.added }
for custo in customizations {
let _ = custo.createTimer()
}
}
}
}
}.listStyle(.inset)
let context = PersistenceController.shared.container.viewContext
do {
try context.save()
} catch {
Logger.error(error)
}
}
}
@ -275,9 +288,10 @@ struct ConfigurationView: View {
struct StartView_Previews: PreviewProvider {
static var previews: some View {
StartView()
StartView(isPresented: .constant(true))
ConfigurationView(preset: Preset.blackTea,
model: TimerModel(),
duration: .constant(60.0))
DurationSheetView(duration: .constant(1.0))
}
}

Loading…
Cancel
Save