|
|
|
|
@ -17,6 +17,11 @@ class BoringContext : ObservableObject { |
|
|
|
|
@Published var siriTimer: AbstractTimer? = nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//enum TimerType { |
|
|
|
|
// case timer |
|
|
|
|
// case stopwatch |
|
|
|
|
//} |
|
|
|
|
|
|
|
|
|
struct ContentView<T : AbstractTimer>: View { |
|
|
|
|
|
|
|
|
|
@Environment(\.managedObjectContext) private var viewContext |
|
|
|
|
@ -32,25 +37,18 @@ struct ContentView<T : AbstractTimer>: 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<T : AbstractTimer>: 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<T : AbstractTimer>: 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<T : AbstractTimer>: 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<T : AbstractTimer>: View { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct MainToolbarView: View { |
|
|
|
|
struct MainToolbarView: ToolbarContent { |
|
|
|
|
|
|
|
|
|
@Environment(\.managedObjectContext) private var viewContext |
|
|
|
|
|
|
|
|
|
@Binding var isEditing: Bool |
|
|
|
|
|
|
|
|
|
// @State var type: TimerType? = nil |
|
|
|
|
|
|
|
|
|
var isShowingNewData: Binding<Bool> |
|
|
|
|
@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<Countdown>() |
|
|
|
|
// .environment(\.managedObjectContext, PersistenceController.preview.container.viewContext) |
|
|
|
|
// .environmentObject(Conductor.maestro) |
|
|
|
|
// |
|
|
|
|
// } |
|
|
|
|
//} |
|
|
|
|
|
|
|
|
|
struct Toolbar_Previews: PreviewProvider { |
|
|
|
|
static var previews: some View { |
|
|
|
|
ContentView<Countdown>() |
|
|
|
|
.environment(\.managedObjectContext, PersistenceController.preview.container.viewContext).environmentObject(Conductor.maestro) |
|
|
|
|
NavigationStack { |
|
|
|
|
Text("Hello") |
|
|
|
|
} |
|
|
|
|
.navigationTitle("Title") |
|
|
|
|
.toolbar { |
|
|
|
|
MainToolbarView(isEditing: .constant(false)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|