mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Update Notion Calendar
This commit is contained in:
parent
ab7d2619d7
commit
563afde92f
4 changed files with 110 additions and 20 deletions
|
|
@ -7231,6 +7231,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Calendar App" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Calendar or Reminder access is denied. Please enable it in System Settings." : {
|
"Calendar or Reminder access is denied. Please enable it in System Settings." : {
|
||||||
"comment" : "A message displayed when a user has denied access to the calendar or reminders on their device. It instructs the user to open System Settings to grant access.",
|
"comment" : "A message displayed when a user has denied access to the calendar or reminders on their device. It instructs the user to open System Settings to grant access.",
|
||||||
|
|
@ -14925,6 +14928,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Enable third-party calendar app launch" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Enable third-party DDC app integration" : {
|
"Enable third-party DDC app integration" : {
|
||||||
"comment" : "A toggle switch that enables or disables integration with a third-party Dynamic Display Control (DDC) app.",
|
"comment" : "A toggle switch that enables or disables integration with a third-party Dynamic Display Control (DDC) app.",
|
||||||
|
|
@ -35981,9 +35987,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"Use Fantastical" : {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"Use MacBook icon when on battery" : {
|
"Use MacBook icon when on battery" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
|
|
@ -37187,7 +37190,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"When enabled, clicking on calendar events will open Fantastical instead of Apple Calendar. More integrations coming soon." : {
|
"When enabled, clicking on calendar events will open the selected third-party calendar app instead of Apple Calendar." : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"When enabled, Focus appears briefly (on/off) and then collapses instead of staying visible." : {
|
"When enabled, Focus appears briefly (on/off) and then collapses instead of staying visible." : {
|
||||||
|
|
|
||||||
|
|
@ -2752,7 +2752,8 @@ struct CalendarSettings: View {
|
||||||
@Default(.lockScreenCalendarSelectionMode) private var lockScreenCalendarSelectionMode
|
@Default(.lockScreenCalendarSelectionMode) private var lockScreenCalendarSelectionMode
|
||||||
@Default(.lockScreenSelectedCalendarIDs) private var lockScreenSelectedCalendarIDs
|
@Default(.lockScreenSelectedCalendarIDs) private var lockScreenSelectedCalendarIDs
|
||||||
@Default(.lockScreenShowCalendarEventAfterStartEnabled) private var lockScreenShowCalendarEventAfterStartEnabled
|
@Default(.lockScreenShowCalendarEventAfterStartEnabled) private var lockScreenShowCalendarEventAfterStartEnabled
|
||||||
@Default(.useFantasticalCalendar) private var useFantasticalCalendar
|
@Default(.enableThirdPartyCalendarApp) private var enableThirdPartyCalendarApp
|
||||||
|
@Default(.selectedCalendarApp) private var selectedCalendarApp
|
||||||
@Default(.fantasticalDefaultView) private var fantasticalDefaultView
|
@Default(.fantasticalDefaultView) private var fantasticalDefaultView
|
||||||
|
|
||||||
private func highlightID(_ title: String) -> String {
|
private func highlightID(_ title: String) -> String {
|
||||||
|
|
@ -3050,28 +3051,37 @@ struct CalendarSettings: View {
|
||||||
|
|
||||||
// MARK: - Third-party Calendar Integration
|
// MARK: - Third-party Calendar Integration
|
||||||
Section {
|
Section {
|
||||||
Defaults.Toggle(key: .useFantasticalCalendar) {
|
Defaults.Toggle(key: .enableThirdPartyCalendarApp) {
|
||||||
HStack {
|
HStack {
|
||||||
Image(systemName: "calendar.badge.clock")
|
Image(systemName: selectedCalendarApp.iconName)
|
||||||
.foregroundColor(.red)
|
.foregroundColor(selectedCalendarApp.iconColor)
|
||||||
.frame(width: 20, height: 20)
|
.frame(width: 20, height: 20)
|
||||||
Text("Use Fantastical")
|
Text("Enable third-party calendar app launch")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.settingsHighlight(id: highlightID("Use Fantastical"))
|
.settingsHighlight(id: highlightID("Enable third-party calendar app launch"))
|
||||||
|
|
||||||
if useFantasticalCalendar {
|
if enableThirdPartyCalendarApp {
|
||||||
Picker("Default View", selection: $fantasticalDefaultView) {
|
Picker("Calendar App", selection: $selectedCalendarApp) {
|
||||||
ForEach(FantasticalViewStyle.allCases, id: \.self) { style in
|
ForEach(ThirdPartyCalendarApp.allCases) { app in
|
||||||
Text(style.displayName).tag(style)
|
Text(app.displayName).tag(app)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.settingsHighlight(id: highlightID("Fantastical Default View"))
|
.settingsHighlight(id: highlightID("Calendar App"))
|
||||||
|
|
||||||
|
if selectedCalendarApp == .fantastical {
|
||||||
|
Picker("Default View", selection: $fantasticalDefaultView) {
|
||||||
|
ForEach(FantasticalViewStyle.allCases, id: \.self) { style in
|
||||||
|
Text(style.displayName).tag(style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.settingsHighlight(id: highlightID("Fantastical Default View"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} header: {
|
} header: {
|
||||||
Text("Third-party Calendar Integration")
|
Text("Third-party Calendar Integration")
|
||||||
} footer: {
|
} footer: {
|
||||||
Text("When enabled, clicking on calendar events will open Fantastical instead of Apple Calendar. More integrations coming soon.")
|
Text("When enabled, clicking on calendar events will open the selected third-party calendar app instead of Apple Calendar.")
|
||||||
}
|
}
|
||||||
|
|
||||||
Section(header: Text("Select Calendars")) {
|
Section(header: Text("Select Calendars")) {
|
||||||
|
|
|
||||||
|
|
@ -268,6 +268,34 @@ enum FantasticalViewStyle: String, CaseIterable, Codable, Defaults.Serializable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ThirdPartyCalendarApp: String, CaseIterable, Codable, Defaults.Serializable, Identifiable {
|
||||||
|
case fantastical = "fantastical"
|
||||||
|
case notionCalendar = "notionCalendar"
|
||||||
|
|
||||||
|
var id: String { rawValue }
|
||||||
|
|
||||||
|
var displayName: String {
|
||||||
|
switch self {
|
||||||
|
case .fantastical: return "Fantastical"
|
||||||
|
case .notionCalendar: return "Notion Calendar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var iconName: String {
|
||||||
|
switch self {
|
||||||
|
case .fantastical: return "calendar.badge.clock"
|
||||||
|
case .notionCalendar: return "calendar.badge.plus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var iconColor: Color {
|
||||||
|
switch self {
|
||||||
|
case .fantastical: return .red
|
||||||
|
case .notionCalendar: return .blue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum ClipboardDisplayMode: String, CaseIterable, Codable, Defaults.Serializable {
|
enum ClipboardDisplayMode: String, CaseIterable, Codable, Defaults.Serializable {
|
||||||
case popover = "popover" // Traditional popover attached to button
|
case popover = "popover" // Traditional popover attached to button
|
||||||
case panel = "panel" // Floating panel near notch
|
case panel = "panel" // Floating panel near notch
|
||||||
|
|
@ -867,7 +895,8 @@ extension Defaults.Keys {
|
||||||
static let lockScreenWeatherWidgetRowOrder = Key<String>("lockScreenWeatherWidgetRowOrder", default: "weather_calendar_focus")
|
static let lockScreenWeatherWidgetRowOrder = Key<String>("lockScreenWeatherWidgetRowOrder", default: "weather_calendar_focus")
|
||||||
|
|
||||||
// MARK: Third-party Calendar Integration
|
// MARK: Third-party Calendar Integration
|
||||||
static let useFantasticalCalendar = Key<Bool>("useFantasticalCalendar", default: false)
|
static let enableThirdPartyCalendarApp = Key<Bool>("enableThirdPartyCalendarApp", default: false)
|
||||||
|
static let selectedCalendarApp = Key<ThirdPartyCalendarApp>("selectedCalendarApp", default: .fantastical)
|
||||||
static let fantasticalDefaultView = Key<FantasticalViewStyle>("fantasticalDefaultView", default: .mini)
|
static let fantasticalDefaultView = Key<FantasticalViewStyle>("fantasticalDefaultView", default: .mini)
|
||||||
|
|
||||||
// MARK: Battery
|
// MARK: Battery
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Defaults
|
import Defaults
|
||||||
|
import AppKit
|
||||||
|
|
||||||
struct EventModel: Equatable, Identifiable {
|
struct EventModel: Equatable, Identifiable {
|
||||||
let id: String
|
let id: String
|
||||||
|
|
@ -98,9 +99,14 @@ extension EventModel {
|
||||||
var isMeeting: Bool { !participants.isEmpty }
|
var isMeeting: Bool { !participants.isEmpty }
|
||||||
|
|
||||||
func calendarAppURL() -> URL? {
|
func calendarAppURL() -> URL? {
|
||||||
// Check if Fantastical is enabled
|
// Check if a third-party calendar app is enabled
|
||||||
if Defaults[.useFantasticalCalendar] {
|
if Defaults[.enableThirdPartyCalendarApp] {
|
||||||
return fantasticalURL()
|
switch Defaults[.selectedCalendarApp] {
|
||||||
|
case .fantastical:
|
||||||
|
return fantasticalURL()
|
||||||
|
case .notionCalendar:
|
||||||
|
return notionCalendarURL()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return appleCalendarURL()
|
return appleCalendarURL()
|
||||||
}
|
}
|
||||||
|
|
@ -160,6 +166,48 @@ extension EventModel {
|
||||||
}
|
}
|
||||||
return URL(string: "x-fantastical3://show/\(viewStyle.rawValue)")
|
return URL(string: "x-fantastical3://show/\(viewStyle.rawValue)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns URL to open event in Notion Calendar (formerly Cron)
|
||||||
|
private func notionCalendarURL() -> URL? {
|
||||||
|
// Reminders still use Apple's Reminders app
|
||||||
|
guard !type.isReminder else {
|
||||||
|
return URL(string: "x-apple-reminderkit://remcdreminder/\(id)")
|
||||||
|
}
|
||||||
|
|
||||||
|
let formatter = ISO8601DateFormatter()
|
||||||
|
|
||||||
|
var components = URLComponents()
|
||||||
|
components.scheme = "cron"
|
||||||
|
components.host = "showEvent"
|
||||||
|
components.queryItems = [
|
||||||
|
URLQueryItem(name: "accountEmail", value: calendar.accountName),
|
||||||
|
URLQueryItem(name: "iCalUID", value: id),
|
||||||
|
URLQueryItem(name: "startDate", value: formatter.string(from: start)),
|
||||||
|
URLQueryItem(name: "endDate", value: formatter.string(from: end)),
|
||||||
|
URLQueryItem(name: "title", value: title)
|
||||||
|
]
|
||||||
|
|
||||||
|
if let url = components.url {
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: just launch Notion Calendar app
|
||||||
|
Self.launchNotionCalendar()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Launches Notion Calendar app directly (fallback or general access)
|
||||||
|
static func launchNotionCalendar() {
|
||||||
|
// Launch via bundle identifier (Notion Calendar's bundle ID is "com.cron.electron")
|
||||||
|
if let url = NSWorkspace.shared.urlForApplication(withBundleIdentifier: "com.cron.electron") {
|
||||||
|
let config = NSWorkspace.OpenConfiguration()
|
||||||
|
NSWorkspace.shared.openApplication(at: url, configuration: config) { _, error in
|
||||||
|
if let error = error {
|
||||||
|
print("Error launching Notion Calendar: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Participant: Hashable {
|
struct Participant: Hashable {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue