Skip to content

Commit

Permalink
Merge pull request #4 from a11rew/fix/send-notifications-prior-to-act…
Browse files Browse the repository at this point in the history
…ivation

Add support for filtering for events from specific calendars
  • Loading branch information
a11rew authored May 18, 2024
2 parents 700f5c0 + 366c073 commit 28ae03b
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 14 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Calendar Focus Sync

## 0.6

- Add support for filtering for events from specific calendars
- Fixes issue with triggering focus in MacOS 14.4
8 changes: 4 additions & 4 deletions Calendar Focus Sync.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@
CODE_SIGN_ENTITLEMENTS = "Calendar Focus Sync/Calendar_Focus_Sync.entitlements";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 3;
CURRENT_PROJECT_VERSION = 5;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = UP7DQ4WSUA;
ENABLE_PREVIEWS = YES;
Expand All @@ -515,7 +515,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 0.4;
MARKETING_VERSION = 0.6;
PRODUCT_BUNDLE_IDENTIFIER = "com.andrewglago.Calendar-Focus-Sync";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand All @@ -533,7 +533,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 4;
CURRENT_PROJECT_VERSION = 5;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = UP7DQ4WSUA;
ENABLE_HARDENED_RUNTIME = YES;
Expand All @@ -548,7 +548,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 0.5;
MARKETING_VERSION = 0.6;
PRODUCT_BUNDLE_IDENTIFIER = "com.andrewglago.Calendar-Focus-Sync";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand Down
16 changes: 16 additions & 0 deletions Calendar Focus Sync/RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
### Internal Release Process

1. Bump `CURRENT_PROJECT_VERSION` and `MARKETING_VERSION` in `Calendar Focus Sync.xcodeproj/project.pbxproj` to the new version number.
2. Update the `CHANGELOG.md` with the new version number and changes.
3. In XCode, Product > Archive, then Distribute App > App Store Connect > Upload

## Direct Distribution

1. In XCode, Product > Archive, then Distribute App > Custom > Copy App
2. Use [create-dmg](https://github.com/sindresorhus/create-dmg) to create a DMG file for distribution

```
create-dmg Calendar\ Focus\ Sync.app/
```

3. Upload the DMG file to GitHub Releases
4 changes: 4 additions & 0 deletions Calendar Focus Sync/Services/CalendarSync.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ class NativeCalendarSync: CalendarSyncer {
// Declare event fetch parameters
// TODO: Filter for specific calendars
let calendars = store.calendars(for: .event)
// Exclude excluded calendars
.filter { calendar in
!UserPreferences.shared.excludedCalendarIds.contains(calendar.calendarIdentifier)
}

// Fetch events
let predicate = store.predicateForEvents(withStart: syncFilter.startDate, end: syncFilter.endDate, calendars: calendars)
Expand Down
1 change: 1 addition & 0 deletions Calendar Focus Sync/Services/SyncOrchestrator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class SyncOrchestrator {
func go() async {
Task { @MainActor in
AppState.shared.calendarEvents = await syncCalendarEvents()
AppState.shared.calendars = store.calendars(for: .event)
}
}

Expand Down
3 changes: 3 additions & 0 deletions Calendar Focus Sync/State/AppState.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import Foundation
import Combine
import EventKit

class AppState: ObservableObject {
static let shared = AppState()

@Published var isShortCutInstalled: Bool = false
@Published var calendarEvents: [CalendarEvent] = []
@Published var calendars: [EKCalendar] = []


init() {
self.isShortCutInstalled = isShortcutInstalled()
Expand Down
27 changes: 26 additions & 1 deletion Calendar Focus Sync/State/UserPreferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,44 @@ class UserPreferences: ObservableObject {
@Published var notificationsAccessGranted: Bool {
didSet {
defaults.set(notificationsAccessGranted, forKey: "notificationsAccessGranted")

Task {
if nativeCalendarAccessGranted {
await SyncOrchestrator.shared.go()
}
}
}
}


@Published var selectedPriorTimeBuffer: Int {
didSet {
defaults.set(selectedPriorTimeBuffer, forKey: "selectedPriorTimeBuffer")

Task {
if nativeCalendarAccessGranted {
await SyncOrchestrator.shared.go()
}
}
}
}


@Published var excludedCalendarIds: [String] = [] {
didSet {
defaults.set(excludedCalendarIds, forKey: "excludedCalendarIds")

Task {
if nativeCalendarAccessGranted {
await SyncOrchestrator.shared.go()
}
}
}
}

init() {
self.nativeCalendarAccessGranted = EKEventStore.authorizationStatus(for: .event) == .fullAccess
self.selectedPriorTimeBuffer = defaults.integer(forKey: "selectedPriorTimeBuffer") != 0 ? defaults.integer(forKey: "selectedPriorTimeBuffer") : 5
self.notificationsAccessGranted = defaults.bool(forKey: "notificationsAccessGranted")
self.excludedCalendarIds = defaults.object(forKey: "excludedCalendarIds") as? [String] ?? []
}
}
75 changes: 66 additions & 9 deletions Calendar Focus Sync/Views/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ struct SettingsView: View {
@EnvironmentObject var userPreferences: UserPreferences
@EnvironmentObject var appState: AppState


@State private var isExpanded = false
@State private var isRequestingCalendarPermissions = false

private var sortedCalendars: [EKCalendar] {
appState.calendars.sorted { $0.title < $1.title }
}

var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 20) {
Expand All @@ -25,23 +31,49 @@ struct SettingsView: View {
}
}


@ViewBuilder
private var CalendarConfigView: some View {
VStack(alignment: .leading) {
Text("Calendars")

VStack {
HStack {
Text("Apple Calendar")
Spacer()

Button(userPreferences.nativeCalendarAccessGranted
? "Granted" : "Grant Calendar Access"
) {
requestCalendarPermissions()
DisclosureGroup(isExpanded: $isExpanded) {
VStack(spacing: 8) {
ForEach(sortedCalendars, id: \.calendarIdentifier) { calendar in
HStack {
Text(calendar.title)
Spacer()
Toggle("", isOn: Binding(
get: { !userPreferences.excludedCalendarIds.contains(calendar.calendarIdentifier) },
set: { isExcluded in
if !isExcluded {
userPreferences.excludedCalendarIds.append(calendar.calendarIdentifier)
} else {
userPreferences.excludedCalendarIds.removeAll { $0 == calendar.calendarIdentifier }
}
}
))
.toggleStyle(.switch)
}
}
}
.padding(.vertical, 4)
} label: {
HStack {
Text("Apple Calendar")

Spacer()

Button(userPreferences.nativeCalendarAccessGranted
? "Granted" : "Grant Calendar Access"
) {
requestCalendarPermissions()
}
.disabled(isRequestingCalendarPermissions || userPreferences.nativeCalendarAccessGranted)
}
}
.disabled(isRequestingCalendarPermissions || userPreferences.nativeCalendarAccessGranted)
.disclosureGroupStyle(CalendarDisclosureStyle())
}
}
.padding(8)
Expand Down Expand Up @@ -131,3 +163,28 @@ struct SettingsViewPreview: PreviewProvider {
.environmentObject(appState)
}
}

struct CalendarDisclosureStyle: DisclosureGroupStyle {
func makeBody(configuration: Configuration) -> some View {
VStack(alignment: .leading) {
Button {
withAnimation {
configuration.isExpanded.toggle()
}
} label: {
HStack {
Image(systemName: configuration.isExpanded ? "chevron.up" : "chevron.down")
.foregroundColor(.accentColor)
.font(.caption)
.animation(nil, value: configuration.isExpanded)

configuration.label
}
}.buttonStyle(PlainButtonStyle())

if configuration.isExpanded {
configuration.content
}
}
}
}

0 comments on commit 28ae03b

Please sign in to comment.