Skip to content

Commit df4c602

Browse files
Attachments Helper (#35)
1 parent e20880a commit df4c602

36 files changed

+2609
-185
lines changed

CHANGELOG.md

+39-32
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
# Changelog
22

3+
# 1.0.0-Beta.12
4+
5+
- Added attachment sync helpers
6+
- Added support for cancellations in watched queries
7+
38
# 1.0.0-beta.11
49

5-
* Fix deadlock when `connect()` is called immediately after opening a database.
10+
- Fix deadlock when `connect()` is called immediately after opening a database.
611

712
# 1.0.0-Beta.10
813

9-
* Added the ability to specify a custom logging implementation
14+
- Added the ability to specify a custom logging implementation
15+
1016
```swift
1117
let db = PowerSyncDatabase(
1218
schema: Schema(
@@ -23,69 +29,70 @@
2329
logger: DefaultLogger(minSeverity: .debug)
2430
)
2531
```
26-
* added `.close()` method on `PowerSyncDatabaseProtocol`
27-
* Update `powersync-kotlin` dependency to version `1.0.0-BETA29`, which fixes these issues:
28-
* Fix potential race condition between jobs in `connect()` and `disconnect()`.
29-
* Fix race condition causing data received during uploads not to be applied.
30-
* Fixed issue where automatic driver migrations would fail with the error:
32+
33+
- added `.close()` method on `PowerSyncDatabaseProtocol`
34+
- Update `powersync-kotlin` dependency to version `1.0.0-BETA29`, which fixes these issues:
35+
- Fix potential race condition between jobs in `connect()` and `disconnect()`.
36+
- Fix race condition causing data received during uploads not to be applied.
37+
- Fixed issue where automatic driver migrations would fail with the error:
38+
3139
```
3240
Sqlite operation failure database is locked attempted to run migration and failed. closing connection
3341
```
3442

3543
## 1.0.0-Beta.9
3644

37-
* Update PowerSync SQLite core extension to 0.3.12.
38-
* Added queuing protection and warnings when connecting multiple PowerSync clients to the same database file.
39-
* Improved concurrent SQLite connection support. A single write connection and multiple read connections are used for concurrent read queries.
40-
* Internally improved the linking of SQLite.
41-
* Enabled Full Text Search support.
42-
* Added the ability to update the schema for existing PowerSync clients.
43-
* Fixed bug where local only, insert only and view name overrides were not applied for schema tables.
45+
- Update PowerSync SQLite core extension to 0.3.12.
46+
- Added queuing protection and warnings when connecting multiple PowerSync clients to the same database file.
47+
- Improved concurrent SQLite connection support. A single write connection and multiple read connections are used for concurrent read queries.
48+
- Internally improved the linking of SQLite.
49+
- Enabled Full Text Search support.
50+
- Added the ability to update the schema for existing PowerSync clients.
51+
- Fixed bug where local only, insert only and view name overrides were not applied for schema tables.
4452

4553
## 1.0.0-Beta.8
4654

47-
* Improved watch query internals. Added the ability to throttle watched queries.
48-
* Added support for sync bucket priorities.
55+
- Improved watch query internals. Added the ability to throttle watched queries.
56+
- Added support for sync bucket priorities.
4957

5058
## 1.0.0-Beta.7
5159

52-
* Fixed an issue where throwing exceptions in the query `mapper` could cause a runtime crash.
53-
* Internally improved type casting.
60+
- Fixed an issue where throwing exceptions in the query `mapper` could cause a runtime crash.
61+
- Internally improved type casting.
5462

5563
## 1.0.0-Beta.6
5664

57-
* BREAKING CHANGE: `watch` queries are now throwable and therefore will need to be accompanied by a `try` e.g.
65+
- BREAKING CHANGE: `watch` queries are now throwable and therefore will need to be accompanied by a `try` e.g.
5866

5967
```swift
6068
try database.watch()
6169
```
6270

63-
* BREAKING CHANGE: `transaction` functions are now throwable and therefore will need to be accompanied by a `try` e.g.
71+
- BREAKING CHANGE: `transaction` functions are now throwable and therefore will need to be accompanied by a `try` e.g.
6472

6573
```swift
6674
try await database.writeTransaction { transaction in
6775
try transaction.execute(...)
6876
}
6977
```
70-
* Allow `execute` errors to be handled
71-
* `userId` is now set to `nil` by default and therefore it is no longer required to be set to `nil` when instantiating `PowerSyncCredentials` and can therefore be left out.
7278

73-
## 1.0.0-Beta.5
79+
- Allow `execute` errors to be handled
80+
- `userId` is now set to `nil` by default and therefore it is no longer required to be set to `nil` when instantiating `PowerSyncCredentials` and can therefore be left out.
7481

75-
* Implement improvements to errors originating in Kotlin so that they can be handled in Swift
76-
* Improve `__fetchCredentials`to log the error but not cause an app crash on error
82+
## 1.0.0-Beta.5
7783

84+
- Implement improvements to errors originating in Kotlin so that they can be handled in Swift
85+
- Improve `__fetchCredentials`to log the error but not cause an app crash on error
7886

7987
## 1.0.0-Beta.4
8088

81-
* Allow cursor to use column name to get value by including the following functions that accept a column name parameter:
82-
`getBoolean`,`getBooleanOptional`,`getString`,`getStringOptional`, `getLong`,`getLongOptional`, `getDouble`,`getDoubleOptional`
83-
* BREAKING CHANGE: This should not affect anyone but made `KotlinPowerSyncCredentials`, `KotlinPowerSyncDatabase` and `KotlinPowerSyncBackendConnector` private as these should never have been public.
84-
89+
- Allow cursor to use column name to get value by including the following functions that accept a column name parameter:
90+
`getBoolean`,`getBooleanOptional`,`getString`,`getStringOptional`, `getLong`,`getLongOptional`, `getDouble`,`getDoubleOptional`
91+
- BREAKING CHANGE: This should not affect anyone but made `KotlinPowerSyncCredentials`, `KotlinPowerSyncDatabase` and `KotlinPowerSyncBackendConnector` private as these should never have been public.
8592

8693
## 1.0.0-Beta.3
8794

88-
* BREAKING CHANGE: Update underlying powersync-kotlin package to BETA18.0 which requires transactions to become synchronous as opposed to asynchronous.
95+
- BREAKING CHANGE: Update underlying powersync-kotlin package to BETA18.0 which requires transactions to become synchronous as opposed to asynchronous.
8996
```swift
9097
try await database.writeTransaction { transaction in
9198
try await transaction.execute(
@@ -106,8 +113,8 @@ try await database.writeTransaction { transaction in
106113

107114
## 1.0.0-Beta.2
108115

109-
* Upgrade PowerSyncSqliteCore to 0.3.8
116+
- Upgrade PowerSyncSqliteCore to 0.3.8
110117

111118
## 1.0.0-Beta.1
112119

113-
* Initial Beta release
120+
- Initial Beta release

Demo/PowerSyncExample.xcodeproj/project.pbxproj

+10-4
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
B69F7D862C8EE27400565448 /* AnyCodable in Frameworks */ = {isa = PBXBuildFile; productRef = B69F7D852C8EE27400565448 /* AnyCodable */; };
4141
B6B3698A2C64F4B30033C307 /* Navigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B369892C64F4B30033C307 /* Navigation.swift */; };
4242
B6FFD5322D06DA8000EEE60F /* PowerSync in Frameworks */ = {isa = PBXBuildFile; productRef = B6FFD5312D06DA8000EEE60F /* PowerSync */; };
43+
BE2F26EC2DA54B2F0080F1AE /* SupabaseRemoteStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE2F26EB2DA54B2A0080F1AE /* SupabaseRemoteStorage.swift */; };
4344
/* End PBXBuildFile section */
4445

4546
/* Begin PBXCopyFilesBuildPhase section */
@@ -106,6 +107,7 @@
106107
B6F421372BC42F450005D0D0 /* core.klib */ = {isa = PBXFileReference; lastKnownFileType = file; path = core.klib; sourceTree = "<group>"; };
107108
B6F4213D2BC42F5B0005D0D0 /* sqlite3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = sqlite3.c; path = "../powersync-kotlin/core/build/interop/sqlite/sqlite3.c"; sourceTree = "<group>"; };
108109
B6F421402BC430B60005D0D0 /* sqlite3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sqlite3.h; path = "../powersync-kotlin/core/build/interop/sqlite/sqlite3.h"; sourceTree = "<group>"; };
110+
BE2F26EB2DA54B2A0080F1AE /* SupabaseRemoteStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupabaseRemoteStorage.swift; sourceTree = "<group>"; };
109111
/* End PBXFileReference section */
110112

111113
/* Begin PBXFrameworksBuildPhase section */
@@ -218,6 +220,7 @@
218220
B65C4D6F2C60D58500176007 /* PowerSync */ = {
219221
isa = PBXGroup;
220222
children = (
223+
BE2F26EB2DA54B2A0080F1AE /* SupabaseRemoteStorage.swift */,
221224
6A7315BA2B98BDD30004CB17 /* SystemManager.swift */,
222225
6A4AD3842B9EE763005CBFD4 /* SupabaseConnector.swift */,
223226
6ABD78772B9F2D2800558A41 /* Schema.swift */,
@@ -564,6 +567,7 @@
564567
B65C4D6D2C60D38B00176007 /* HomeScreen.swift in Sources */,
565568
6A7315882B9854220004CB17 /* PowerSyncExampleApp.swift in Sources */,
566569
B666585F2C62115300159A81 /* ListRow.swift in Sources */,
570+
BE2F26EC2DA54B2F0080F1AE /* SupabaseRemoteStorage.swift in Sources */,
567571
B66658632C621CA700159A81 /* AddTodoListView.swift in Sources */,
568572
B666585D2C620E9E00159A81 /* WifiIcon.swift in Sources */,
569573
6A9669042B9EE6FA00B05DCF /* SignInScreen.swift in Sources */,
@@ -705,10 +709,11 @@
705709
CODE_SIGN_STYLE = Automatic;
706710
CURRENT_PROJECT_VERSION = 1;
707711
DEVELOPMENT_ASSET_PATHS = "\"PowerSyncExample/Preview Content\"";
708-
DEVELOPMENT_TEAM = 6WA62GTJNA;
712+
DEVELOPMENT_TEAM = ZGT7463CVJ;
709713
ENABLE_PREVIEWS = YES;
710714
ENABLE_USER_SCRIPT_SANDBOXING = NO;
711715
GENERATE_INFOPLIST_FILE = YES;
716+
INFOPLIST_KEY_NSCameraUsageDescription = "Take Photos for Todo Completion";
712717
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
713718
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
714719
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
@@ -721,7 +726,7 @@
721726
MARKETING_VERSION = 1.0;
722727
ONLY_ACTIVE_ARCH = YES;
723728
OTHER_LDFLAGS = "$(inherited)";
724-
PRODUCT_BUNDLE_IDENTIFIER = com.powersync.PowerSyncExample;
729+
PRODUCT_BUNDLE_IDENTIFIER = com.powersync.PowerSyncSwiftExample;
725730
PRODUCT_NAME = "$(TARGET_NAME)";
726731
SWIFT_EMIT_LOC_STRINGS = YES;
727732
SWIFT_OBJC_BRIDGING_HEADER = "PowerSyncExample/PowerSyncExample-Bridging-Header.h";
@@ -742,10 +747,11 @@
742747
CODE_SIGN_STYLE = Automatic;
743748
CURRENT_PROJECT_VERSION = 1;
744749
DEVELOPMENT_ASSET_PATHS = "\"PowerSyncExample/Preview Content\"";
745-
DEVELOPMENT_TEAM = 6WA62GTJNA;
750+
DEVELOPMENT_TEAM = ZGT7463CVJ;
746751
ENABLE_PREVIEWS = YES;
747752
ENABLE_USER_SCRIPT_SANDBOXING = NO;
748753
GENERATE_INFOPLIST_FILE = YES;
754+
INFOPLIST_KEY_NSCameraUsageDescription = "Take Photos for Todo Completion";
749755
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
750756
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
751757
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
@@ -757,7 +763,7 @@
757763
);
758764
MARKETING_VERSION = 1.0;
759765
OTHER_LDFLAGS = "$(inherited)";
760-
PRODUCT_BUNDLE_IDENTIFIER = com.powersync.PowerSyncExample;
766+
PRODUCT_BUNDLE_IDENTIFIER = com.powersync.PowerSyncSwiftExample;
761767
PRODUCT_NAME = "$(TARGET_NAME)";
762768
SWIFT_EMIT_LOC_STRINGS = YES;
763769
SWIFT_OBJC_BRIDGING_HEADER = "PowerSyncExample/PowerSyncExample-Bridging-Header.h";

Demo/PowerSyncExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
"kind" : "remoteSourceControl",
1616
"location" : "https://github.com/powersync-ja/powersync-kotlin.git",
1717
"state" : {
18-
"revision" : "443df078f4b9352de137000b993d564d4ab019b7",
19-
"version" : "1.0.0-BETA28.0"
18+
"revision" : "633a2924f7893f7ebeb064cbcd9c202937673633",
19+
"version" : "1.0.0-BETA30.0"
2020
}
2121
},
2222
{

Demo/PowerSyncExample.xcodeproj/xcshareddata/xcschemes/PowerSyncExample.xcscheme

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
ignoresPersistentStateOnLaunch = "NO"
4040
debugDocumentVersioning = "YES"
4141
debugServiceExtension = "internal"
42+
enableGPUValidationMode = "1"
4243
allowLocationSimulation = "YES">
4344
<BuildableProductRunnable
4445
runnableDebuggingMode = "0">
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,116 @@
11
import SwiftUI
22

33
struct TodoListRow: View {
4-
let todo: Todo
5-
let completeTapped: () -> Void
6-
7-
var body: some View {
8-
HStack {
9-
Text(todo.description)
10-
Spacer()
11-
Button {
12-
completeTapped()
13-
} label: {
14-
Image(systemName: todo.isComplete ? "checkmark.circle.fill" : "circle")
15-
}
16-
.buttonStyle(.plain)
4+
let todo: Todo
5+
let isCameraAvailable: Bool
6+
let completeTapped: () -> Void
7+
let deletePhotoTapped: () -> Void
8+
let capturePhotoTapped: () -> Void
9+
let selectPhotoTapped: () -> Void
10+
11+
@State private var image: UIImage? = nil
12+
13+
var body: some View {
14+
HStack {
15+
Text(todo.description)
16+
Group {
17+
if let image = image {
18+
Image(uiImage: image)
19+
.resizable()
20+
.scaledToFit()
21+
22+
} else if todo.photoUri != nil {
23+
// Show progress while loading the image
24+
ProgressView()
25+
.onAppear {
26+
Task {
27+
await loadImage()
28+
}
29+
}
30+
} else if todo.photoId != nil {
31+
// Show progres, wait for a URI to be present
32+
ProgressView()
33+
} else {
34+
EmptyView()
35+
}
36+
}
37+
Spacer()
38+
VStack {
39+
if todo.photoId == nil {
40+
HStack {
41+
if isCameraAvailable {
42+
Button {
43+
capturePhotoTapped()
44+
} label: {
45+
Image(systemName: "camera.fill")
46+
}
47+
.buttonStyle(.plain)
48+
}
49+
Button {
50+
selectPhotoTapped()
51+
} label: {
52+
Image(systemName: "photo.on.rectangle")
53+
}
54+
.buttonStyle(.plain)
55+
}
56+
} else {
57+
Button {
58+
deletePhotoTapped()
59+
} label: {
60+
Image(systemName: "trash.fill")
61+
}
62+
.buttonStyle(.plain)
63+
}
64+
Spacer()
65+
Button {
66+
completeTapped()
67+
} label: {
68+
Image(systemName: todo.isComplete ? "checkmark.circle.fill" : "circle")
69+
}
70+
.buttonStyle(.plain)
71+
}.onChange(of: todo.photoId) { _, newPhotoId in
72+
if newPhotoId == nil {
73+
// Clear the image when photoId becomes nil
74+
image = nil
75+
}
76+
}
77+
}
1778
}
18-
}
19-
}
2079

80+
private func loadImage() async {
81+
guard let urlString = todo.photoUri else { return }
82+
let url = URL(fileURLWithPath: urlString)
83+
84+
do {
85+
let data = try Data(contentsOf: url)
86+
if let loadedImage = UIImage(data: data) {
87+
image = loadedImage
88+
} else {
89+
print("Failed to decode image from data.")
90+
}
91+
} catch {
92+
print("Error loading image from disk:", error)
93+
}
94+
}
95+
}
2196

2297
#Preview {
2398
TodoListRow(
24-
todo: .init(
25-
id: UUID().uuidString.lowercased(),
26-
listId: UUID().uuidString.lowercased(),
27-
photoId: nil,
28-
description: "description",
29-
isComplete: false,
30-
createdAt: "",
31-
completedAt: nil,
32-
createdBy: UUID().uuidString.lowercased(),
33-
completedBy: nil
34-
)
99+
todo: .init(
100+
id: UUID().uuidString.lowercased(),
101+
listId: UUID().uuidString.lowercased(),
102+
photoId: nil,
103+
description: "description",
104+
isComplete: false,
105+
createdAt: "",
106+
completedAt: nil,
107+
createdBy: UUID().uuidString.lowercased(),
108+
completedBy: nil,
109+
110+
),
111+
isCameraAvailable: true,
112+
completeTapped: {},
113+
deletePhotoTapped: {},
114+
capturePhotoTapped: {}
35115
) {}
36116
}

0 commit comments

Comments
 (0)