Skip to content
Merged
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
8 changes: 4 additions & 4 deletions swift/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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
Expand All @@ -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 <https://portal.ditto.live/>. 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 <https://portal.ditto.live/>. 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.
Comment thread
biozal marked this conversation as resolved.
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.
Expand Down
40 changes: 22 additions & 18 deletions swift/Tasks.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
0D19ADAF2F319E1B004D866D /* DittoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 0D19ADAE2F319E1B004D866D /* DittoSwift */; };
ABCDEF012345678900000001 /* TasksUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABCDEF012345678900000002 /* TasksUITests.swift */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -55,8 +54,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4170A8552CED346F00043F5A /* DittoObjC in Frameworks */,
4170A8572CED346F00043F5A /* DittoSwift in Frameworks */,
0D19ADAF2F319E1B004D866D /* DittoSwift in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -70,11 +68,19 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
0D40BBA52F2AAE8A006A72A4 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
41F869812CECF42500DC7268 = {
isa = PBXGroup;
children = (
41F8698C2CECF42500DC7268 /* Tasks */,
ABCDEF012345678900000005 /* TasksUITests */,
0D40BBA52F2AAE8A006A72A4 /* Frameworks */,
41F8698B2CECF42500DC7268 /* Products */,
);
sourceTree = "<group>";
Expand Down Expand Up @@ -118,8 +124,7 @@
);
name = Tasks;
packageProductDependencies = (
4170A8542CED346F00043F5A /* DittoObjC */,
4170A8562CED346F00043F5A /* DittoSwift */,
0D19ADAE2F319E1B004D866D /* DittoSwift */,
);
productName = Tasks;
productReference = 41F8698A2CECF42500DC7268 /* Tasks.app */;
Expand Down Expand Up @@ -151,7 +156,7 @@
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1610;
LastUpgradeCheck = 1610;
LastUpgradeCheck = 2620;
TargetAttributes = {
41F869892CECF42500DC7268 = {
CreatedOnToolsVersion = 16.1;
Expand All @@ -168,7 +173,7 @@
mainGroup = 41F869812CECF42500DC7268;
minimizedProjectReferenceProxies = 1;
packageReferences = (
4170A8532CED346F00043F5A /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */,
0D19ADAD2F319E10004D866D /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */,
);
preferredProjectObjectVersion = 77;
productRefGroup = 41F8698B2CECF42500DC7268 /* Products */;
Expand Down Expand Up @@ -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";
};
Expand Down Expand Up @@ -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;
};
Expand All @@ -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";
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -526,25 +535,20 @@
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
4170A8532CED346F00043F5A /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */ = {
0D19ADAD2F319E10004D866D /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/getditto/DittoSwiftPackage";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 4.14.3;
kind = upToNextMinorVersion;
minimumVersion = 5.0.0;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
4170A8542CED346F00043F5A /* DittoObjC */ = {
isa = XCSwiftPackageProductDependency;
package = 4170A8532CED346F00043F5A /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */;
productName = DittoObjC;
};
4170A8562CED346F00043F5A /* DittoSwift */ = {
0D19ADAE2F319E1B004D866D /* DittoSwift */ = {
isa = XCSwiftPackageProductDependency;
package = 4170A8532CED346F00043F5A /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */;
package = 0D19ADAD2F319E10004D866D /* XCRemoteSwiftPackageReference "DittoSwiftPackage" */;
productName = DittoSwift;
};
/* End XCSwiftPackageProductDependency section */
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1640"
LastUpgradeVersion = "2620"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
77 changes: 49 additions & 28 deletions swift/Tasks/DittoManager.swift
Original file line number Diff line number Diff line change
@@ -1,42 +1,63 @@
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 {
let ditto: Ditto
@Published var ditto: Ditto?
static let shared = DittoManager()

private init() {
// https://docs.ditto.live/sdk/latest/install-guides/swift#integrating-and-initializing-sync
ditto = Ditto(
identity: .onlinePlayground(
appID: Env.DITTO_APP_ID,
token: Env.DITTO_PLAYGROUND_TOKEN,
// This is required to be set to false to use the correct URLs
// This only disables cloud sync when the webSocketURL is not set explicitly
enableDittoCloudSync: false,
customAuthURL: URL(string: Env.DITTO_AUTH_URL)
)
)

// Set the Ditto Websocket URL
ditto.updateTransportConfig { transportConfig in
transportConfig.connect.webSocketURLs.insert(Env.DITTO_WEBSOCKET_URL)
private init() {}

/// 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)
}

// disable sync with v3 peers, required for DQL
// https://docs.ditto.live/sdk/latest/ditto-config
let config = DittoConfig(
databaseID: Env.DITTO_APP_ID,
connect: .server(url: authURL))

do {
try ditto.disableSyncWithV3()
} catch let error {
print(
"DittoManger - ERROR: disableSyncWithV3() failed with error \"\(error)\""
)
}
let dittoOpened = try await Ditto.open(config: config)
dittoOpened.auth?.expirationHandler = { ditto, secondsRemaining in
// Authenticate when token is expiring. This closure must not throw.
ditto.auth?.login(token: Env.DITTO_PLAYGROUND_TOKEN,
provider: .development) { clientInfo, error in
if let error = error {
// Cannot throw from here; log the error instead.
print(
"Ditto auth refresh failed: \(error), " +
"client info: \(String(describing: clientInfo)), " +
"seconds remaining \(secondsRemaining)"
)
}
}
}
self.ditto = dittoOpened

let isPreview: Bool =
ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1"
if !isPreview {
DittoLogger.minimumLogLevel = .debug
} catch {
self.ditto = nil
throw error
Comment thread
biozal marked this conversation as resolved.
}
}
}
1 change: 1 addition & 0 deletions swift/Tasks/EditScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion swift/Tasks/TaskModel.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
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
Expand Down
9 changes: 2 additions & 7 deletions swift/Tasks/TasksApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import SwiftUI
@main
struct TasksApp: App {
@State private var isLoading = true
private let ditto = DittoManager.shared.ditto

var body: some Scene {
WindowGroup {
Expand All @@ -16,14 +15,10 @@ struct TasksApp: App {
}
.task {
do {
// Disable DQL strict mode. When set to false, collection
// definitions are no longer required. SELECT queries will
// return and display all fields by default.
// https://docs.ditto.live/dql/strict-mode
try await ditto.store.execute(query: "ALTER SYSTEM SET DQL_STRICT_MODE = false")
try await DittoManager.shared.initDitto()
isLoading = false
} catch {
fatalError("Internal inconsistency, expected setting DQL strict mode to false to always succeed but it failed: \(error)")
fatalError("Failed to initialize Ditto: \(error)")
}
}
}
Expand Down
Loading
Loading