From a311d1df4d454cc43fc8345f44f0ad2539a6f850 Mon Sep 17 00:00:00 2001 From: Aaron LaBeau <80424345+biozal@users.noreply.github.com> Date: Sat, 31 Jan 2026 13:21:59 -0600 Subject: [PATCH 01/13] fix: Updated for latest v5 release, updated code to fix changes in APIs and ran swiftlint --- swift/Tasks.xcodeproj/project.pbxproj | 38 ++--- .../xcshareddata/swiftpm/Package.resolved | 4 +- .../xcshareddata/xcschemes/Tasks.xcscheme | 2 +- swift/Tasks/DittoManager.swift | 55 ++++---- swift/Tasks/TasksApp.swift | 9 +- swift/Tasks/TasksListScreen.swift | 133 ++++++++++-------- 6 files changed, 129 insertions(+), 112 deletions(-) diff --git a/swift/Tasks.xcodeproj/project.pbxproj b/swift/Tasks.xcodeproj/project.pbxproj index 7507a5f9d..a5746e45b 100644 --- a/swift/Tasks.xcodeproj/project.pbxproj +++ b/swift/Tasks.xcodeproj/project.pbxproj @@ -7,8 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 4170A8552CED346F00043F5A /* DittoObjC in Frameworks */ = {isa = PBXBuildFile; productRef = 4170A8542CED346F00043F5A /* DittoObjC */; }; - 4170A8572CED346F00043F5A /* DittoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 4170A8562CED346F00043F5A /* DittoSwift */; }; + 0D40BBA72F2AAE8A006A72A4 /* DittoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 0D40BBA62F2AAE8A006A72A4 /* DittoSwift */; }; ABCDEF012345678900000001 /* TasksUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABCDEF012345678900000002 /* TasksUITests.swift */; }; /* End PBXBuildFile section */ @@ -55,8 +54,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 4170A8552CED346F00043F5A /* DittoObjC in Frameworks */, - 4170A8572CED346F00043F5A /* DittoSwift in Frameworks */, + 0D40BBA72F2AAE8A006A72A4 /* DittoSwift in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -70,11 +68,19 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 0D40BBA52F2AAE8A006A72A4 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; 41F869812CECF42500DC7268 = { isa = PBXGroup; children = ( 41F8698C2CECF42500DC7268 /* Tasks */, ABCDEF012345678900000005 /* TasksUITests */, + 0D40BBA52F2AAE8A006A72A4 /* Frameworks */, 41F8698B2CECF42500DC7268 /* Products */, ); sourceTree = ""; @@ -118,8 +124,7 @@ ); name = Tasks; packageProductDependencies = ( - 4170A8542CED346F00043F5A /* DittoObjC */, - 4170A8562CED346F00043F5A /* DittoSwift */, + 0D40BBA62F2AAE8A006A72A4 /* DittoSwift */, ); productName = Tasks; productReference = 41F8698A2CECF42500DC7268 /* Tasks.app */; @@ -151,7 +156,7 @@ attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1610; - LastUpgradeCheck = 1610; + LastUpgradeCheck = 2620; TargetAttributes = { 41F869892CECF42500DC7268 = { CreatedOnToolsVersion = 16.1; @@ -168,7 +173,7 @@ mainGroup = 41F869812CECF42500DC7268; minimizedProjectReferenceProxies = 1; packageReferences = ( - 4170A8532CED346F00043F5A /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */, + 0D40BBA42F2AAE7D006A72A4 /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */, ); preferredProjectObjectVersion = 77; productRefGroup = 41F8698B2CECF42500DC7268 /* Products */; @@ -326,6 +331,7 @@ MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; + STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; @@ -382,6 +388,7 @@ MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; + STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_COMPILATION_MODE = wholemodule; VALIDATE_PRODUCT = YES; }; @@ -400,6 +407,7 @@ GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Tasks/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Ditto Tasks"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "Uses Bluetooth to connect and sync with nearby devices"; INFOPLIST_KEY_NSBluetoothPeripheralUsageDescription = "Uses Bluetooth to connect and sync with nearby devices"; INFOPLIST_KEY_NSLocalNetworkUsageDescription = "Uses WiFi to connect and sync with nearby devices"; @@ -435,6 +443,7 @@ GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Tasks/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Ditto Tasks"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "Uses Bluetooth to connect and sync with nearby devices"; INFOPLIST_KEY_NSBluetoothPeripheralUsageDescription = "Uses Bluetooth to connect and sync with nearby devices"; INFOPLIST_KEY_NSLocalNetworkUsageDescription = "Uses WiFi to connect and sync with nearby devices"; @@ -526,25 +535,20 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 4170A8532CED346F00043F5A /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */ = { + 0D40BBA42F2AAE7D006A72A4 /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/getditto/DittoSwiftPackage"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 4.13.1; + minimumVersion = "5.0.0-dev-weekly.20260126.180"; }; }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 4170A8542CED346F00043F5A /* DittoObjC */ = { - isa = XCSwiftPackageProductDependency; - package = 4170A8532CED346F00043F5A /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */; - productName = DittoObjC; - }; - 4170A8562CED346F00043F5A /* DittoSwift */ = { + 0D40BBA62F2AAE8A006A72A4 /* DittoSwift */ = { isa = XCSwiftPackageProductDependency; - package = 4170A8532CED346F00043F5A /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */; + package = 0D40BBA42F2AAE7D006A72A4 /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */; productName = DittoSwift; }; /* End XCSwiftPackageProductDependency section */ diff --git a/swift/Tasks.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/swift/Tasks.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 9d0559ad6..7d2def6b3 100644 --- a/swift/Tasks.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/swift/Tasks.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/getditto/DittoSwiftPackage", "state" : { - "revision" : "c68c60c68ca4783248466781fd7607e1e59af198", - "version" : "4.13.1" + "revision" : "620b2b8ba0177d6d80875f752d588d2b30322200", + "version" : "5.0.0-swift-remove-support-for-cocoapods.1" } } ], diff --git a/swift/Tasks.xcodeproj/xcshareddata/xcschemes/Tasks.xcscheme b/swift/Tasks.xcodeproj/xcshareddata/xcschemes/Tasks.xcscheme index bfcc99fa5..43aab3fa6 100644 --- a/swift/Tasks.xcodeproj/xcshareddata/xcschemes/Tasks.xcscheme +++ b/swift/Tasks.xcodeproj/xcshareddata/xcschemes/Tasks.xcscheme @@ -1,6 +1,6 @@ Date: Fri, 6 Feb 2026 10:35:25 -0600 Subject: [PATCH 02/13] updated to latest weekly build --- swift/Tasks.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/Tasks.xcodeproj/project.pbxproj b/swift/Tasks.xcodeproj/project.pbxproj index a5746e45b..915d7b245 100644 --- a/swift/Tasks.xcodeproj/project.pbxproj +++ b/swift/Tasks.xcodeproj/project.pbxproj @@ -540,7 +540,7 @@ repositoryURL = "https://github.com/getditto/DittoSwiftPackage"; requirement = { kind = upToNextMajorVersion; - minimumVersion = "5.0.0-dev-weekly.20260126.180"; + minimumVersion = "5.0.0-dev-weekly.20260202.183"; }; }; /* End XCRemoteSwiftPackageReference section */ From 16cd9783e838c960b8fd3a04454ba69153f0c27c Mon Sep 17 00:00:00 2001 From: Aaron LaBeau <80424345+biozal@users.noreply.github.com> Date: Tue, 17 Feb 2026 20:11:42 -0600 Subject: [PATCH 03/13] fix for preview 4 --- swift/Tasks.xcodeproj/project.pbxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/swift/Tasks.xcodeproj/project.pbxproj b/swift/Tasks.xcodeproj/project.pbxproj index 915d7b245..b551872a0 100644 --- a/swift/Tasks.xcodeproj/project.pbxproj +++ b/swift/Tasks.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 0D40BBA72F2AAE8A006A72A4 /* DittoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 0D40BBA62F2AAE8A006A72A4 /* DittoSwift */; }; + 0D19ADAF2F319E1B004D866D /* DittoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 0D19ADAE2F319E1B004D866D /* DittoSwift */; }; ABCDEF012345678900000001 /* TasksUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABCDEF012345678900000002 /* TasksUITests.swift */; }; /* End PBXBuildFile section */ @@ -54,7 +54,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 0D40BBA72F2AAE8A006A72A4 /* DittoSwift in Frameworks */, + 0D19ADAF2F319E1B004D866D /* DittoSwift in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -124,7 +124,7 @@ ); name = Tasks; packageProductDependencies = ( - 0D40BBA62F2AAE8A006A72A4 /* DittoSwift */, + 0D19ADAE2F319E1B004D866D /* DittoSwift */, ); productName = Tasks; productReference = 41F8698A2CECF42500DC7268 /* Tasks.app */; @@ -173,7 +173,7 @@ mainGroup = 41F869812CECF42500DC7268; minimizedProjectReferenceProxies = 1; packageReferences = ( - 0D40BBA42F2AAE7D006A72A4 /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */, + 0D19ADAD2F319E10004D866D /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */, ); preferredProjectObjectVersion = 77; productRefGroup = 41F8698B2CECF42500DC7268 /* Products */; @@ -535,20 +535,20 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 0D40BBA42F2AAE7D006A72A4 /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */ = { + 0D19ADAD2F319E10004D866D /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/getditto/DittoSwiftPackage"; requirement = { kind = upToNextMajorVersion; - minimumVersion = "5.0.0-dev-weekly.20260202.183"; + minimumVersion = "5.0.0-preview.4"; }; }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 0D40BBA62F2AAE8A006A72A4 /* DittoSwift */ = { + 0D19ADAE2F319E1B004D866D /* DittoSwift */ = { isa = XCSwiftPackageProductDependency; - package = 0D40BBA42F2AAE7D006A72A4 /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */; + package = 0D19ADAD2F319E10004D866D /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */; productName = DittoSwift; }; /* End XCSwiftPackageProductDependency section */ From 0b8ef868c42591de918aba658ba65e1114fec1ac Mon Sep 17 00:00:00 2001 From: Aaron LaBeau Date: Fri, 27 Feb 2026 11:45:45 -0600 Subject: [PATCH 04/13] updated to v5 preview 5 --- swift/Tasks.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/Tasks.xcodeproj/project.pbxproj b/swift/Tasks.xcodeproj/project.pbxproj index b551872a0..15c90042a 100644 --- a/swift/Tasks.xcodeproj/project.pbxproj +++ b/swift/Tasks.xcodeproj/project.pbxproj @@ -540,7 +540,7 @@ repositoryURL = "https://github.com/getditto/DittoSwiftPackage"; requirement = { kind = upToNextMajorVersion; - minimumVersion = "5.0.0-preview.4"; + minimumVersion = "5.0.0-preview.5"; }; }; /* End XCRemoteSwiftPackageReference section */ From d68b112ad4481fdd71052595e43b355c4347ceaa Mon Sep 17 00:00:00 2001 From: Aaron LaBeau Date: Mon, 2 Mar 2026 11:17:24 -0600 Subject: [PATCH 05/13] Updated to Preview 5 --- swift/Tasks.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/Tasks.xcodeproj/project.pbxproj b/swift/Tasks.xcodeproj/project.pbxproj index 15c90042a..a9728598d 100644 --- a/swift/Tasks.xcodeproj/project.pbxproj +++ b/swift/Tasks.xcodeproj/project.pbxproj @@ -402,7 +402,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"Tasks/Preview Content\""; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = E3FRN9JNGJ; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Tasks/Info.plist; @@ -438,7 +438,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"Tasks/Preview Content\""; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = E3FRN9JNGJ; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Tasks/Info.plist; From 778bc040ff9f62340fe94690a74da4ac7260d5f5 Mon Sep 17 00:00:00 2001 From: Aaron LaBeau Date: Wed, 11 Mar 2026 13:06:11 -0500 Subject: [PATCH 06/13] updated to RC1 --- swift/Tasks.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/Tasks.xcodeproj/project.pbxproj b/swift/Tasks.xcodeproj/project.pbxproj index a9728598d..2977dfc21 100644 --- a/swift/Tasks.xcodeproj/project.pbxproj +++ b/swift/Tasks.xcodeproj/project.pbxproj @@ -540,7 +540,7 @@ repositoryURL = "https://github.com/getditto/DittoSwiftPackage"; requirement = { kind = upToNextMajorVersion; - minimumVersion = "5.0.0-preview.5"; + minimumVersion = "5.0.0-rc.1"; }; }; /* End XCRemoteSwiftPackageReference section */ From bdd435743a11615770a2748bbbe6ffed9b60d091 Mon Sep 17 00:00:00 2001 From: Aaron LaBeau <80424345+biozal@users.noreply.github.com> Date: Mon, 13 Apr 2026 13:44:02 -0500 Subject: [PATCH 07/13] update to rc2 --- swift/Tasks.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/Tasks.xcodeproj/project.pbxproj b/swift/Tasks.xcodeproj/project.pbxproj index 2977dfc21..060181076 100644 --- a/swift/Tasks.xcodeproj/project.pbxproj +++ b/swift/Tasks.xcodeproj/project.pbxproj @@ -540,7 +540,7 @@ repositoryURL = "https://github.com/getditto/DittoSwiftPackage"; requirement = { kind = upToNextMajorVersion; - minimumVersion = "5.0.0-rc.1"; + minimumVersion = "5.0.0-rc.3"; }; }; /* End XCRemoteSwiftPackageReference section */ From 74c0ff6d736696eb02d8cadfac4f4a896ebada6b Mon Sep 17 00:00:00 2001 From: Aaron LaBeau Date: Tue, 5 May 2026 09:32:17 -0500 Subject: [PATCH 08/13] Updated for v5 release --- swift/Tasks.xcodeproj/project.pbxproj | 4 ++-- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- swift/Tasks/TaskModel.swift | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/swift/Tasks.xcodeproj/project.pbxproj b/swift/Tasks.xcodeproj/project.pbxproj index 060181076..d518892e2 100644 --- a/swift/Tasks.xcodeproj/project.pbxproj +++ b/swift/Tasks.xcodeproj/project.pbxproj @@ -539,8 +539,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/getditto/DittoSwiftPackage"; requirement = { - kind = upToNextMajorVersion; - minimumVersion = "5.0.0-rc.3"; + kind = upToNextMinorVersion; + minimumVersion = 5.0.0; }; }; /* End XCRemoteSwiftPackageReference section */ diff --git a/swift/Tasks.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/swift/Tasks.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 7d2def6b3..9a067e4ab 100644 --- a/swift/Tasks.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/swift/Tasks.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/getditto/DittoSwiftPackage", "state" : { - "revision" : "620b2b8ba0177d6d80875f752d588d2b30322200", - "version" : "5.0.0-swift-remove-support-for-cocoapods.1" + "revision" : "60091ac1da98c96ffa0ed7c566650e7e08d01c74", + "version" : "5.0.0" } } ], diff --git a/swift/Tasks/TaskModel.swift b/swift/Tasks/TaskModel.swift index 509c4c30c..07a02addf 100644 --- a/swift/Tasks/TaskModel.swift +++ b/swift/Tasks/TaskModel.swift @@ -1,4 +1,5 @@ import DittoSwift +import Foundation /// A document in the `tasks` collection struct TaskModel { From 51aa46af6c9d0a04f1412ffc005739916de43481 Mon Sep 17 00:00:00 2001 From: Aaron LaBeau Date: Tue, 5 May 2026 09:35:27 -0500 Subject: [PATCH 09/13] updated readme --- swift/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/swift/README.md b/swift/README.md index ade103ec8..56596b8f7 100644 --- a/swift/README.md +++ b/swift/README.md @@ -4,7 +4,7 @@ After you have completed the [common prerequisites] you will need the following: -- [Xcode](https://developer.apple.com/xcode/) 15 or greater +- [Xcode](https://developer.apple.com/xcode/) 16 or greater (Required for Swift 6) ## Permissions (already configured) @@ -13,7 +13,7 @@ After you have completed the [common prerequisites] you will need the following: ## Documentation - [Swift Install Guide](https://docs.ditto.live/install-guides/swift) -- [Swift API Reference](https://software.ditto.live/cocoa/DittoSwift/4.8.2/api-reference/) +- [Swift API Reference](https://software.ditto.live/cocoa/DittoSwift/5.0.0/api-reference/documentation/dittoswift/) - [Swift Release Notes](https://docs.ditto.live/release-notes/swift) [common prerequisites]: https://github.com/getditto/quickstart#common-prerequisites @@ -22,8 +22,8 @@ After you have completed the [common prerequisites] you will need the following: Assuming you have Xcode and other prerequisites installed, you can build and run the app by following these steps: -1. Create an application at . Make note of the app ID and online playground token. -2. Copy the `.env.sample` file at the top level of the `quickstart` repo to `.env` and add your App ID , Online playground Token, Auth URL, and Websocket URL. +1. Create an application at . Make note of the Database ID and Online Playground Token. +2. Copy the `.env.sample` file at the top level of the `quickstart` repo to `.env` and add your Database ID (used to be called App ID), Online Playground Token, and Auth URL. 3. Launch Xcode and open the `quickstart/swift/Tasks.xcodeproj` project. 4. Navigate to the project **Signing & Capabilities** tab and modify the **Team** and **Bundle Identifier** settings to your Apple developer account credentials to provision building to your device. 5. In Xcode, select a connected iOS device or iOS Simulator as the destination. From a2a1a87161923cdeeafe08775cc8dace92f5255b Mon Sep 17 00:00:00 2001 From: Aaron LaBeau Date: Tue, 5 May 2026 09:40:47 -0500 Subject: [PATCH 10/13] updated to remove dev team --- swift/Tasks.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/Tasks.xcodeproj/project.pbxproj b/swift/Tasks.xcodeproj/project.pbxproj index d518892e2..fb929289c 100644 --- a/swift/Tasks.xcodeproj/project.pbxproj +++ b/swift/Tasks.xcodeproj/project.pbxproj @@ -402,7 +402,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"Tasks/Preview Content\""; - DEVELOPMENT_TEAM = E3FRN9JNGJ; + DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Tasks/Info.plist; @@ -438,7 +438,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"Tasks/Preview Content\""; - DEVELOPMENT_TEAM = E3FRN9JNGJ; + DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Tasks/Info.plist; From 876cd89bb340db393a875c5ac87a739cf5064856 Mon Sep 17 00:00:00 2001 From: Aaron LaBeau Date: Tue, 5 May 2026 09:50:25 -0500 Subject: [PATCH 11/13] Fixed issues with MainActor --- swift/Tasks/DittoManager.swift | 1 + swift/Tasks/EditScreen.swift | 1 + swift/Tasks/TaskModel.swift | 2 +- swift/Tasks/TasksListScreen.swift | 39 ++++++++++++++++++------------- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/swift/Tasks/DittoManager.swift b/swift/Tasks/DittoManager.swift index 1172b8aee..5a8c4f2b3 100644 --- a/swift/Tasks/DittoManager.swift +++ b/swift/Tasks/DittoManager.swift @@ -2,6 +2,7 @@ import DittoSwift import Foundation /// Owner of the Ditto object +@MainActor class DittoManager: ObservableObject { @Published var ditto: Ditto? static let shared = DittoManager() diff --git a/swift/Tasks/EditScreen.swift b/swift/Tasks/EditScreen.swift index f34a0baf5..ae4b77422 100644 --- a/swift/Tasks/EditScreen.swift +++ b/swift/Tasks/EditScreen.swift @@ -3,6 +3,7 @@ import DittoSwift import SwiftUI /// View model for EditScreen +@MainActor class EditScreenViewModel: ObservableObject { @Published var taskTitleText: String @Published var isExistingTask: Bool = false diff --git a/swift/Tasks/TaskModel.swift b/swift/Tasks/TaskModel.swift index 07a02addf..c76a770af 100644 --- a/swift/Tasks/TaskModel.swift +++ b/swift/Tasks/TaskModel.swift @@ -2,7 +2,7 @@ import DittoSwift import Foundation /// A document in the `tasks` collection -struct TaskModel { +struct TaskModel: Sendable { // swiftlint:disable:next identifier_name let _id: String var title: String diff --git a/swift/Tasks/TasksListScreen.swift b/swift/Tasks/TasksListScreen.swift index 26bc1d22a..5d5654c52 100644 --- a/swift/Tasks/TasksListScreen.swift +++ b/swift/Tasks/TasksListScreen.swift @@ -9,7 +9,7 @@ class TasksListScreenViewModel: ObservableObject { @Published var isPresentingEditScreen: Bool = false private(set) var taskToEdit: TaskModel? - private let ditto = DittoManager.shared.ditto + private var ditto: Ditto? { DittoManager.shared.ditto } private var subscription: DittoSyncSubscription? private var storeObserver: DittoStoreObserver? @@ -31,17 +31,17 @@ class TasksListScreenViewModel: ObservableObject { } } - deinit { + /// Cancel observers/subscriptions and stop sync. Call from `.onDisappear` + /// — `deinit` is `nonisolated` and cannot safely touch `@MainActor` state. + func teardown() { subscription?.cancel() subscription = nil storeObserver?.cancel() storeObserver = nil - if let ditto = self.ditto { - if ditto.sync.isActive { - ditto.sync.stop() - } + if let ditto = self.ditto, ditto.sync.isActive { + ditto.sync.stop() } } @@ -81,7 +81,8 @@ class TasksListScreenViewModel: ObservableObject { } func toggleComplete(task: TaskModel) { - Task { + Task { [weak self] in + guard let self else { return } let done = !task.done let query = """ UPDATE tasks @@ -104,8 +105,9 @@ class TasksListScreenViewModel: ObservableObject { } } - nonisolated func saveEditedTask(_ task: TaskModel) { - Task { + func saveEditedTask(_ task: TaskModel) { + Task { [weak self] in + guard let self else { return } let query = """ UPDATE tasks SET title = :title, @@ -134,8 +136,9 @@ class TasksListScreenViewModel: ObservableObject { } } - nonisolated func saveNewTask(_ task: TaskModel) { - Task { + func saveNewTask(_ task: TaskModel) { + Task { [weak self] in + guard let self else { return } let newTask = task.value let query = "INSERT INTO tasks DOCUMENTS (:newTask)" @@ -152,8 +155,9 @@ class TasksListScreenViewModel: ObservableObject { } } - nonisolated func deleteTask(_ task: TaskModel) { - Task { + func deleteTask(_ task: TaskModel) { + Task { [weak self] in + guard let self else { return } let query = "UPDATE tasks SET deleted = true WHERE _id = :_id" do { if let ditto = self.ditto { @@ -168,8 +172,9 @@ class TasksListScreenViewModel: ObservableObject { } } - private nonisolated func populateTasksCollection() { - Task { + private func populateTasksCollection() { + Task { [weak self] in + guard let self else { return } let initialTasks: [TaskModel] = [ TaskModel( _id: "50191411-4C46-4940-8B72-5F8017A04FA7", @@ -306,6 +311,9 @@ struct TasksListScreen: View { } } } + .onDisappear { + viewModel.teardown() + } } private func deleteTaskItems(at offsets: IndexSet) { @@ -325,7 +333,6 @@ struct TasksListScreen: View { private static func saveSyncEnabledState(_ state: Bool) { UserDefaults.standard.set(state, forKey: isSyncEnabledKey) - UserDefaults.standard.synchronize() } } From 5a7b1d4d19024c12d403a63af62265bd86941a2e Mon Sep 17 00:00:00 2001 From: Aaron LaBeau <80424345+biozal@users.noreply.github.com> Date: Tue, 5 May 2026 09:50:38 -0500 Subject: [PATCH 12/13] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- swift/Tasks/TasksListScreen.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/swift/Tasks/TasksListScreen.swift b/swift/Tasks/TasksListScreen.swift index 5d5654c52..681dae66b 100644 --- a/swift/Tasks/TasksListScreen.swift +++ b/swift/Tasks/TasksListScreen.swift @@ -265,7 +265,8 @@ struct TasksListScreen: View { .toolbar { ToolbarItem(placement: .topBarTrailing) { HStack { - Toggle(" Sync", isOn: $syncEnabled) + Toggle("Sync", isOn: $syncEnabled) + .padding(.leading, 8) .toggleStyle(SwitchToggleStyle()) .onChange(of: syncEnabled) { newSyncEnabled in Self.saveSyncEnabledState(newSyncEnabled) @@ -286,7 +287,7 @@ struct TasksListScreen: View { }) .buttonStyle(.borderedProminent) .padding(.bottom) - .padding(.trailing, 100) + Spacer() } } .sheet( From 9258a9b8a781a5e61f82ec49c40500d331464fc6 Mon Sep 17 00:00:00 2001 From: Aaron LaBeau Date: Tue, 5 May 2026 16:24:25 -0500 Subject: [PATCH 13/13] Updated Ditto Manager based on feedback --- swift/Tasks/DittoManager.swift | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/swift/Tasks/DittoManager.swift b/swift/Tasks/DittoManager.swift index 5a8c4f2b3..2eca54c2c 100644 --- a/swift/Tasks/DittoManager.swift +++ b/swift/Tasks/DittoManager.swift @@ -1,6 +1,17 @@ import DittoSwift import Foundation +enum DittoManagerError: LocalizedError { + case invalidAuthURL(String) + + var errorDescription: String? { + switch self { + case .invalidAuthURL(let value): + return "DITTO_AUTH_URL is missing or not a valid URL: \"\(value)\". Check your .env configuration." + } + } +} + /// Owner of the Ditto object @MainActor class DittoManager: ObservableObject { @@ -11,10 +22,20 @@ class DittoManager: ObservableObject { /// Initializes Ditto and configures logging. Handles thrown errors. func initDitto() async throws { + // Configure logging for non-preview runs + let isPreview: Bool = ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" + if !isPreview { + DittoLogger.minimumLogLevel = .debug + } + + guard let authURL = URL(string: Env.DITTO_AUTH_URL) else { + throw DittoManagerError.invalidAuthURL(Env.DITTO_AUTH_URL) + } + // https://docs.ditto.live/sdk/latest/ditto-config let config = DittoConfig( databaseID: Env.DITTO_APP_ID, - connect: .server(url: URL(string: Env.DITTO_AUTH_URL)!)) + connect: .server(url: authURL)) do { let dittoOpened = try await Ditto.open(config: config) @@ -38,11 +59,5 @@ class DittoManager: ObservableObject { self.ditto = nil throw error } - - // Configure logging for non-preview runs - let isPreview: Bool = ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" - if !isPreview { - DittoLogger.minimumLogLevel = .debug - } } }