/
SleepTimer.swift
127 lines (94 loc) · 3.68 KB
/
SleepTimer.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
//
// SleepTimerManager.swift
// BookPlayer
//
// Created by Florian Pichler on 30.03.18.
// Copyright © 2018 Florian Pichler.
//
import Foundation
import UIKit
typealias SleepTimerStart = () -> Void
typealias SleepTimerProgress = (Double) -> Void
typealias SleepTimerEnd = (_ cancelled: Bool) -> Void
final class SleepTimer {
static let shared = SleepTimer()
let durationFormatter: DateComponentsFormatter = DateComponentsFormatter()
private var timer: Timer?
private var onStart: SleepTimerStart?
private var onProgress: SleepTimerProgress?
private var onEnd: SleepTimerEnd?
private let defaultMessage: String = "Pause playback"
private let alert: UIAlertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
private var timeLeft: TimeInterval = 0.0
private let intervals: [TimeInterval] = [
300.0,
600.0,
900.0,
1800.0,
2700.0,
3600.0
]
// MARK: Internals
private init() {
self.durationFormatter.unitsStyle = .positional
self.durationFormatter.allowedUnits = [.minute, .second]
self.durationFormatter.collapsesLargestUnit = true
self.reset()
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
formatter.allowedUnits = [.hour, .minute]
self.alert.addAction(UIAlertAction(title: "Off", style: .default, handler: { _ in
self.cancel()
}))
for interval in self.intervals {
let formattedDuration = formatter.string(from: interval as TimeInterval)!
self.alert.addAction(UIAlertAction(title: "In \(formattedDuration)", style: .default, handler: { _ in
self.sleep(in: interval)
}))
}
self.alert.addAction(UIAlertAction(title: "End of current chapter", style: .default) { _ in
self.cancel()
self.alert.message = "Sleeping when the chapter ends"
NotificationCenter.default.addObserver(self, selector: #selector(self.end), name: .chapterChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.end), name: .bookChange, object: nil)
})
self.alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
}
private func sleep(in seconds: Double) {
self.onStart?()
self.onProgress?(seconds)
self.reset()
self.timeLeft = seconds
self.timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
RunLoop.main.add(self.timer!, forMode: RunLoopMode.commonModes)
}
private func reset() {
self.alert.message = defaultMessage
self.timer?.invalidate()
NotificationCenter.default.removeObserver(self, name: .bookEnd, object: nil)
NotificationCenter.default.removeObserver(self, name: .chapterChange, object: nil)
}
private func cancel() {
self.reset()
self.onEnd?(true)
}
@objc private func update() {
self.timeLeft -= 1.0
self.onProgress?(self.timeLeft)
self.alert.message = "Sleeping in \(self.durationFormatter.string(from: self.timeLeft)!)"
if self.timeLeft <= 0 {
self.end()
}
}
@objc private func end() {
self.reset()
self.onEnd?(false)
}
// MARK: Public methods
func actionSheet(onStart: @escaping SleepTimerStart, onProgress: @escaping SleepTimerProgress, onEnd: @escaping SleepTimerEnd) -> UIAlertController {
self.onStart = onStart
self.onEnd = onEnd
self.onProgress = onProgress
return self.alert
}
}