parent
676c813bab
commit
1a8bcf6a4d
@ -0,0 +1,56 @@ |
|||||||
|
// |
||||||
|
// TimerRouter.swift |
||||||
|
// LeCountdown |
||||||
|
// |
||||||
|
// Created by Laurent Morvillier on 02/02/2023. |
||||||
|
// |
||||||
|
|
||||||
|
import Foundation |
||||||
|
import NotificationCenter |
||||||
|
|
||||||
|
class TimerRouter { |
||||||
|
|
||||||
|
static func performAction(timer: AbstractTimer, handler: @escaping (Result<Bool, Error>) -> Void) { |
||||||
|
switch timer { |
||||||
|
case let countdown as Countdown: |
||||||
|
self._launchCountdown(countdown, handler: handler) |
||||||
|
case let alarm as Alarm: |
||||||
|
self._scheduleAlarm(alarm, handler: handler) |
||||||
|
case let stopwatch as Stopwatch: |
||||||
|
self._startStopwatch(stopwatch, handler: handler) |
||||||
|
default: |
||||||
|
print("missing launcher for \(self)") |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
fileprivate static func _launchCountdown(_ countdown: Countdown, handler: @escaping (Result<Bool, Error>) -> Void) { |
||||||
|
UNUserNotificationCenter.current().getNotificationSettings { settings in |
||||||
|
|
||||||
|
switch settings.authorizationStatus { |
||||||
|
case .notDetermined, .denied: |
||||||
|
handler(.failure(TimerError.notificationAuthorizationMissing)) |
||||||
|
default: |
||||||
|
CountdownScheduler.master.scheduleIfPossible(countdown: countdown) { result in |
||||||
|
switch result { |
||||||
|
case .success(_): |
||||||
|
handler(.success(true)) |
||||||
|
case .failure(let failure): |
||||||
|
handler(.failure(failure)) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
fileprivate static func _scheduleAlarm(_ alarm: Alarm, handler: @escaping (Result<Bool, Error>) -> Void) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
fileprivate static func _startStopwatch(_ stopwatch: Stopwatch, handler: @escaping (Result<Bool, Error>) -> Void) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,31 @@ |
|||||||
|
// |
||||||
|
// PermissionAlertView.swift |
||||||
|
// LeCountdown |
||||||
|
// |
||||||
|
// Created by Laurent Morvillier on 02/02/2023. |
||||||
|
// |
||||||
|
|
||||||
|
import SwiftUI |
||||||
|
|
||||||
|
struct PermissionAlertView: View { |
||||||
|
|
||||||
|
var body: some View { |
||||||
|
Button("Show permissions") { |
||||||
|
self._showPermissionSettings() |
||||||
|
} |
||||||
|
Button("OK", role: .cancel) { } |
||||||
|
} |
||||||
|
|
||||||
|
fileprivate func _showPermissionSettings() { |
||||||
|
if let url = URL(string: UIApplication.openNotificationSettingsURLString) { |
||||||
|
UIApplication.shared.open(url) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
struct PermissionAlertView_Previews: PreviewProvider { |
||||||
|
static var previews: some View { |
||||||
|
PermissionAlertView() |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,98 @@ |
|||||||
|
// |
||||||
|
// DialView.swift |
||||||
|
// LeCountdown |
||||||
|
// |
||||||
|
// Created by Laurent Morvillier on 02/02/2023. |
||||||
|
// |
||||||
|
|
||||||
|
import SwiftUI |
||||||
|
|
||||||
|
struct DialView: View { |
||||||
|
|
||||||
|
@Environment(\.managedObjectContext) private var viewContext |
||||||
|
|
||||||
|
@EnvironmentObject var boringContext: BoringContext |
||||||
|
|
||||||
|
@State var timer: AbstractTimer |
||||||
|
|
||||||
|
var frameSize: CGFloat |
||||||
|
|
||||||
|
var body: some View { |
||||||
|
ZStack(alignment: .topTrailing) { |
||||||
|
|
||||||
|
Image(timer.imageName).resizable() |
||||||
|
|
||||||
|
Button { |
||||||
|
self._launchTimer(timer) |
||||||
|
} label: { |
||||||
|
self._dialView(timer: timer) |
||||||
|
} |
||||||
|
|
||||||
|
NavigationLink { |
||||||
|
self._editView(timer: timer, isPresented: $boringContext.isShowingNewData) |
||||||
|
} label: { |
||||||
|
Image(systemName: "gearshape.fill") |
||||||
|
.font(.system(size: 24, weight: .light)) |
||||||
|
.padding() |
||||||
|
.foregroundColor(Color.white) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
.frame(width: frameSize, height: frameSize) |
||||||
|
.cornerRadius(40.0) |
||||||
|
} |
||||||
|
|
||||||
|
@ViewBuilder |
||||||
|
fileprivate func _dialView(timer: AbstractTimer) -> some View { |
||||||
|
switch timer { |
||||||
|
case let countdown as Countdown: |
||||||
|
CountdownDialView(countdown: countdown) |
||||||
|
case let alarm as Alarm: |
||||||
|
AlarmDialView(alarm: alarm) |
||||||
|
case let stopwatch as Stopwatch: |
||||||
|
StopwatchDialView(stopwatch: stopwatch) |
||||||
|
default: |
||||||
|
Text("missing dial view") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@ViewBuilder |
||||||
|
fileprivate func _editView(timer: AbstractTimer, isPresented: Binding<Bool>) -> some View { |
||||||
|
switch timer { |
||||||
|
case let countdown as Countdown: |
||||||
|
CountdownEditView(countdown: countdown, isPresented: isPresented) |
||||||
|
case let alarm as Alarm: |
||||||
|
AlarmEditView(alarm: alarm, isPresented: isPresented) |
||||||
|
case let stopwatch as Stopwatch: |
||||||
|
StopwatchEditView(stopwatch: stopwatch, isPresented: isPresented) |
||||||
|
default: |
||||||
|
Text("missing edit view") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fileprivate func _launchTimer(_ timer: AbstractTimer) { |
||||||
|
|
||||||
|
TimerRouter.performAction(timer: timer) { result in |
||||||
|
switch result { |
||||||
|
case .success: |
||||||
|
break |
||||||
|
case .failure(let failure): |
||||||
|
switch failure { |
||||||
|
case TimerError.notificationAuthorizationMissing: |
||||||
|
self.boringContext.showPermissionAlert = true |
||||||
|
default: |
||||||
|
self.boringContext.error = failure |
||||||
|
self.boringContext.showDefaultAlert = true |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
struct DialView_Previews: PreviewProvider { |
||||||
|
static var previews: some View { |
||||||
|
DialView(timer: Countdown.fake(context: PersistenceController.preview.container.viewContext), frameSize: 150.0) |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue