diff --git a/LeCountdown.xcodeproj/project.pbxproj b/LeCountdown.xcodeproj/project.pbxproj index 0af4f5f..5e6ceed 100644 --- a/LeCountdown.xcodeproj/project.pbxproj +++ b/LeCountdown.xcodeproj/project.pbxproj @@ -74,6 +74,7 @@ C445FA922987CC8A0054D761 /* Sound.swift in Sources */ = {isa = PBXBuildFile; fileRef = C445FA912987CC8A0054D761 /* Sound.swift */; }; C4636D9C29AF46BD00994E31 /* ActivityKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4636D9B29AF46BD00994E31 /* ActivityKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; C4636D9D29AF46D900994E31 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C438C7D02981216200BF3EF9 /* WidgetKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + C46926BD29DDC49E0003E310 /* SubscriptionButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46926BC29DDC49E0003E310 /* SubscriptionButtonView.swift */; }; C473C2F029A8CFFC0056B38A /* TimerRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8B1D7298C0727005C86A5 /* TimerRouter.swift */; }; C473C2F129A8DA0B0056B38A /* Conductor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8B15629891271005C86A5 /* Conductor.swift */; }; C473C2F229A8DA1F0056B38A /* CountdownScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C438C7C02980228B00BF3EF9 /* CountdownScheduler.swift */; }; @@ -379,6 +380,7 @@ C445FA902987C0CF0054D761 /* LeCountdown.0.2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = LeCountdown.0.2.xcdatamodel; sourceTree = ""; }; C445FA912987CC8A0054D761 /* Sound.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sound.swift; sourceTree = ""; }; C4636D9B29AF46BD00994E31 /* ActivityKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ActivityKit.framework; path = System/Library/Frameworks/ActivityKit.framework; sourceTree = SDKROOT; }; + C46926BC29DDC49E0003E310 /* SubscriptionButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionButtonView.swift; sourceTree = ""; }; C473C2F829A8DC0A0056B38A /* LaunchWidgetAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchWidgetAttributes.swift; sourceTree = ""; }; C473C32729AA307D0056B38A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/LaunchWidget.intentdefinition; sourceTree = ""; }; C473C32929AA30890056B38A /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/LaunchWidget.strings; sourceTree = ""; }; @@ -813,6 +815,7 @@ C4BA2B56299FFA4F00CB4FBA /* AppGuard.swift */, C4E5D67F29B8FD93008E7465 /* Store.swift */, C4BA2B5E299FFC8300CB4FBA /* StoreView.swift */, + C46926BC29DDC49E0003E310 /* SubscriptionButtonView.swift */, ); path = Subscription; sourceTree = ""; @@ -1239,6 +1242,7 @@ C4F8B164298A9A92005C86A5 /* AlarmFormView.swift in Sources */, C40FDB622992985C0042A390 /* TextToSpeechRecorder.swift in Sources */, C4BA2B43299FCB2B00CB4FBA /* RecordsView.swift in Sources */, + C46926BD29DDC49E0003E310 /* SubscriptionButtonView.swift in Sources */, C4BA2B2F299E69A000CB4FBA /* View+Extension.swift in Sources */, C4E5D68629BB369E008E7465 /* TimersView.swift in Sources */, C4E5D68A29BB7953008E7465 /* SettingsView.swift in Sources */, diff --git a/LeCountdown/Subscription/AppGuard.swift b/LeCountdown/Subscription/AppGuard.swift index aad54b9..970da5f 100644 --- a/LeCountdown/Subscription/AppGuard.swift +++ b/LeCountdown/Subscription/AppGuard.swift @@ -126,7 +126,7 @@ extension Notification.Name { } var isSubscriber: Bool { - return true //self.currentPlan != .none + return self.currentPlan != .none } var currentPlan: StorePlan { diff --git a/LeCountdown/Subscription/StoreView.swift b/LeCountdown/Subscription/StoreView.swift index 2489de6..cf76596 100644 --- a/LeCountdown/Subscription/StoreView.swift +++ b/LeCountdown/Subscription/StoreView.swift @@ -123,6 +123,7 @@ struct PlanView: View { VStack { if let plan = StorePlan(rawValue: product.id) { Text("\(product.displayPrice) / \(plan.formattedPeriod)").font(.title3) + .foregroundColor(.white) } else { Text("Plan not found") } @@ -137,6 +138,8 @@ struct PlanView: View { } }.padding() + .foregroundColor(.black) + .background(Color(red: 1.0, green: 0.8, blue: 0.9)) } fileprivate func _purchase(product: Product) { diff --git a/LeCountdown/Subscription/SubscriptionButtonView.swift b/LeCountdown/Subscription/SubscriptionButtonView.swift new file mode 100644 index 0000000..cdba866 --- /dev/null +++ b/LeCountdown/Subscription/SubscriptionButtonView.swift @@ -0,0 +1,38 @@ +// +// SubscriptionButtonView.swift +// LeCountdown +// +// Created by Laurent Morvillier on 05/04/2023. +// + +import SwiftUI + + +struct SubscriptionButtonView: View { + + @State private var showSubscriptionSheet: Bool = false + + var body: some View { + Button { + self.showSubscriptionSheet = true + } label: { + Text("Get fully enchanted") + .frame(maxWidth: .infinity) + } + .sheet(isPresented: self.$showSubscriptionSheet, content: { + StoreView(isPresented: self.$showSubscriptionSheet) + }) + .frame(height: 50.0) + .background(Color.accentColor) + .cornerRadius(8.0) + .padding(.horizontal) + .buttonStyle(.bordered) + .foregroundColor(.white) + } +} + +struct SubscriptionButtonView_Previews: PreviewProvider { + static var previews: some View { + SubscriptionButtonView() + } +} diff --git a/LeCountdown/Views/ContentView.swift b/LeCountdown/Views/ContentView.swift index 38af741..9c92bb5 100644 --- a/LeCountdown/Views/ContentView.swift +++ b/LeCountdown/Views/ContentView.swift @@ -17,6 +17,11 @@ class BoringContext : ObservableObject { @Published var siriTimer: AbstractTimer? = nil } +//enum TimerType { +// case timer +// case stopwatch +//} + struct ContentView: View { @Environment(\.managedObjectContext) private var viewContext @@ -32,25 +37,18 @@ struct ContentView: View { @State private var showSettingsSheet: Bool = false @State private var showStatsSheet: Bool = false - @State private var showAddSheet: Bool = false +// @State private var showAddSheet: Bool = false +// @State private var showTimerSheet: Bool = false +// @State private var showStopwatchSheet: Bool = false @State private var showSubscriptionSheet: Bool = false - + var body: some View { VStack { if !AppGuard.main.isSubscriber { - Button { - self.showSubscriptionSheet = true - } label: { - Text("Get fully enchanted") - .frame(maxWidth: .infinity) - } .background(Color.accentColor) - .cornerRadius(8.0) - .padding(.horizontal) - .buttonStyle(.bordered) - .foregroundColor(.white) + SubscriptionButtonView() } TimersView(isEditing: self.$isEditing, @@ -61,41 +59,12 @@ struct ContentView: View { .environment(\.managedObjectContext, viewContext) .environmentObject(self.boringContext) - // if !self.tipsShown, let tip = Preferences.tipToShow { - // TipView(tip: tip) { - // self._hideTip(tip) - // }.padding() - // } - if !conductor.liveTimers.isEmpty { Spacer() - if UIDevice.isPhoneIdiom { - - SiriTimerView(timer: self.boringContext.siriTimer, isVisible: self.$siriTipShown) - - HStack(alignment: .center) { - VolumeView(changeVolume: true) - .padding(12.0) - }.frame(width: 300.0, height: 40.0) - .background(Color(white: 0.9)) - .cornerRadius(16.0) - } else { - - HStack() { - if self.siriTipShown { - SiriTimerView(timer: self.boringContext.siriTimer, isVisible: self.$siriTipShown) - Spacer() - } - VolumeView() - .padding(12.0) - .frame(width: 300.0, height: 40.0) - .background(Color(white: 0.9)) - .cornerRadius(16.0) - }.padding(.horizontal) - } - + SiriVolumeView(timer: self.boringContext.siriTimer, siriTipShown: self.$siriTipShown) + LiveTimerListView() .environment(\.managedObjectContext, viewContext) .environmentObject(conductor) @@ -105,8 +74,7 @@ struct ContentView: View { .cornerRadius(32.0, corners: [.topRight, .topLeft]) } } - - .navigationTitle("Home") + .navigationTitle(Bundle.main.applicationName) .alert(boringContext.error?.localizedDescription ?? "missing error", isPresented: $boringContext.showDefaultAlert) { Button("OK", role: .cancel) { } } @@ -115,59 +83,12 @@ struct ContentView: View { } .sheet(isPresented: self.$boringContext.isShowingNewData, content: { }) - .sheet(isPresented: self.$showSettingsSheet, content: { - SettingsView() - .presentationDetents([.height(240.0)]) - }) - .sheet(isPresented: self.$showSubscriptionSheet, content: { - StoreView(isPresented: self.$showSubscriptionSheet) - }) - .sheet(isPresented: self.$showStatsSheet, content: { - NavigationStack { - ActivitiesView() - } - }) - .sheet(isPresented: self.$showAddSheet, content: { - NavigationStack { - NewCountdownView(isPresented: $showAddSheet, tabSelection: .constant(0)) - .environment(\.managedObjectContext, viewContext) - } - }) +// .sheet(isPresented: self.$showAddSheet, content: { +// NewCountdownView(isPresented: $showAddSheet, tabSelection: .constant(0)) +// .environment(\.managedObjectContext, viewContext) +// }) .toolbar { - ToolbarItem(placement: .navigationBarLeading) { - Button { - withAnimation { - self.isEditing.toggle() - } - } label: { - Text(self.isEditing ? "Done" : "Edit") - } - } - ToolbarItemGroup(placement: .navigationBarTrailing) { - if self.viewContext.count(entityName: "Record") > 0 { - Button { - withAnimation { - self.showStatsSheet.toggle() - } - } label: { - Image(systemName: "chart.bar.doc.horizontal") - } - } - Button { - withAnimation { - self.showSettingsSheet.toggle() - } - } label: { - Image(systemName: "gearshape.fill") - } - Button { - withAnimation { - self.showAddSheet.toggle() - } - } label: { - Image(systemName: "plus") - } - } + MainToolbarView(isEditing: self.$isEditing) } .onAppear { self._askPermissions() @@ -243,37 +164,87 @@ struct ContentView: View { } -struct MainToolbarView: View { +struct MainToolbarView: ToolbarContent { + + @Environment(\.managedObjectContext) private var viewContext + + @Binding var isEditing: Bool + +// @State var type: TimerType? = nil - var isShowingNewData: Binding + @State var showSettingsSheet: Bool = false + @State var showStatsSheet: Bool = false + @State var showAddSheet: Bool = false + @State var showTimerSheet: Bool = false + @State var showStopwatchSheet: Bool = false - var body: some View { - Button { - self.isShowingNewData.wrappedValue = true - } label: { - HStack { - Image(systemName: "timer") - Text("countdown") + var body: some ToolbarContent { + ToolbarItem(placement: .navigationBarLeading) { + Button { + withAnimation { + self.isEditing.toggle() + } + } label: { + Text(self.isEditing ? "Done" : "Edit") } } - Button { - self.isShowingNewData.wrappedValue = true - } label: { - HStack { - Image(systemName: "stopwatch") - Text("stopwatch") + ToolbarItemGroup(placement: .navigationBarTrailing) { + if self.haveRecords() { + Button { + withAnimation { + self.showStatsSheet.toggle() + } + } label: { + Image(systemName: "chart.bar.doc.horizontal") + } + .sheet(isPresented: self.$showStatsSheet, content: { + NavigationStack { + ActivitiesView() + } + }) } - } - Button { - self.isShowingNewData.wrappedValue = true - } label: { - HStack { - Image(systemName: "alarm") - Text("alarm") + Button { + withAnimation { + self.showSettingsSheet.toggle() + } + } label: { + Image(systemName: "gearshape.fill") } + .sheet(isPresented: self.$showSettingsSheet, content: { + SettingsView() + .presentationDetents([.height(240.0)]) + }) + Button { + withAnimation { + self.showAddSheet.toggle() + } + } label: { + Image(systemName: "plus") + } + .confirmationDialog("Please select", isPresented: self.$showAddSheet) { + Button("Timer") { + self.showAddSheet = false + self.showTimerSheet.toggle() + } + Button("Stopwatch") { + self.showAddSheet = false + self.showStopwatchSheet.toggle() + } + } + .sheet(isPresented: self.$showStopwatchSheet, content: { + NewStopwatchView(isPresented: $showStopwatchSheet, tabSelection: .constant(0)) + }) + .sheet(isPresented: self.$showTimerSheet, content: { + NewCountdownView(isPresented: $showTimerSheet, tabSelection: .constant(0)) + }) } } + + func haveRecords() -> Bool { + return self.viewContext.count(entityName: "Record") > 0 + } + } fileprivate extension Countdown { @@ -311,10 +282,24 @@ class TimerSpot : Identifiable, Equatable { } -struct ContentView_Previews: PreviewProvider { +//struct ContentView_Previews: PreviewProvider { +// static var previews: some View { +// ContentView() +// .environment(\.managedObjectContext, PersistenceController.preview.container.viewContext) +// .environmentObject(Conductor.maestro) +// +// } +//} + +struct Toolbar_Previews: PreviewProvider { static var previews: some View { - ContentView() - .environment(\.managedObjectContext, PersistenceController.preview.container.viewContext).environmentObject(Conductor.maestro) + NavigationStack { + Text("Hello") + } + .navigationTitle("Title") + .toolbar { + MainToolbarView(isEditing: .constant(false)) + } } } diff --git a/LeCountdown/Views/Countdown/NewCountdownView.swift b/LeCountdown/Views/Countdown/NewCountdownView.swift index 093219c..eb727bc 100644 --- a/LeCountdown/Views/Countdown/NewCountdownView.swift +++ b/LeCountdown/Views/Countdown/NewCountdownView.swift @@ -27,15 +27,16 @@ struct NewCountdownView : View { } var body: some View { - CountdownEditView(isPresented: $isPresented, tabSelection: self.tabSelection) - .environment(\.managedObjectContext, viewContext) - .navigationTitle("New countdown") - .onAppear { - self.userActivity.becomeCurrent() - } - .onDisappear { - self.userActivity.resignCurrent() - } + NavigationStack { + CountdownEditView(isPresented: $isPresented, tabSelection: self.tabSelection) + .environment(\.managedObjectContext, viewContext) + .onAppear { + self.userActivity.becomeCurrent() + } + .onDisappear { + self.userActivity.resignCurrent() + } + } } } @@ -155,8 +156,7 @@ struct CountdownEditView : View { } } - - .navigationTitle("Edit countdown") + .navigationTitle(self.countdown?.name ?? NSLocalizedString("New timer", comment: "")) } .onAppear { self._onAppear() diff --git a/LeCountdown/Views/Reusable/SiriTimerView.swift b/LeCountdown/Views/Reusable/SiriTimerView.swift index 01bda28..ac1128c 100644 --- a/LeCountdown/Views/Reusable/SiriTimerView.swift +++ b/LeCountdown/Views/Reusable/SiriTimerView.swift @@ -8,6 +8,43 @@ import SwiftUI import _AppIntents_SwiftUI +struct SiriVolumeView: View { + + var timer: AbstractTimer? = nil + @Binding var siriTipShown: Bool + + var body: some View { + + if UIDevice.isPhoneIdiom { + SiriTimerView(timer: self.timer, + isVisible: self.$siriTipShown) + + HStack(alignment: .center) { + VolumeView(changeVolume: true) + .padding(12.0) + }.frame(width: 300.0, height: 40.0) + .background(Color(white: 0.9)) + .cornerRadius(16.0) + + } else { + HStack() { + if self.siriTipShown { + SiriTimerView(timer: self.timer, + isVisible: self.$siriTipShown) + Spacer() + } + VolumeView() + .padding(12.0) + .frame(width: 300.0, height: 40.0) + .background(Color(white: 0.9)) + .cornerRadius(16.0) + }.padding(.horizontal) + } + + } + +} + struct SiriTimerView: View { var timer: AbstractTimer? = nil diff --git a/LeCountdown/Views/Reusable/SoundFormView.swift b/LeCountdown/Views/Reusable/SoundFormView.swift index fe0f78b..d077b5f 100644 --- a/LeCountdown/Views/Reusable/SoundFormView.swift +++ b/LeCountdown/Views/Reusable/SoundFormView.swift @@ -35,7 +35,7 @@ struct SoundFormView : View { SoundLinkView(soundModel: self.model.soundModel, catalog: .ring, - title: "Sound") + title: NSLocalizedString("Sound", comment: "") ) if self.repeatCountBinding != nil { Picker("Repeat Count", selection: self.repeatCountBinding!) { @@ -49,7 +49,7 @@ struct SoundFormView : View { SoundLinkView(soundModel: self.model.confirmationSoundModel, catalog: .confirmation, - title: "Confirmation Sound") + title: NSLocalizedString("Confirmation Sound", comment: "")) }.sheet(isPresented: self.$imageSelectionSheetShown) { ImageSelectionView(showBinding: self.$imageSelectionSheetShown, imageBinding: self.imageBinding) diff --git a/LeCountdown/fr.lproj/Localizable.strings b/LeCountdown/fr.lproj/Localizable.strings index 68a261a..8b86a4e 100644 --- a/LeCountdown/fr.lproj/Localizable.strings +++ b/LeCountdown/fr.lproj/Localizable.strings @@ -137,7 +137,7 @@ "New alarm" = "Nouvelle alarme"; /* No comment provided by engineer. */ -"New countdown" = "Nouveau minuteur"; +"New timer" = "Nouveau minuteur"; /* No comment provided by engineer. */ "New stopwatch" = "Nouveau chrono"; @@ -259,3 +259,10 @@ "year" = "an"; "Get fully enchanted" = "Enchantement permanent"; "Ask Siri: %@ %@!" = "Dites à Siri: %@ %@!"; +"Timer" = "Minuteur"; +"Stopwatch" = "Chronomètre"; +"Duration" = "Durée"; +"Confirmation Sound" = "Son de démarrage"; +"Name" = "Nom"; +"Hours" = "Heures"; +"Default Volume" = "Volume par défaut";