Skip to content

Commit 52274dd

Browse files
committed
Add time-based color coding to countdown text in status bar
Color the countdown timer text (e.g. "in 5m") based on time remaining until the next meeting: green >=15min, yellow >=5min, red <5min. Works in both inline and under-title display modes. Controlled by a new toggle in Preferences > Appearance > Status Bar, off by default.
1 parent 6a088d3 commit 52274dd

4 files changed

Lines changed: 40 additions & 10 deletions

File tree

MeetingBar/Extensions/DefaultsKeys.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ extension Defaults.Keys {
4242
static let statusbarEventTitleLength = Key<Int>("statusbarEventTitleLength", default: statusbarEventTitleLengthLimits.max)
4343

4444
static let hideMeetingTitle = Key<Bool>("hideMeetingTitle", default: false)
45+
static let timeBasedStatusBarColor = Key<Bool>("timeBasedStatusBarColor", default: false)
4546
static let dismissedEvents = Key<[ProcessedEvent]>("dismissedEvents", default: [])
4647

4748
static let ongoingEventVisibility = Key<OngoingEventVisibility>("ongoingEventVisibility", default: .showTenMinBeforeNext)

MeetingBar/Resources /Localization /en.lproj/Localizable.strings

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
"preferences_appearance_status_bar_ongoing_time_immediate_value" = "hide after start";
102102
"preferences_appearance_status_bar_ongoing_time_ten_after_value" = "hide 10 min after start";
103103
"preferences_appearance_status_bar_ongoing_time_ten_before_next_value" = "hide 10 min before next event";
104+
"preferences_appearance_status_bar_time_color_toggle" = "Color countdown by time remaining";
104105
"preferences_appearance_status_bar_next_event_toggle" = "Show only events starting within";
105106
"preferences_appearance_status_bar_next_event_stepper" = "%d minutes";
106107
"preferences_appearance_menu_title" = "Menu";

MeetingBar/UI/StatusBar/StatusBarItemController.swift

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ final class StatusBarItemController {
7171
.timeFormat, .bookmarks, .eventTitleFormat,
7272
.personalEventsAppereance, .pastEventsAppereance,
7373
.declinedEventsAppereance, .ongoingEventVisibility,
74-
.showTimelineInMenu,
74+
.showTimelineInMenu, .timeBasedStatusBarColor,
7575
options: []
7676
)
7777
.receive(on: DispatchQueue.main)
@@ -258,11 +258,6 @@ final class StatusBarItemController {
258258
let menuTitle = NSMutableAttributedString()
259259

260260
if Defaults[.eventTimeFormat] != .show_under_title || Defaults[.eventTitleFormat] == .none {
261-
var eventTitle = title
262-
if Defaults[.eventTimeFormat] == .show {
263-
eventTitle += " " + time
264-
}
265-
266261
var styles = [NSAttributedString.Key: Any]()
267262
styles[NSAttributedString.Key.font] = NSFont.systemFont(ofSize: MenuStyleConstants.defaultFontSize)
268263

@@ -274,7 +269,15 @@ final class StatusBarItemController {
274269
styles[NSAttributedString.Key.underlineStyle] = NSUnderlineStyle.single.rawValue | NSUnderlineStyle.patternDot.rawValue | NSUnderlineStyle.byWord.rawValue
275270
}
276271

277-
menuTitle.append(NSAttributedString(string: eventTitle, attributes: styles))
272+
menuTitle.append(NSAttributedString(string: title, attributes: styles))
273+
274+
if Defaults[.eventTimeFormat] == .show, !time.isEmpty {
275+
var timeStyles = styles
276+
if Defaults[.timeBasedStatusBarColor] {
277+
timeStyles[NSAttributedString.Key.foregroundColor] = countdownColor(for: nextEvent)
278+
}
279+
menuTitle.append(NSAttributedString(string: " " + time, attributes: timeStyles))
280+
}
278281
} else {
279282
let paragraphStyle = NSMutableParagraphStyle()
280283
paragraphStyle.lineHeightMultiple = 0.7
@@ -298,9 +301,10 @@ final class StatusBarItemController {
298301

299302
menuTitle.append(NSAttributedString(string: title, attributes: styles))
300303

301-
let timeAttributes = [
302-
NSAttributedString.Key.font: NSFont.systemFont(ofSize: 9),
303-
NSAttributedString.Key.foregroundColor: NSColor.lightGray
304+
let timeColor: NSColor = Defaults[.timeBasedStatusBarColor] ? countdownColor(for: nextEvent) : .lightGray
305+
let timeAttributes: [NSAttributedString.Key: Any] = [
306+
.font: NSFont.systemFont(ofSize: 9),
307+
.foregroundColor: timeColor
304308
]
305309
menuTitle.append(NSAttributedString(string: "\n" + time, attributes: timeAttributes))
306310

@@ -536,6 +540,24 @@ func shortenTitle(title: String?, offset: Int) -> String {
536540
return eventTitle
537541
}
538542

543+
func countdownColor(for event: MBEvent) -> NSColor {
544+
let now = Date()
545+
let timeRemaining: TimeInterval
546+
if event.startDate <= now, event.endDate > now {
547+
timeRemaining = event.endDate.timeIntervalSinceNow
548+
} else {
549+
timeRemaining = event.startDate.timeIntervalSinceNow
550+
}
551+
552+
if timeRemaining >= 15 * 60 {
553+
return .systemGreen
554+
} else if timeRemaining >= 5 * 60 {
555+
return .systemYellow
556+
} else {
557+
return .systemRed
558+
}
559+
}
560+
539561
func createEventStatusString(title: String, startDate: Date, endDate: Date) -> (String, String) {
540562
var eventTime: String
541563

MeetingBar/UI/Views/Preferences/AppearanceTab.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ struct StatusBarSection: View {
149149
@Default(.showEventMaxTimeUntilEventThreshold) var showEventMaxTimeUntilEventThreshold
150150
@Default(.showEventMaxTimeUntilEventEnabled) var showEventMaxTimeUntilEventEnabled
151151
@Default(.ongoingEventVisibility) var ongoingEventVisibility
152+
@Default(.timeBasedStatusBarColor) var timeBasedStatusBarColor
152153

153154
var body: some View {
154155
GroupBox(label: Label("preferences_appearance_status_bar_title".loco(), systemImage: "menubar.rectangle")) {
@@ -236,6 +237,11 @@ struct StatusBarSection: View {
236237
)
237238
.disabled(!showEventMaxTimeUntilEventEnabled)
238239
}
240+
Toggle(
241+
"preferences_appearance_status_bar_time_color_toggle".loco(),
242+
isOn: $timeBasedStatusBarColor
243+
)
244+
239245
Picker("preferences_appearance_status_bar_ongoing_title".loco(), selection: $ongoingEventVisibility) {
240246
Text("preferences_appearance_status_bar_ongoing_time_immediate_value".loco()).tag(
241247
OngoingEventVisibility.hideImmediateAfter)

0 commit comments

Comments
 (0)