mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Update Notch Timer View: Give option to disable/enable presets
This commit is contained in:
parent
547ed4d323
commit
57fc9b9bf9
4 changed files with 114 additions and 43 deletions
|
|
@ -17340,6 +17340,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Show preset list in timer tab" : {
|
||||||
|
"comment" : "A toggle that lets users decide whether to show a list of presets in the timer tab.",
|
||||||
|
"isCommentAutoGenerated" : true
|
||||||
|
},
|
||||||
"Show progress" : {
|
"Show progress" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ struct NotchTimerView: View {
|
||||||
@Default(.timerSolidColor) private var solidColor
|
@Default(.timerSolidColor) private var solidColor
|
||||||
@Default(.timerShowsProgress) private var showsProgress
|
@Default(.timerShowsProgress) private var showsProgress
|
||||||
@Default(.timerProgressStyle) private var progressStyle
|
@Default(.timerProgressStyle) private var progressStyle
|
||||||
|
@Default(.showTimerPresetsInNotchTab) private var showTimerPresetsInNotchTab
|
||||||
|
|
||||||
@AppStorage("customTimerDuration") private var customTimerDuration: Double = 600
|
@AppStorage("customTimerDuration") private var customTimerDuration: Double = 600
|
||||||
@State private var customHours: Int = 0
|
@State private var customHours: Int = 0
|
||||||
|
|
@ -249,48 +250,37 @@ struct NotchTimerView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
private var customTimerComposer: some View {
|
private var customTimerComposer: some View {
|
||||||
|
Group {
|
||||||
|
if showTimerPresetsInNotchTab {
|
||||||
VStack(alignment: .leading, spacing: 12) {
|
VStack(alignment: .leading, spacing: 12) {
|
||||||
DurationInputRow(hours: $customHours, minutes: $customMinutes, seconds: $customSeconds)
|
DurationInputRow(
|
||||||
|
hours: $customHours,
|
||||||
|
minutes: $customMinutes,
|
||||||
|
seconds: $customSeconds,
|
||||||
|
fieldWidth: durationFieldWidth
|
||||||
|
)
|
||||||
|
|
||||||
HStack(spacing: 10) {
|
HStack(spacing: 10) {
|
||||||
Button {
|
startButton
|
||||||
withAnimation(.smooth) {
|
resetButton
|
||||||
timerManager.startTimer(duration: customDurationInSeconds, name: "Custom Timer")
|
|
||||||
coordinator.currentView = .timer
|
|
||||||
}
|
}
|
||||||
} label: {
|
|
||||||
Label("Start", systemImage: "play.fill")
|
|
||||||
.font(.system(size: 15, weight: .semibold))
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.padding(.vertical, 10)
|
|
||||||
.foregroundStyle(Color.white)
|
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
} else {
|
||||||
.background(startButtonColor.opacity(isStartDisabled ? 0.5 : 1))
|
HStack(alignment: .center, spacing: 16) {
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
|
DurationInputRow(
|
||||||
.overlay(
|
hours: $customHours,
|
||||||
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
minutes: $customMinutes,
|
||||||
.stroke(Color.white.opacity(0.15), lineWidth: 1)
|
seconds: $customSeconds,
|
||||||
|
fieldWidth: durationFieldWidth
|
||||||
)
|
)
|
||||||
.opacity(isStartDisabled ? 0.7 : 1)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.disabled(isStartDisabled)
|
|
||||||
|
|
||||||
Button {
|
VStack(spacing: 10) {
|
||||||
resetCustomTimerInputs()
|
startButton
|
||||||
} label: {
|
resetButton
|
||||||
Label("Reset", systemImage: "arrow.counterclockwise")
|
}
|
||||||
.font(.system(size: 15, weight: .semibold))
|
.frame(width: buttonColumnWidth, alignment: .top)
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.padding(.vertical, 10)
|
|
||||||
.foregroundStyle(.white.opacity(0.9))
|
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
|
||||||
.background(Color.white.opacity(0.16))
|
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
|
|
||||||
.overlay(
|
|
||||||
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
|
||||||
.stroke(Color.white.opacity(0.08), lineWidth: 1)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(12)
|
.padding(12)
|
||||||
|
|
@ -331,7 +321,7 @@ struct NotchTimerView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
private var shouldShowPresetColumn: Bool {
|
private var shouldShowPresetColumn: Bool {
|
||||||
!timerManager.isTimerActive
|
!timerManager.isTimerActive && showTimerPresetsInNotchTab
|
||||||
}
|
}
|
||||||
|
|
||||||
private var resolvedNotchHeight: CGFloat {
|
private var resolvedNotchHeight: CGFloat {
|
||||||
|
|
@ -424,6 +414,53 @@ struct NotchTimerView: View {
|
||||||
customDurationInSeconds == 0
|
customDurationInSeconds == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var durationFieldWidth: CGFloat {
|
||||||
|
showTimerPresetsInNotchTab ? 64 : 78
|
||||||
|
}
|
||||||
|
|
||||||
|
private var buttonColumnWidth: CGFloat { 210 }
|
||||||
|
|
||||||
|
private var startButton: some View {
|
||||||
|
Button {
|
||||||
|
withAnimation(.smooth) {
|
||||||
|
timerManager.startTimer(duration: customDurationInSeconds, name: "Custom Timer")
|
||||||
|
coordinator.currentView = .timer
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
Label("Start", systemImage: "play.fill")
|
||||||
|
.font(.system(size: 15, weight: .semibold))
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.padding(.vertical, 10)
|
||||||
|
.foregroundStyle(Color.white)
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.background(startButtonColor.opacity(isStartDisabled ? 0.5 : 1))
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
||||||
|
.stroke(Color.white.opacity(0.15), lineWidth: 1)
|
||||||
|
)
|
||||||
|
.opacity(isStartDisabled ? 0.7 : 1)
|
||||||
|
.disabled(isStartDisabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var resetButton: some View {
|
||||||
|
Button(action: resetCustomTimerInputs) {
|
||||||
|
Label("Reset", systemImage: "arrow.counterclockwise")
|
||||||
|
.font(.system(size: 15, weight: .semibold))
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.padding(.vertical, 10)
|
||||||
|
.foregroundStyle(.white.opacity(0.9))
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.background(Color.white.opacity(0.16))
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
||||||
|
.stroke(Color.white.opacity(0.08), lineWidth: 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private var customDurationInSeconds: TimeInterval {
|
private var customDurationInSeconds: TimeInterval {
|
||||||
TimeInterval(customHours * 3600 + customMinutes * 60 + customSeconds)
|
TimeInterval(customHours * 3600 + customMinutes * 60 + customSeconds)
|
||||||
}
|
}
|
||||||
|
|
@ -496,14 +533,27 @@ private struct DurationInputRow: View {
|
||||||
@Binding var hours: Int
|
@Binding var hours: Int
|
||||||
@Binding var minutes: Int
|
@Binding var minutes: Int
|
||||||
@Binding var seconds: Int
|
@Binding var seconds: Int
|
||||||
|
let fieldWidth: CGFloat
|
||||||
|
|
||||||
|
init(
|
||||||
|
hours: Binding<Int>,
|
||||||
|
minutes: Binding<Int>,
|
||||||
|
seconds: Binding<Int>,
|
||||||
|
fieldWidth: CGFloat = 64
|
||||||
|
) {
|
||||||
|
_hours = hours
|
||||||
|
_minutes = minutes
|
||||||
|
_seconds = seconds
|
||||||
|
self.fieldWidth = fieldWidth
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(alignment: .center, spacing: 8) {
|
HStack(alignment: .center, spacing: 8) {
|
||||||
DurationField(label: "HH", value: $hours, range: 0...23)
|
DurationField(label: "HH", value: $hours, range: 0...23, width: fieldWidth)
|
||||||
colon
|
colon
|
||||||
DurationField(label: "MM", value: $minutes, range: 0...59)
|
DurationField(label: "MM", value: $minutes, range: 0...59, width: fieldWidth)
|
||||||
colon
|
colon
|
||||||
DurationField(label: "SS", value: $seconds, range: 0...59)
|
DurationField(label: "SS", value: $seconds, range: 0...59, width: fieldWidth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -518,6 +568,19 @@ private struct DurationField: View {
|
||||||
let label: String
|
let label: String
|
||||||
@Binding var value: Int
|
@Binding var value: Int
|
||||||
let range: ClosedRange<Int>
|
let range: ClosedRange<Int>
|
||||||
|
let width: CGFloat
|
||||||
|
|
||||||
|
init(
|
||||||
|
label: String,
|
||||||
|
value: Binding<Int>,
|
||||||
|
range: ClosedRange<Int>,
|
||||||
|
width: CGFloat = 64
|
||||||
|
) {
|
||||||
|
self.label = label
|
||||||
|
_value = value
|
||||||
|
self.range = range
|
||||||
|
self.width = width
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 6) {
|
VStack(spacing: 6) {
|
||||||
|
|
@ -525,7 +588,7 @@ private struct DurationField: View {
|
||||||
.font(.system(size: 28, weight: .semibold, design: .monospaced))
|
.font(.system(size: 28, weight: .semibold, design: .monospaced))
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
.textFieldStyle(.plain)
|
.textFieldStyle(.plain)
|
||||||
.frame(width: 64, height: 46)
|
.frame(width: width, height: 46)
|
||||||
.background(Color.white.opacity(0.08))
|
.background(Color.white.opacity(0.08))
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
|
.clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3352,6 +3352,7 @@ struct TimerSettings: View {
|
||||||
@Default(.timerShowsLabel) private var showsLabel
|
@Default(.timerShowsLabel) private var showsLabel
|
||||||
@Default(.timerShowsProgress) private var showsProgress
|
@Default(.timerShowsProgress) private var showsProgress
|
||||||
@Default(.timerProgressStyle) private var progressStyle
|
@Default(.timerProgressStyle) private var progressStyle
|
||||||
|
@Default(.showTimerPresetsInNotchTab) private var showTimerPresetsInNotchTab
|
||||||
@Default(.timerControlWindowEnabled) private var controlWindowEnabled
|
@Default(.timerControlWindowEnabled) private var controlWindowEnabled
|
||||||
@Default(.mirrorSystemTimer) private var mirrorSystemTimer
|
@Default(.mirrorSystemTimer) private var mirrorSystemTimer
|
||||||
@Default(.timerDisplayMode) private var timerDisplayMode
|
@Default(.timerDisplayMode) private var timerDisplayMode
|
||||||
|
|
@ -3494,6 +3495,8 @@ struct TimerSettings: View {
|
||||||
Toggle("Show timer name", isOn: $showsLabel)
|
Toggle("Show timer name", isOn: $showsLabel)
|
||||||
Toggle("Show countdown", isOn: $showsCountdown)
|
Toggle("Show countdown", isOn: $showsCountdown)
|
||||||
Toggle("Show progress", isOn: $showsProgress)
|
Toggle("Show progress", isOn: $showsProgress)
|
||||||
|
Toggle("Show preset list in timer tab", isOn: $showTimerPresetsInNotchTab)
|
||||||
|
.settingsHighlight(id: highlightID("Show preset list in timer tab"))
|
||||||
|
|
||||||
Toggle("Show floating pause/stop controls", isOn: $controlWindowEnabled)
|
Toggle("Show floating pause/stop controls", isOn: $controlWindowEnabled)
|
||||||
.disabled(showsLabel)
|
.disabled(showsLabel)
|
||||||
|
|
|
||||||
|
|
@ -547,6 +547,7 @@ extension Defaults.Keys {
|
||||||
static let enableTimerFeature = Key<Bool>("enableTimerFeature", default: true)
|
static let enableTimerFeature = Key<Bool>("enableTimerFeature", default: true)
|
||||||
static let timerDisplayMode = Key<TimerDisplayMode>("timerDisplayMode", default: .tab)
|
static let timerDisplayMode = Key<TimerDisplayMode>("timerDisplayMode", default: .tab)
|
||||||
static let timerPresets = Key<[TimerPreset]>("timerPresets", default: TimerPreset.defaultPresets)
|
static let timerPresets = Key<[TimerPreset]>("timerPresets", default: TimerPreset.defaultPresets)
|
||||||
|
static let showTimerPresetsInNotchTab = Key<Bool>("showTimerPresetsInNotchTab", default: true)
|
||||||
static let timerIconColorMode = Key<TimerIconColorMode>("timerIconColorMode", default: .adaptive)
|
static let timerIconColorMode = Key<TimerIconColorMode>("timerIconColorMode", default: .adaptive)
|
||||||
static let timerSolidColor = Key<Color>("timerSolidColor", default: .blue)
|
static let timerSolidColor = Key<Color>("timerSolidColor", default: .blue)
|
||||||
static let timerShowsCountdown = Key<Bool>("timerShowsCountdown", default: true)
|
static let timerShowsCountdown = Key<Bool>("timerShowsCountdown", default: true)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue