Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions boringNotch/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -1805,6 +1805,23 @@
}
}
}
},
"Alternative calendars" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Alternative calendars"
}
}
}
},
"Always alternate" : {

},
"Always default" : {

},
"Always show full event titles" : {
"localizations" : {
Expand Down Expand Up @@ -3412,6 +3429,17 @@
}
}
},
"Calendar subtitle display" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Calendar subtitle display"
}
}
}
},
"Calendars" : {
"localizations" : {
"ar" : {
Expand Down Expand Up @@ -10647,6 +10675,9 @@
}
}
}
},
"Lunar" : {

},
"Made with 🫶🏻 by not so boring not.people" : {
"localizations" : {
Expand Down Expand Up @@ -13561,6 +13592,9 @@
}
}
}
},
"Now Playing" : {

},
"Open Calendar Settings" : {
"localizations" : {
Expand Down Expand Up @@ -19000,6 +19034,9 @@
}
}
}
},
"Tap to switch" : {

},
"Time to Full Charge: %lld min" : {
"localizations" : {
Expand Down
54 changes: 53 additions & 1 deletion boringNotch/components/Calendar/BoringCalendar.swift
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This view should be refactored. It shouldn't have the hidden view for sizing in a ZStack and it should probably use the .headline font for lunar to keep its characters a similar size to the year.

Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,34 @@ struct CalendarView: View {
@EnvironmentObject var vm: BoringViewModel
@ObservedObject private var calendarManager = CalendarManager.shared
@State private var selectedDate = Date()
@Default(.calendarSubtitleDisplayMode) var displayMode
@Default(.alternativeCalendar) var alternativeCalendar
@Default(.calendarIsShowingAlternate) var isShowingAlternate

private var shouldShowAlternate: Bool {
switch displayMode {
case .alwaysDefault:
return false
case .alwaysAlternate:
return true
case .tapToSwitch:
return isShowingAlternate
}
}

// A hidden view strictly for sizing
private func subtitleSizingView(date: Date) -> some View {
ZStack {
Text(date.formatted(.dateTime.year()))
switch alternativeCalendar {
case .lunar:
Text(date.formatted(.dateTime.lunar()))
}
}
.font(.title3)
.fontWeight(.light)
.fixedSize() // Ensure it takes up its natural calculated size
}

var body: some View {
VStack(spacing: 0) {
Expand All @@ -242,10 +270,34 @@ struct CalendarView: View {
.font(.title3)
.fontWeight(.semibold)
.foregroundColor(.white)
Text(selectedDate.formatted(.dateTime.year()))

ZStack(alignment: .leading) {
// Invisible layer to reserve space for the widest possible content
subtitleSizingView(date: selectedDate)
.hidden()

// Visible content
Group {
if shouldShowAlternate {
switch alternativeCalendar {
case .lunar:
Text(selectedDate.formatted(.dateTime.lunar()))
}
} else {
Text(selectedDate.formatted(.dateTime.year()))
}
}
.font(.title3)
.fontWeight(.light)
.foregroundColor(Color(white: 0.65))
.onTapGesture {
if displayMode == .tapToSwitch {
withAnimation(.smooth(duration: 0.2)) {
isShowingAlternate.toggle()
}
}
}
}
}

ZStack(alignment: .top) {
Expand Down
19 changes: 19 additions & 0 deletions boringNotch/components/Settings/Views/CalendarSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ struct CalendarSettings: View {
@Default(.hideCompletedReminders) var hideCompletedReminders
@Default(.hideAllDayEvents) var hideAllDayEvents
@Default(.autoScrollToNextEvent) var autoScrollToNextEvent
@Default(.calendarSubtitleDisplayMode) var calendarSubtitleDisplayMode
@Default(.alternativeCalendar) var alternativeCalendar

var body: some View {
Form {
Expand All @@ -33,6 +35,23 @@ struct CalendarSettings: View {
Defaults.Toggle(key: .showFullEventTitles) {
Text("Always show full event titles")
}

Picker("Calendar subtitle display", selection: $calendarSubtitleDisplayMode) {
ForEach(CalendarSubtitleDisplayMode.allCases) { item in
Text(item.localizedString).tag(item)
}
}
.pickerStyle(.menu)

if calendarSubtitleDisplayMode != .alwaysDefault {
Picker("Alternative calendars", selection: $alternativeCalendar) {
ForEach(AlternativeCalendarType.allCases) { item in
Text(item.localizedString).tag(item)
}
}
.pickerStyle(.menu)
}

Section(header: Text("Calendars")) {
if calendarManager.calendarAuthorizationStatus != .fullAccess {
Text("Calendar access is denied. Please enable it in System Settings.")
Expand Down
25 changes: 25 additions & 0 deletions boringNotch/extensions/DataTypes+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,31 @@ extension Date {
}
}

struct LunarDateStyle: FormatStyle {
func format(_ value: Date) -> String {
let formatter = DateFormatter()
formatter.calendar = Foundation.Calendar(identifier: .chinese)
formatter.locale = Locale(identifier: "zh_CN")
formatter.dateStyle = .long
formatter.timeStyle = .none

let fullDate = formatter.string(from: value)

if let yearRange = fullDate.range(of: "年") {
let extracted = String(fullDate[yearRange.upperBound...])
return extracted
}

return fullDate
}
}
Comment on lines +45 to +62
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should avoid recreating this every time. I added a suggestion below that makes the formatter static and also should handle the formatting in a cleaner way.

Suggested change
struct LunarDateStyle: FormatStyle {
func format(_ value: Date) -> String {
let formatter = DateFormatter()
formatter.calendar = Foundation.Calendar(identifier: .chinese)
formatter.locale = Locale(identifier: "zh_CN")
formatter.dateStyle = .long
formatter.timeStyle = .none
let fullDate = formatter.string(from: value)
if let yearRange = fullDate.range(of: "") {
let extracted = String(fullDate[yearRange.upperBound...])
return extracted
}
return fullDate
}
}
struct LunarDateStyle: FormatStyle {
private static let formatter: DateFormatter = {
let f = DateFormatter()
f.calendar = Calendar(identifier: .chinese)
f.locale = Locale(identifier: "zh_CN")
f.dateStyle = .long
f.dateFormat = "MMMMd"
return f
}()
func format(_ value: Date) -> String {
Self.formatter.string(from: value)
}
}


extension Date.FormatStyle {
func lunar() -> LunarDateStyle {
LunarDateStyle()
}
}

extension NSSize {
var s: String { "\(width.i)×\(height.i)" }

Expand Down
36 changes: 36 additions & 0 deletions boringNotch/models/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,38 @@ enum OSDControlSource: String, CaseIterable, Identifiable, Defaults.Serializable
}
}

enum CalendarSubtitleDisplayMode: String, CaseIterable, Identifiable, Defaults.Serializable {
case alwaysDefault
case alwaysAlternate
case tapToSwitch

var id: String { self.rawValue }

var localizedString: String {
switch self {
case .alwaysDefault:
return NSLocalizedString("Always default", comment: "")
case .alwaysAlternate:
return NSLocalizedString("Always alternate", comment: "")
case .tapToSwitch:
return NSLocalizedString("Tap to switch", comment: "")
}
}
}

enum AlternativeCalendarType: String, CaseIterable, Identifiable, Defaults.Serializable {
case lunar = "Lunar"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change 'lunar' to 'Chinese.' The Chinese calendar is actually lunisolar, and 'lunar' is too ambiguous since several other calendars use the lunar or lunisolar system.


var id: String { self.rawValue }

var localizedString: String {
switch self {
case .lunar:
return NSLocalizedString("Lunar", comment: "")
}
}
}

extension Defaults.Keys {
// MARK: General
static let menubarIcon = Key<Bool>("menubarIcon", default: true)
Expand Down Expand Up @@ -242,6 +274,10 @@ extension Defaults.Keys {
static let showFullEventTitles = Key<Bool>("showFullEventTitles", default: false)
static let autoScrollToNextEvent = Key<Bool>("autoScrollToNextEvent", default: true)

static let calendarSubtitleDisplayMode = Key<CalendarSubtitleDisplayMode>("calendarSubtitleDisplayMode", default: .alwaysDefault)
static let alternativeCalendar = Key<AlternativeCalendarType>("alternativeCalendar", default: .lunar)
static let calendarIsShowingAlternate = Key<Bool>("calendarIsShowingAlternate", default: false)

// MARK: Fullscreen Media Detection
static let hideNotchOption = Key<HideNotchOption>("hideNotchOption", default: .nowPlayingOnly)

Expand Down