pommedoro/Sources/Pommedoro/BreakScreens.swift

284 lines
12 KiB
Swift

import AppKit
extension AppDelegate {
func showFullOverlay() {
countdownTimer?.invalidate()
currentSuggestion = SuggestionManager.shared.next()
statusItem.button?.title = "🍅 Time's Up!"
for window in countdownWindows { window.orderOut(nil) }
breakCountdownLabels.removeAll()
breakRemainingSeconds = 300
startBreakTimer()
for (i, window) in overlayWindows.enumerated() {
window.ignoresMouseEvents = false
buildSuggestionScreen(window: window, isPrimary: i == 0)
NSAnimationContext.runAnimationGroup { ctx in
ctx.duration = 0.3
window.animator().alphaValue = 1.0
}
}
}
func startBreakTimer() {
breakTimer?.invalidate()
breakTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] timer in
guard let self = self else { timer.invalidate(); return }
self.breakRemainingSeconds -= 1
self.updateBreakCountdownLabels()
if self.breakRemainingSeconds <= 0 {
timer.invalidate()
}
}
}
func updateBreakCountdownLabels() {
let minutes = breakRemainingSeconds / 60
let seconds = breakRemainingSeconds % 60
let text = String(format: "%02d:%02d", minutes, seconds)
for label in breakCountdownLabels {
label.stringValue = text
}
}
func buildSuggestionScreen(window: NSWindow, isPrimary: Bool) {
let size = window.frame.size
let view = NSView(frame: NSRect(origin: .zero, size: size))
view.wantsLayer = true
view.layer?.backgroundColor = NSColor.systemTeal.withAlphaComponent(0.85).cgColor
let countdownLabel = NSTextField(labelWithString: "05:00")
countdownLabel.font = NSFont.monospacedSystemFont(ofSize: 72, weight: .bold)
countdownLabel.textColor = .white
countdownLabel.alignment = .center
countdownLabel.sizeToFit()
countdownLabel.frame.origin = CGPoint(
x: (size.width - countdownLabel.frame.width) / 2,
y: (size.height / 2) + 80
)
view.addSubview(countdownLabel)
breakCountdownLabels.append(countdownLabel)
let suggestion = NSTextField(labelWithString: currentSuggestion)
suggestion.font = NSFont.systemFont(ofSize: 48, weight: .medium)
suggestion.textColor = NSColor.white.withAlphaComponent(0.9)
suggestion.alignment = .center
suggestion.sizeToFit()
suggestion.frame.origin = CGPoint(
x: (size.width - suggestion.frame.width) / 2,
y: (size.height / 2) - 10
)
view.addSubview(suggestion)
if isPrimary {
let closeBtn = NSButton(frame: NSRect(x: size.width - 140, y: size.height - 60, width: 120, height: 36))
closeBtn.title = "Close"
closeBtn.bezelStyle = .rounded
closeBtn.font = NSFont.systemFont(ofSize: 14, weight: .medium)
closeBtn.target = self
closeBtn.action = #selector(closePommedoro)
view.addSubview(closeBtn)
let continueWorkingBtn = NSButton(frame: NSRect(x: (size.width - 200) / 2, y: size.height / 2 - 50, width: 200, height: 50))
continueWorkingBtn.title = "Continue Working"
continueWorkingBtn.bezelStyle = .rounded
continueWorkingBtn.font = NSFont.systemFont(ofSize: 18, weight: .semibold)
continueWorkingBtn.target = self
continueWorkingBtn.action = #selector(resumePommedoro)
view.addSubview(continueWorkingBtn)
let btnY = size.height / 2 - 110
let btnW: CGFloat = 160
let btnH: CGFloat = 44
let gap: CGFloat = 16
let totalW = btnW * 3 + gap * 2
let startX = (size.width - totalW) / 2
let successBtn = NSButton(frame: NSRect(x: startX, y: btnY, width: btnW, height: btnH))
successBtn.title = "Success!"
successBtn.bezelStyle = .rounded
successBtn.font = NSFont.systemFont(ofSize: 16, weight: .semibold)
successBtn.target = self
successBtn.action = #selector(didSuccess)
view.addSubview(successBtn)
let nextTimeBtn = NSButton(frame: NSRect(x: startX + btnW + gap, y: btnY, width: btnW, height: btnH))
nextTimeBtn.title = "Next Time"
nextTimeBtn.bezelStyle = .rounded
nextTimeBtn.font = NSFont.systemFont(ofSize: 16, weight: .semibold)
nextTimeBtn.target = self
nextTimeBtn.action = #selector(resumePommedoro)
view.addSubview(nextTimeBtn)
let dontSuggestBtn = NSButton(frame: NSRect(x: startX + (btnW + gap) * 2, y: btnY, width: btnW, height: btnH))
dontSuggestBtn.title = "Don't Suggest"
dontSuggestBtn.bezelStyle = .rounded
dontSuggestBtn.font = NSFont.systemFont(ofSize: 16, weight: .semibold)
dontSuggestBtn.target = self
dontSuggestBtn.action = #selector(dismissSuggestion)
view.addSubview(dontSuggestBtn)
}
window.contentView = view
}
@objc func didSuccess() {
breakCountdownLabels.removeAll()
for (i, window) in overlayWindows.enumerated() {
let size = window.frame.size
let view = NSView(frame: NSRect(origin: .zero, size: size))
view.wantsLayer = true
view.layer?.backgroundColor = NSColor.systemTeal.withAlphaComponent(0.85).cgColor
let countdownLabel = NSTextField(labelWithString: String(format: "%02d:%02d", breakRemainingSeconds / 60, breakRemainingSeconds % 60))
countdownLabel.font = NSFont.monospacedSystemFont(ofSize: 36, weight: .bold)
countdownLabel.textColor = NSColor.white.withAlphaComponent(0.7)
countdownLabel.alignment = .center
countdownLabel.sizeToFit()
countdownLabel.frame.origin = CGPoint(
x: (size.width - countdownLabel.frame.width) / 2,
y: size.height - 80
)
view.addSubview(countdownLabel)
breakCountdownLabels.append(countdownLabel)
let congrats = NSTextField(labelWithString: "Nice work!")
congrats.font = NSFont.systemFont(ofSize: 72, weight: .bold)
congrats.textColor = .white
congrats.alignment = .center
congrats.sizeToFit()
congrats.frame.origin = CGPoint(
x: (size.width - congrats.frame.width) / 2,
y: (size.height / 2) + 80
)
view.addSubview(congrats)
let prompt = NSTextField(labelWithString: "How did that impact your readiness for the day?")
prompt.font = NSFont.systemFont(ofSize: 36, weight: .medium)
prompt.textColor = NSColor.white.withAlphaComponent(0.9)
prompt.alignment = .center
prompt.sizeToFit()
prompt.frame.origin = CGPoint(
x: (size.width - prompt.frame.width) / 2,
y: (size.height / 2) + 10
)
view.addSubview(prompt)
if i == 0 {
let closeBtn = NSButton(frame: NSRect(x: size.width - 140, y: size.height - 60, width: 120, height: 36))
closeBtn.title = "Close"
closeBtn.bezelStyle = .rounded
closeBtn.font = NSFont.systemFont(ofSize: 14, weight: .medium)
closeBtn.target = self
closeBtn.action = #selector(closePommedoro)
view.addSubview(closeBtn)
let reflY = size.height / 2 - 60
let btnW: CGFloat = 180
let btnH: CGFloat = 44
let gap: CGFloat = 16
let totalW = btnW * 3 + gap * 2
let startX = (size.width - totalW) / 2
let greatBtn = NSButton(frame: NSRect(x: startX, y: reflY, width: btnW, height: btnH))
greatBtn.title = "Feeling Great"
greatBtn.bezelStyle = .rounded
greatBtn.font = NSFont.systemFont(ofSize: 15, weight: .medium)
greatBtn.target = self
greatBtn.action = #selector(reflectionDone)
view.addSubview(greatBtn)
let okBtn = NSButton(frame: NSRect(x: startX + btnW + gap, y: reflY, width: btnW, height: btnH))
okBtn.title = "About the Same"
okBtn.bezelStyle = .rounded
okBtn.font = NSFont.systemFont(ofSize: 15, weight: .medium)
okBtn.target = self
okBtn.action = #selector(reflectionDone)
view.addSubview(okBtn)
let notBtn = NSButton(frame: NSRect(x: startX + (btnW + gap) * 2, y: reflY, width: btnW, height: btnH))
notBtn.title = "Not Really"
notBtn.bezelStyle = .rounded
notBtn.font = NSFont.systemFont(ofSize: 15, weight: .medium)
notBtn.target = self
notBtn.action = #selector(reflectionDone)
view.addSubview(notBtn)
}
window.contentView = view
}
}
@objc func reflectionDone() {
breakCountdownLabels.removeAll()
for (i, window) in overlayWindows.enumerated() {
let size = window.frame.size
let view = NSView(frame: NSRect(origin: .zero, size: size))
view.wantsLayer = true
view.layer?.backgroundColor = NSColor.systemTeal.withAlphaComponent(0.85).cgColor
let countdownLabel = NSTextField(labelWithString: String(format: "%02d:%02d", breakRemainingSeconds / 60, breakRemainingSeconds % 60))
countdownLabel.font = NSFont.monospacedSystemFont(ofSize: 36, weight: .bold)
countdownLabel.textColor = NSColor.white.withAlphaComponent(0.7)
countdownLabel.alignment = .center
countdownLabel.sizeToFit()
countdownLabel.frame.origin = CGPoint(
x: (size.width - countdownLabel.frame.width) / 2,
y: size.height - 80
)
view.addSubview(countdownLabel)
breakCountdownLabels.append(countdownLabel)
let msg = NSTextField(labelWithString: "Ready when you are")
msg.font = NSFont.systemFont(ofSize: 56, weight: .bold)
msg.textColor = .white
msg.alignment = .center
msg.sizeToFit()
msg.frame.origin = CGPoint(
x: (size.width - msg.frame.width) / 2,
y: (size.height / 2) + 40
)
view.addSubview(msg)
if i == 0 {
let closeBtn = NSButton(frame: NSRect(x: size.width - 140, y: size.height - 60, width: 120, height: 36))
closeBtn.title = "Close"
closeBtn.bezelStyle = .rounded
closeBtn.font = NSFont.systemFont(ofSize: 14, weight: .medium)
closeBtn.target = self
closeBtn.action = #selector(closePommedoro)
view.addSubview(closeBtn)
let btnW: CGFloat = 180
let btnH: CGFloat = 50
let gap: CGFloat = 24
let totalW = btnW * 2 + gap
let startX = (size.width - totalW) / 2
let btnY = size.height / 2 - 50
let pauseBtn = NSButton(frame: NSRect(x: startX, y: btnY, width: btnW, height: btnH))
pauseBtn.title = "Pause"
pauseBtn.bezelStyle = .rounded
pauseBtn.font = NSFont.systemFont(ofSize: 18, weight: .semibold)
pauseBtn.target = self
pauseBtn.action = #selector(pauseFromOverlay)
view.addSubview(pauseBtn)
let continueBtn = NSButton(frame: NSRect(x: startX + btnW + gap, y: btnY, width: btnW, height: btnH))
continueBtn.title = "Continue"
continueBtn.bezelStyle = .rounded
continueBtn.font = NSFont.systemFont(ofSize: 18, weight: .semibold)
continueBtn.target = self
continueBtn.action = #selector(resumePommedoro)
view.addSubview(continueBtn)
}
window.contentView = view
}
}
}