Restore recent accounts and return from native browser sign-in
Reviewed by GPT-6 Astra. Add saved account switching, app URL handlers, and domain-based Store bundle identifiers. Both Mac and iOS signed build 4 archives and exports verified under Team Tito.
9 files changed,
+141
−70
native/apple/Package.resolved+13 −13native/apple/Package.swift+2 −2native/apple/Sources/CalendarApp/CalendarApp.swift+4 −4native/apple/Sources/CalendarKit/CalendarWorkspace.swift+3 −2native/ios/Info.plist+35 −0native/ios/project.yml+45 −31native/macos/CalendarMacStore.xcodeproj/project.pbxproj+5 −3native/macos/Info.plist+13 −0native/macos/project.yml+21 −15
CI passed — run details
diff --git a/native/apple/Package.resolved b/native/apple/Package.resolved| index 710f96c..cf50d40 100644 |
| --- a/native/apple/Package.resolved |
| +++ b/native/apple/Package.resolved |
| @@ -1,22 +1,22 @@ |
| { |
| - "pins": [ |
| + "pins" : [ |
| { |
| - "identity": "native", |
| - "kind": "remoteSourceControl", |
| - "location": "https://amadan.net/rastrillo/native", |
| - "state": { |
| - "revision": "4c61d6283a188c95647e1d0e609e69d29c2e7fa1" |
| + "identity" : "native", |
| + "kind" : "remoteSourceControl", |
| + "location" : "https://amadan.net/rastrillo/native", |
| + "state" : { |
| + "revision" : "229525909e1d6ac3b6a353d1c4d022798b0e9a24" |
| } |
| }, |
| { |
| - "identity": "sparkle", |
| - "kind": "remoteSourceControl", |
| - "location": "https://github.com/sparkle-project/Sparkle", |
| - "state": { |
| - "revision": "ac2def288cbff5cfc7df3ffef6abdf45b72bcb0a", |
| - "version": "2.9.6" |
| + "identity" : "sparkle", |
| + "kind" : "remoteSourceControl", |
| + "location" : "https://github.com/sparkle-project/Sparkle", |
| + "state" : { |
| + "revision" : "ac2def288cbff5cfc7df3ffef6abdf45b72bcb0a", |
| + "version" : "2.9.6" |
| } |
| } |
| ], |
| - "version": 2 |
| + "version" : 2 |
| } |
diff --git a/native/apple/Package.swift b/native/apple/Package.swift| index d2e6c1e..5c2847e 100644 |
| --- a/native/apple/Package.swift |
| +++ b/native/apple/Package.swift |
| @@ -2,8 +2,8 @@ |
| import PackageDescription |
| import Foundation |
| -let sharedNative: Package.Dependency = ProcessInfo.processInfo.environment["OFICINA_NATIVE_PACKAGE_PATH"].map { .package(path: $0) } |
| - ?? .package(url: "https://amadan.net/rastrillo/native", revision: "4c61d6283a188c95647e1d0e609e69d29c2e7fa1") |
| +let sharedNative: Package.Dependency = ProcessInfo.processInfo.environment["OFICINA_NATIVE_PACKAGE_PATH"].map { .package(name: "native", path: $0) } |
| + ?? .package(url: "https://amadan.net/rastrillo/native", revision: "229525909e1d6ac3b6a353d1c4d022798b0e9a24") |
| let package = Package(name: "CalendarNative", platforms: [.macOS(.v14), .iOS(.v17)], |
| products: [.library(name: "CalendarKit", targets: ["CalendarKit"]), .executable(name: "CalendarMac", targets: ["CalendarMac"])], |
diff --git a/native/apple/Sources/CalendarApp/CalendarApp.swift b/native/apple/Sources/CalendarApp/CalendarApp.swift| index f03a37e..78368d4 100644 |
| --- a/native/apple/Sources/CalendarApp/CalendarApp.swift |
| +++ b/native/apple/Sources/CalendarApp/CalendarApp.swift |
| @@ -19,11 +19,11 @@ import AppKit |
| WindowGroup("Calendar", id: "calendar") { |
| Group { |
| if let client = connection.client { |
| - CalendarWorkspace(client: client, model: model, signOut: { model.clear(); connection.signOut(); model = CalendarModel() }) |
| + CalendarWorkspace(client: client, model: model, accounts: { model.clear(); connection.showAccounts(); model = CalendarModel() }, signOut: { model.clear(); connection.signOut(); model = CalendarModel() }) |
| } else { |
| - NativeSignInView("Oficina Calendar", systemImage: "calendar", connection: connection) |
| + NativeAccountsView("Oficina Calendar", systemImage: "calendar", connection: connection) |
| } |
| - }.tint(Color(red: 0.78, green: 0.22, blue: 0.29)) |
| + }.id(connection.activeAccountID).onOpenURL(perform: connection.handleOpenURL).tint(Color(red: 0.78, green: 0.22, blue: 0.29)) |
| #if os(macOS) |
| .frame(minWidth: 780, minHeight: 650) |
| #endif |
| @@ -41,7 +41,7 @@ import AppKit |
| if let client = connection.client { |
| CalendarMenuView(client: client, model: model).tint(Color(red: 0.78, green: 0.22, blue: 0.29)) |
| } else { |
| - NativeSignInView("Oficina Calendar", systemImage: "calendar", connection: connection) |
| + NativeAccountsView("Oficina Calendar", systemImage: "calendar", connection: connection) |
| .frame(width: 380, height: 480) |
| } |
| }.menuBarExtraStyle(.window) |
diff --git a/native/apple/Sources/CalendarKit/CalendarWorkspace.swift b/native/apple/Sources/CalendarKit/CalendarWorkspace.swift| index 9bc5f0c..9c1a218 100644 |
| --- a/native/apple/Sources/CalendarKit/CalendarWorkspace.swift |
| +++ b/native/apple/Sources/CalendarKit/CalendarWorkspace.swift |
| @@ -4,6 +4,7 @@ import SwiftUI |
| @MainActor public struct CalendarWorkspace: View { |
| public let client: NativeHTTP |
| public let signOut: () -> Void |
| + private let accounts: (() -> Void)? |
| @StateObject private var model: CalendarModel |
| @State private var quickAdding = false |
| @State private var settings = false |
| @@ -14,7 +15,7 @@ import SwiftUI |
| @State private var column: NavigationSplitViewColumn = .detail |
| @Environment(\.dynamicTypeSize) private var typeSize |
| private let accent = Color(red: 0.78, green: 0.22, blue: 0.29) |
| - public init(client: NativeHTTP, model: CalendarModel? = nil, signOut: @escaping () -> Void) { self.client = client; self.signOut = signOut; _model = StateObject(wrappedValue: model ?? CalendarModel()) } |
| + public init(client: NativeHTTP, model: CalendarModel? = nil, accounts: (() -> Void)? = nil, signOut: @escaping () -> Void) { self.client = client; self.signOut = signOut; self.accounts = accounts; _model = StateObject(wrappedValue: model ?? CalendarModel()) } |
| public var body: some View { |
| NavigationSplitView(preferredCompactColumn: $column) { |
| @@ -32,7 +33,7 @@ import SwiftUI |
| Button("Settings", systemImage: "gear") { settings = true } |
| Button("Sign out", action: signOut) |
| } |
| - }.navigationTitle("Calendar").navigationSplitViewColumnWidth(min: 220, ideal: 260, max: 340) |
| + }.toolbar { if let accounts { ToolbarItem(placement: .navigation) { Button("Accounts", systemImage: "chevron.backward", action: accounts) } } }.navigationTitle("Calendar").navigationSplitViewColumnWidth(min: 220, ideal: 260, max: 340) |
| } detail: { |
| List { |
| Section { |
diff --git a/native/ios/Info.plist b/native/ios/Info.plist| new file mode 100644 |
| index 0000000..dee8168 |
| --- /dev/null |
| +++ b/native/ios/Info.plist |
| @@ -0,0 +1,35 @@ |
| +<?xml version="1.0" encoding="UTF-8"?> |
| +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
| +<plist version="1.0"> |
| +<dict> |
| + <key>CFBundleDevelopmentRegion</key> |
| + <string>$(DEVELOPMENT_LANGUAGE)</string> |
| + <key>CFBundleExecutable</key> |
| + <string>$(EXECUTABLE_NAME)</string> |
| + <key>CFBundleIdentifier</key> |
| + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> |
| + <key>CFBundleInfoDictionaryVersion</key> |
| + <string>6.0</string> |
| + <key>CFBundleName</key> |
| + <string>$(PRODUCT_NAME)</string> |
| + <key>CFBundlePackageType</key> |
| + <string>APPL</string> |
| + <key>CFBundleShortVersionString</key> |
| + <string>$(MARKETING_VERSION)</string> |
| + <key>CFBundleURLTypes</key> |
| + <array> |
| + <dict> |
| + <key>CFBundleTypeRole</key> |
| + <string>Editor</string> |
| + <key>CFBundleURLName</key> |
| + <string>works.oficina.calendar.signin</string> |
| + <key>CFBundleURLSchemes</key> |
| + <array> |
| + <string>works.oficina.calendar</string> |
| + </array> |
| + </dict> |
| + </array> |
| + <key>CFBundleVersion</key> |
| + <string>$(CURRENT_PROJECT_VERSION)</string> |
| +</dict> |
| +</plist> |
diff --git a/native/ios/project.yml b/native/ios/project.yml| index 4959bd1..247ba91 100644 |
| --- a/native/ios/project.yml |
| +++ b/native/ios/project.yml |
| @@ -8,64 +8,77 @@ packages: |
| path: ../apple |
| RastrilloNative: |
| url: https://amadan.net/rastrillo/native |
| - revision: 4c61d6283a188c95647e1d0e609e69d29c2e7fa1 |
| + revision: 229525909e1d6ac3b6a353d1c4d022798b0e9a24 |
| settings: |
| base: |
| SWIFT_VERSION: '5.0' |
| CODE_SIGN_STYLE: Automatic |
| - MARKETING_VERSION: '0.1.0' |
| + MARKETING_VERSION: 0.1.0 |
| CURRENT_PROJECT_VERSION: '1' |
| targets: |
| CalendarPhone: |
| type: application |
| platform: iOS |
| sources: |
| - - ../apple/Sources/CalendarApp |
| - - Assets.xcassets |
| - - path: ../LICENSE.lucide |
| - buildPhase: resources |
| - - path: ../PrivacyInfo.xcprivacy |
| - buildPhase: resources |
| + - ../apple/Sources/CalendarApp |
| + - Assets.xcassets |
| + - path: ../LICENSE.lucide |
| + buildPhase: resources |
| + - path: ../PrivacyInfo.xcprivacy |
| + buildPhase: resources |
| dependencies: |
| - - package: CalendarNative |
| - product: CalendarKit |
| - - package: RastrilloNative |
| - product: RastrilloApple |
| + - package: CalendarNative |
| + product: CalendarKit |
| + - package: RastrilloNative |
| + product: RastrilloApple |
| settings: |
| base: |
| ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon |
| - PRODUCT_BUNDLE_IDENTIFIER: net.amadan.oficina.calendar.ios |
| - TARGETED_DEVICE_FAMILY: '1,2' |
| - GENERATE_INFOPLIST_FILE: YES |
| + PROVISIONING_PROFILE_SPECIFIER: $(OFICINA_PROVISIONING_PROFILE) |
| + PRODUCT_BUNDLE_IDENTIFIER: works.oficina.calendar |
| + TARGETED_DEVICE_FAMILY: 1,2 |
| + GENERATE_INFOPLIST_FILE: true |
| INFOPLIST_KEY_CFBundleDisplayName: Oficina Calendar |
| - INFOPLIST_KEY_UILaunchScreen_Generation: YES |
| - INFOPLIST_KEY_UISupportedInterfaceOrientations: UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortraitUpsideDown |
| - |
| + INFOPLIST_KEY_UILaunchScreen_Generation: true |
| + INFOPLIST_KEY_UISupportedInterfaceOrientations: UIInterfaceOrientationPortrait |
| + UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight |
| + UIInterfaceOrientationPortraitUpsideDown |
| + info: |
| + path: Info.plist |
| + properties: |
| + CFBundleURLTypes: |
| + - CFBundleURLName: works.oficina.calendar.signin |
| + CFBundleURLSchemes: |
| + - works.oficina.calendar |
| + CFBundleTypeRole: Editor |
| + CFBundleShortVersionString: $(MARKETING_VERSION) |
| + CFBundleVersion: $(CURRENT_PROJECT_VERSION) |
| CalendarReviewPhone: |
| type: application |
| platform: iOS |
| - sources: [Review] |
| + sources: |
| + - Review |
| dependencies: |
| - - package: CalendarNative |
| - product: CalendarKit |
| - - package: RastrilloNative |
| - product: RastrilloApple |
| + - package: CalendarNative |
| + product: CalendarKit |
| + - package: RastrilloNative |
| + product: RastrilloApple |
| settings: |
| base: |
| PRODUCT_BUNDLE_IDENTIFIER: net.amadan.oficina.calendar.review |
| - TARGETED_DEVICE_FAMILY: '1,2' |
| - GENERATE_INFOPLIST_FILE: YES |
| - INFOPLIST_KEY_UILaunchScreen_Generation: YES |
| - |
| + TARGETED_DEVICE_FAMILY: 1,2 |
| + GENERATE_INFOPLIST_FILE: true |
| + INFOPLIST_KEY_UILaunchScreen_Generation: true |
| CalendarPhoneUITests: |
| type: bundle.ui-testing |
| platform: iOS |
| - sources: [UITests] |
| + sources: |
| + - UITests |
| dependencies: |
| - - target: CalendarReviewPhone |
| + - target: CalendarReviewPhone |
| settings: |
| base: |
| - GENERATE_INFOPLIST_FILE: YES |
| + GENERATE_INFOPLIST_FILE: true |
| TEST_TARGET_NAME: CalendarReviewPhone |
| schemes: |
| CalendarReviewPhone: |
| @@ -73,4 +86,5 @@ schemes: |
| targets: |
| CalendarReviewPhone: all |
| test: |
| - targets: [CalendarPhoneUITests] |
| + targets: |
| + - CalendarPhoneUITests |
diff --git a/native/macos/CalendarMacStore.xcodeproj/project.pbxproj b/native/macos/CalendarMacStore.xcodeproj/project.pbxproj| index c4368f0..7d85cf2 100644 |
| --- a/native/macos/CalendarMacStore.xcodeproj/project.pbxproj |
| +++ b/native/macos/CalendarMacStore.xcodeproj/project.pbxproj |
| @@ -180,7 +180,8 @@ |
| "$(inherited)", |
| "@executable_path/../Frameworks", |
| ); |
| - PRODUCT_BUNDLE_IDENTIFIER = net.amadan.oficina.calendar; |
| + PRODUCT_BUNDLE_IDENTIFIER = works.oficina.calendar; |
| + PROVISIONING_PROFILE_SPECIFIER = "$(OFICINA_PROVISIONING_PROFILE)"; |
| SDKROOT = macosx; |
| }; |
| name = Debug; |
| @@ -196,7 +197,8 @@ |
| "$(inherited)", |
| "@executable_path/../Frameworks", |
| ); |
| - PRODUCT_BUNDLE_IDENTIFIER = net.amadan.oficina.calendar; |
| + PRODUCT_BUNDLE_IDENTIFIER = works.oficina.calendar; |
| + PROVISIONING_PROFILE_SPECIFIER = "$(OFICINA_PROVISIONING_PROFILE)"; |
| SDKROOT = macosx; |
| }; |
| name = Release; |
| @@ -364,7 +366,7 @@ |
| repositoryURL = "https://amadan.net/rastrillo/native"; |
| requirement = { |
| kind = revision; |
| - revision = 4c61d6283a188c95647e1d0e609e69d29c2e7fa1; |
| + revision = 229525909e1d6ac3b6a353d1c4d022798b0e9a24; |
| }; |
| }; |
| /* End XCRemoteSwiftPackageReference section */ |
diff --git a/native/macos/Info.plist b/native/macos/Info.plist| index 9070ef0..dd46943 100644 |
| --- a/native/macos/Info.plist |
| +++ b/native/macos/Info.plist |
| @@ -20,6 +20,19 @@ |
| <string>APPL</string> |
| <key>CFBundleShortVersionString</key> |
| <string>$(MARKETING_VERSION)</string> |
| + <key>CFBundleURLTypes</key> |
| + <array> |
| + <dict> |
| + <key>CFBundleTypeRole</key> |
| + <string>Editor</string> |
| + <key>CFBundleURLName</key> |
| + <string>works.oficina.calendar.signin</string> |
| + <key>CFBundleURLSchemes</key> |
| + <array> |
| + <string>works.oficina.calendar</string> |
| + </array> |
| + </dict> |
| + </array> |
| <key>CFBundleVersion</key> |
| <string>$(CURRENT_PROJECT_VERSION)</string> |
| <key>LSApplicationCategoryType</key> |
diff --git a/native/macos/project.yml b/native/macos/project.yml| index d4fe807..f064a2e 100644 |
| --- a/native/macos/project.yml |
| +++ b/native/macos/project.yml |
| @@ -7,31 +7,31 @@ packages: |
| path: ../apple |
| RastrilloNative: |
| url: https://amadan.net/rastrillo/native |
| - revision: 4c61d6283a188c95647e1d0e609e69d29c2e7fa1 |
| + revision: 229525909e1d6ac3b6a353d1c4d022798b0e9a24 |
| settings: |
| base: |
| SWIFT_VERSION: '5.0' |
| CODE_SIGN_STYLE: Automatic |
| - MARKETING_VERSION: '0.1.0' |
| + MARKETING_VERSION: 0.1.0 |
| CURRENT_PROJECT_VERSION: '3' |
| - ENABLE_HARDENED_RUNTIME: YES |
| + ENABLE_HARDENED_RUNTIME: true |
| targets: |
| CalendarMacStore: |
| type: application |
| platform: macOS |
| sources: |
| - - ../apple/Sources/CalendarApp |
| - - path: AppIcon.icns |
| - buildPhase: resources |
| - - path: ../LICENSE.lucide |
| - buildPhase: resources |
| - - path: ../PrivacyInfo.xcprivacy |
| - buildPhase: resources |
| + - ../apple/Sources/CalendarApp |
| + - path: AppIcon.icns |
| + buildPhase: resources |
| + - path: ../LICENSE.lucide |
| + buildPhase: resources |
| + - path: ../PrivacyInfo.xcprivacy |
| + buildPhase: resources |
| dependencies: |
| - - package: CalendarNative |
| - product: CalendarKit |
| - - package: RastrilloNative |
| - product: RastrilloApple |
| + - package: CalendarNative |
| + product: CalendarKit |
| + - package: RastrilloNative |
| + product: RastrilloApple |
| info: |
| path: Info.plist |
| properties: |
| @@ -42,7 +42,13 @@ targets: |
| CFBundleIconFile: AppIcon |
| LSApplicationCategoryType: public.app-category.productivity |
| NSHighResolutionCapable: true |
| + CFBundleURLTypes: |
| + - CFBundleURLName: works.oficina.calendar.signin |
| + CFBundleURLSchemes: |
| + - works.oficina.calendar |
| + CFBundleTypeRole: Editor |
| settings: |
| base: |
| - PRODUCT_BUNDLE_IDENTIFIER: net.amadan.oficina.calendar |
| + PROVISIONING_PROFILE_SPECIFIER: $(OFICINA_PROVISIONING_PROFILE) |
| + PRODUCT_BUNDLE_IDENTIFIER: works.oficina.calendar |
| CODE_SIGN_ENTITLEMENTS: AppStore.entitlements |