Skip to content

Commit c5b2717

Browse files
updated mac app
1 parent 8f42f8d commit c5b2717

File tree

2 files changed

+81
-80
lines changed

2 files changed

+81
-80
lines changed

apps/ios/YearProgressApp/AppDelegate.swift

Lines changed: 81 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,25 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
77
private var currentMode: ProgressMode = .year
88
private var updateTimer: Timer?
99
private let launchAtLoginKey = "LaunchAtLogin"
10-
private let customStartDateKey = "CustomStartDate"
1110
private let customEndDateKey = "CustomEndDate"
1211
private var yearMenuItem: NSMenuItem?
1312
private var monthMenuItem: NSMenuItem?
1413
private var dayMenuItem: NSMenuItem?
14+
private var weekMenuItem: NSMenuItem?
15+
private var workWeekMenuItem: NSMenuItem?
1516
private var customMenuItem: NSMenuItem?
1617

17-
18-
private var customStartDate: Date?
1918
private var customEndDate: Date?
2019

2120
private enum ProgressMode: CaseIterable {
22-
case year, month, day, custom
21+
case year, month, week, workWeek, day, custom
2322

2423
var title: String {
2524
switch self {
2625
case .year: return "of yyyy"
27-
case .month: return "of MMM"
26+
case .month: return "of MMMM"
27+
case .week: return "of Week"
28+
case .workWeek: return "of Work Week"
2829
case .day: return "of Today"
2930
case .custom: return "Custom"
3031
}
@@ -46,10 +47,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
4647
func applicationDidFinishLaunching(_ aNotification: Notification) {
4748
NSApp.setActivationPolicy(.accessory)
4849

49-
50-
if let startDate = UserDefaults.standard.object(forKey: customStartDateKey) as? Date,
51-
let endDate = UserDefaults.standard.object(forKey: customEndDateKey) as? Date {
52-
customStartDate = startDate
50+
if let endDate = UserDefaults.standard.object(forKey: customEndDateKey) as? Date {
5351
customEndDate = endDate
5452
}
5553

@@ -78,21 +76,26 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
7876

7977
yearMenuItem = NSMenuItem(title: "Year Progress", action: #selector(selectYearMode), keyEquivalent: "")
8078
monthMenuItem = NSMenuItem(title: "Month Progress", action: #selector(selectMonthMode), keyEquivalent: "")
79+
weekMenuItem = NSMenuItem(title: "Week Progress", action: #selector(selectWeekMode), keyEquivalent: "")
80+
workWeekMenuItem = NSMenuItem(title: "Work Week Progress", action: #selector(selectWorkWeekMode), keyEquivalent: "")
8181
dayMenuItem = NSMenuItem(title: "Day Progress", action: #selector(selectDayMode), keyEquivalent: "")
8282
customMenuItem = NSMenuItem(title: "Custom Date Progress", action: #selector(selectCustomMode), keyEquivalent: "")
8383

8484
if let yearItem = yearMenuItem, let monthItem = monthMenuItem,
85+
let weekItem = weekMenuItem, let workWeekItem = workWeekMenuItem,
8586
let dayItem = dayMenuItem, let customItem = customMenuItem {
8687
menu.addItem(yearItem)
8788
menu.addItem(monthItem)
89+
menu.addItem(weekItem)
90+
menu.addItem(workWeekItem)
8891
menu.addItem(dayItem)
8992
menu.addItem(customItem)
9093
}
9194

9295
menu.addItem(NSMenuItem.separator())
9396

9497

95-
let configureCustomItem = NSMenuItem(title: "Configure Custom Dates...", action: #selector(configureCustomDates), keyEquivalent: "")
98+
let configureCustomItem = NSMenuItem(title: "Configure Custom End Date...", action: #selector(configureCustomDates), keyEquivalent: "")
9699
menu.addItem(configureCustomItem)
97100

98101

@@ -121,96 +124,78 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
121124
updateProgress()
122125
}
123126

127+
@objc private func selectWeekMode() {
128+
currentMode = .week
129+
updateMenuCheckmarks()
130+
updateProgress()
131+
}
132+
133+
@objc private func selectWorkWeekMode() {
134+
currentMode = .workWeek
135+
updateMenuCheckmarks()
136+
updateProgress()
137+
}
138+
124139
@objc private func selectDayMode() {
125140
currentMode = .day
126141
updateMenuCheckmarks()
127142
updateProgress()
128143
}
129144

130145
@objc private func selectCustomMode() {
131-
132-
if let _ = customStartDate, let _ = customEndDate {
146+
if let _ = customEndDate {
133147
currentMode = .custom
134148
updateMenuCheckmarks()
135149
updateProgress()
136150
} else {
137-
138151
configureCustomDates()
139152
}
140153
}
141154

142155
@objc private func configureCustomDates() {
143-
144156
let window = NSWindow(
145-
contentRect: NSRect(x: 0, y: 0, width: 400, height: 200),
157+
contentRect: NSRect(x: 0, y: 0, width: 400, height: 150),
146158
styleMask: [.titled, .closable],
147159
backing: .buffered,
148160
defer: false
149161
)
150-
window.title = "Configure Custom Dates"
162+
window.title = "Configure Custom End Date"
151163
window.center()
152164

153-
154-
let contentView = NSView(frame: NSRect(x: 0, y: 0, width: 400, height: 200))
155-
156-
157-
let startLabel = NSTextField(labelWithString: "Start Date:")
158-
startLabel.frame = NSRect(x: 20, y: 160, width: 100, height: 20)
159-
contentView.addSubview(startLabel)
160-
161-
162-
let startDatePicker = NSDatePicker()
163-
startDatePicker.datePickerStyle = .textField
164-
startDatePicker.datePickerMode = .single
165-
startDatePicker.frame = NSRect(x: 130, y: 160, width: 200, height: 20)
166-
if let startDate = customStartDate {
167-
startDatePicker.dateValue = startDate
168-
} else {
169-
startDatePicker.dateValue = Date()
170-
}
171-
contentView.addSubview(startDatePicker)
172-
165+
let contentView = NSView(frame: NSRect(x: 0, y: 0, width: 400, height: 150))
173166

174167
let endLabel = NSTextField(labelWithString: "End Date:")
175-
endLabel.frame = NSRect(x: 20, y: 120, width: 100, height: 20)
168+
endLabel.frame = NSRect(x: 20, y: 100, width: 100, height: 20)
176169
contentView.addSubview(endLabel)
177170

178-
179171
let endDatePicker = NSDatePicker()
180172
endDatePicker.datePickerStyle = .textField
181173
endDatePicker.datePickerMode = .single
182-
endDatePicker.frame = NSRect(x: 130, y: 120, width: 200, height: 20)
174+
endDatePicker.frame = NSRect(x: 130, y: 100, width: 200, height: 20)
183175
if let endDate = customEndDate {
184176
endDatePicker.dateValue = endDate
185177
} else {
186-
187178
endDatePicker.dateValue = Calendar.current.date(byAdding: .year, value: 1, to: Date()) ?? Date()
188179
}
189180
contentView.addSubview(endDatePicker)
190181

191-
192-
let descLabel = NSTextField(wrappingLabelWithString: "Set start and end dates to track progress between them.")
193-
descLabel.frame = NSRect(x: 20, y: 80, width: 360, height: 30)
182+
let descLabel = NSTextField(wrappingLabelWithString: "Set an end date to track progress from today to that date.")
183+
descLabel.frame = NSRect(x: 20, y: 60, width: 360, height: 30)
194184
contentView.addSubview(descLabel)
195185

196-
197186
let saveButton = NSButton(title: "Save", target: nil, action: nil)
198187
saveButton.frame = NSRect(x: 280, y: 20, width: 100, height: 32)
199188
saveButton.bezelStyle = .rounded
200189
saveButton.keyEquivalent = "\r"
201190

202-
203191
saveButton.target = self
204192
saveButton.action = #selector(saveCustomDates(_:))
205193

206-
207-
objc_setAssociatedObject(saveButton, UnsafeRawPointer(bitPattern: 1)!, startDatePicker, .OBJC_ASSOCIATION_RETAIN)
208194
objc_setAssociatedObject(saveButton, UnsafeRawPointer(bitPattern: 2)!, endDatePicker, .OBJC_ASSOCIATION_RETAIN)
209195
objc_setAssociatedObject(saveButton, UnsafeRawPointer(bitPattern: 3)!, window, .OBJC_ASSOCIATION_RETAIN)
210196

211197
contentView.addSubview(saveButton)
212198

213-
214199
let cancelButton = NSButton(title: "Cancel", target: nil, action: nil)
215200
cancelButton.frame = NSRect(x: 170, y: 20, width: 100, height: 32)
216201
cancelButton.bezelStyle = .rounded
@@ -225,41 +210,31 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
225210
}
226211

227212
@objc private func saveCustomDates(_ sender: NSButton) {
228-
229-
guard let startDatePicker = objc_getAssociatedObject(sender, UnsafeRawPointer(bitPattern: 1)!) as? NSDatePicker,
230-
let endDatePicker = objc_getAssociatedObject(sender, UnsafeRawPointer(bitPattern: 2)!) as? NSDatePicker,
213+
guard let endDatePicker = objc_getAssociatedObject(sender, UnsafeRawPointer(bitPattern: 2)!) as? NSDatePicker,
231214
let window = objc_getAssociatedObject(sender, UnsafeRawPointer(bitPattern: 3)!) as? NSWindow else {
232215
return
233216
}
234217

235-
let startDate = startDatePicker.dateValue
236218
let endDate = endDatePicker.dateValue
237219

238-
239-
if startDate >= endDate {
220+
if Date() >= endDate {
240221
let alert = NSAlert()
241-
alert.messageText = "Invalid Date Range"
242-
alert.informativeText = "The start date must be before the end date."
222+
alert.messageText = "Invalid Date"
223+
alert.informativeText = "The end date must be in the future."
243224
alert.alertStyle = .warning
244225
alert.addButton(withTitle: "OK")
245226
alert.beginSheetModal(for: window, completionHandler: nil)
246227
return
247228
}
248229

249-
250-
customStartDate = startDate
251230
customEndDate = endDate
252231

253-
254-
UserDefaults.standard.set(startDate, forKey: customStartDateKey)
255232
UserDefaults.standard.set(endDate, forKey: customEndDateKey)
256233

257-
258234
currentMode = .custom
259235
updateMenuCheckmarks()
260236
updateProgress()
261237

262-
263238
window.close()
264239
}
265240

@@ -270,15 +245,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
270245
}
271246

272247
private func startTimer() {
273-
274248
updateTimer?.invalidate()
275249

276-
277250
updateTimer = Timer.scheduledTimer(withTimeInterval: 60.0, repeats: true) { [weak self] _ in
278251
self?.updateProgress()
279252
}
280253

281-
282254
RunLoop.current.add(updateTimer!, forMode: .common)
283255
}
284256

@@ -318,9 +290,45 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
318290
progress = Double(calendar.dateComponents([.second], from: startOfMonth, to: now).second!) /
319291
Double(calendar.dateComponents([.second], from: startOfMonth, to: endOfMonth).second!) * 100
320292

321-
dateFormatter.dateFormat = "MMM"
293+
dateFormatter.dateFormat = "MMMM"
322294
displayText = "of \(dateFormatter.string(from: now))"
323295

296+
case .week:
297+
let weekday = calendar.component(.weekday, from: now)
298+
let daysToSubtract = weekday - calendar.firstWeekday
299+
let startOfWeek = calendar.date(byAdding: .day, value: -daysToSubtract, to: calendar.startOfDay(for: now))!
300+
let endOfWeek = calendar.date(byAdding: .day, value: 7, to: startOfWeek)!
301+
302+
progress = Double(calendar.dateComponents([.second], from: startOfWeek, to: now).second!) /
303+
Double(calendar.dateComponents([.second], from: startOfWeek, to: endOfWeek).second!) * 100
304+
305+
let weekOfYear = calendar.component(.weekOfYear, from: now)
306+
displayText = "Week \(weekOfYear)"
307+
308+
case .workWeek:
309+
let weekday = calendar.component(.weekday, from: now)
310+
311+
312+
if weekday == 1 || weekday == 7 {
313+
progress = 100.0
314+
displayText = "Weekend!"
315+
} else {
316+
317+
var daysToSubtract = weekday - 2
318+
if daysToSubtract < 0 {
319+
daysToSubtract += 7
320+
}
321+
322+
let startOfWorkWeek = calendar.date(byAdding: .day, value: -daysToSubtract, to: calendar.startOfDay(for: now))!
323+
let endOfWorkWeek = calendar.date(byAdding: .day, value: 5, to: startOfWorkWeek)!
324+
325+
progress = Double(calendar.dateComponents([.second], from: startOfWorkWeek, to: now).second!) /
326+
Double(calendar.dateComponents([.second], from: startOfWorkWeek, to: endOfWorkWeek).second!) * 100
327+
328+
let weekOfYear = calendar.component(.weekOfYear, from: now)
329+
displayText = "Week \(weekOfYear)"
330+
}
331+
324332
case .day:
325333
let startOfDay = calendar.date(from: calendar.dateComponents([.year, .month, .day], from: now))!
326334
let endOfDay = calendar.date(byAdding: DateComponents(day: 1), to: startOfDay)!
@@ -330,36 +338,28 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
330338
displayText = "of Today"
331339

332340
case .custom:
333-
if let start = customStartDate, let end = customEndDate {
334-
335-
let totalDuration = calendar.dateComponents([.second], from: start, to: end).second!
336-
let elapsedDuration = calendar.dateComponents([.second], from: start, to: now).second!
341+
if let end = customEndDate {
342+
let start = Date()
337343

338-
339-
if now < start {
340-
progress = 0
341-
} else if now > end {
344+
if start > end {
342345
progress = 100
343346
} else {
344-
progress = Double(elapsedDuration) / Double(totalDuration) * 100
347+
progress = 0
345348
}
346349

347-
348350
dateFormatter.dateFormat = "MMM d, yyyy"
349-
displayText = "\(dateFormatter.string(from: start)) - \(dateFormatter.string(from: end))"
351+
displayText = "until \(dateFormatter.string(from: end))"
350352
} else {
351353
progress = 0
352354
displayText = "Custom (not set)"
353355
}
354356
}
355357

356358
if let button = statusItem.button {
357-
358359
let roundedProgress = Int(round(progress / 5.0) * 5)
359360
let imageName = String(format: "gauge%02d", roundedProgress)
360361

361362
if let originalImage = NSImage(named: imageName) {
362-
363363
let resizedImage = NSImage(size: NSSize(width: 18, height: 18))
364364
resizedImage.lockFocus()
365365
originalImage.size = NSSize(width: 18, height: 18)
@@ -378,6 +378,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
378378
private func updateMenuCheckmarks() {
379379
yearMenuItem?.state = currentMode == .year ? .on : .off
380380
monthMenuItem?.state = currentMode == .month ? .on : .off
381+
weekMenuItem?.state = currentMode == .week ? .on : .off
382+
workWeekMenuItem?.state = currentMode == .workWeek ? .on : .off
381383
dayMenuItem?.state = currentMode == .day ? .on : .off
382384
customMenuItem?.state = currentMode == .custom ? .on : .off
383385
}
@@ -399,7 +401,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
399401
}
400402

401403
func applicationWillTerminate(_ notification: Notification) {
402-
403404
updateTimer?.invalidate()
404405
}
405406
}

0 commit comments

Comments
 (0)