Skip to content

Commit 7055b08

Browse files
Add image preview to demo
1 parent 18bcd4c commit 7055b08

File tree

10 files changed

+211
-104
lines changed

10 files changed

+211
-104
lines changed

Demo/PowerSyncExample/Components/TodoListRow.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,30 @@ import SwiftUI
33
struct TodoListRow: View {
44
let todo: Todo
55
let completeTapped: () -> Void
6+
@State private var image: UIImage? = nil
67

78
var body: some View {
89
HStack {
910
Text(todo.description)
11+
Group {
12+
if (todo.photoUri == nil) {
13+
// Nothing to display when photoURI is nil
14+
EmptyView()
15+
} else if let image = image {
16+
Image(uiImage: image)
17+
.resizable()
18+
.scaledToFit()
19+
} else if todo.photoUri != nil {
20+
// Only show loading indicator if we have a URL string
21+
ProgressView()
22+
.onAppear {
23+
loadImage()
24+
}}
25+
else {
26+
EmptyView()
27+
}
28+
29+
}
1030
Spacer()
1131
Button {
1232
completeTapped()
@@ -16,6 +36,18 @@ struct TodoListRow: View {
1636
.buttonStyle(.plain)
1737
}
1838
}
39+
40+
private func loadImage() {
41+
guard let urlString = todo.photoUri else {
42+
return
43+
}
44+
let url = URL(fileURLWithPath: urlString)
45+
46+
if let imageData = try? Data(contentsOf: url),
47+
let loadedImage = UIImage(data: imageData) {
48+
self.image = loadedImage
49+
}
50+
}
1951
}
2052

2153

Demo/PowerSyncExample/PowerSync/Schema.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ let lists = Table(
1010
// ID column is automatically included
1111
.text("name"),
1212
.text("created_at"),
13-
.text("owner_id")
13+
.text("owner_id"),
1414
]
1515
)
1616

@@ -26,14 +26,14 @@ let todos = Table(
2626
Column.text("created_at"),
2727
Column.text("completed_at"),
2828
Column.text("created_by"),
29-
Column.text("completed_by")
29+
Column.text("completed_by"),
3030
],
3131
indexes: [
3232
Index(
3333
name: "list_id",
3434
columns: [IndexedColumn.ascending("list_id")]
35-
)
35+
),
3636
]
3737
)
3838

39-
let AppSchema = Schema(lists, todos)
39+
let AppSchema = Schema(lists, todos, createAttachmentsTable(name: "attachments"))

Demo/PowerSyncExample/PowerSync/SupabaseConnector.swift

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
import AnyCodable
12
import Auth
2-
import SwiftUI
3-
import Supabase
43
import PowerSync
5-
import AnyCodable
4+
import Supabase
5+
import SwiftUI
66

7-
private struct PostgresFatalCodes {
7+
private enum PostgresFatalCodes {
88
/// Postgres Response codes that we cannot recover from by retrying.
99
static let fatalResponseCodes: [String] = [
1010
// Class 22 — Data Exception
@@ -14,7 +14,7 @@ private struct PostgresFatalCodes {
1414
// Examples include NOT NULL, FOREIGN KEY and UNIQUE violations.
1515
"23...",
1616
// INSUFFICIENT PRIVILEGE - typically a row-level security violation
17-
"42501"
17+
"42501",
1818
]
1919

2020
static func isFatalError(_ code: String) -> Bool {
@@ -27,20 +27,20 @@ private struct PostgresFatalCodes {
2727
// Look for code: Optional("XXXXX") pattern
2828
let errorString = String(describing: error)
2929
if let range = errorString.range(of: "code: Optional\\(\"([^\"]+)\"\\)", options: .regularExpression),
30-
let codeRange = errorString[range].range(of: "\"([^\"]+)\"", options: .regularExpression) {
31-
// Extract just the code from within the quotes
32-
let code = errorString[codeRange].dropFirst().dropLast()
33-
return String(code)
34-
}
30+
let codeRange = errorString[range].range(of: "\"([^\"]+)\"", options: .regularExpression)
31+
{
32+
// Extract just the code from within the quotes
33+
let code = errorString[codeRange].dropFirst().dropLast()
34+
return String(code)
35+
}
3536
return nil
3637
}
3738
}
3839

39-
4040
@Observable
4141
class SupabaseConnector: PowerSyncBackendConnector {
4242
let powerSyncEndpoint: String = Secrets.powerSyncEndpoint
43-
let client: SupabaseClient = SupabaseClient(supabaseURL: Secrets.supabaseURL, supabaseKey: Secrets.supabaseAnonKey)
43+
let client: SupabaseClient = .init(supabaseURL: Secrets.supabaseURL, supabaseKey: Secrets.supabaseAnonKey)
4444
var session: Session?
4545
private var errorCode: String?
4646

@@ -68,20 +68,23 @@ class SupabaseConnector: PowerSyncBackendConnector {
6868
return id.uuidString.lowercased()
6969
}
7070

71+
func getStorageBucket() -> StorageFileApi {
72+
return client.storage.from(Secrets.supabaseStorageBucket)
73+
}
74+
7175
override func fetchCredentials() async throws -> PowerSyncCredentials? {
7276
session = try await client.auth.session
7377

74-
if (self.session == nil) {
78+
if session == nil {
7579
throw AuthError.sessionMissing
7680
}
7781

7882
let token = session!.accessToken
7983

80-
return PowerSyncCredentials(endpoint: self.powerSyncEndpoint, token: token)
84+
return PowerSyncCredentials(endpoint: powerSyncEndpoint, token: token)
8185
}
8286

8387
override func uploadData(database: PowerSyncDatabaseProtocol) async throws {
84-
8588
guard let transaction = try await database.getNextCrudTransaction() else { return }
8689

8790
var lastEntry: CrudEntry?
@@ -96,39 +99,36 @@ class SupabaseConnector: PowerSyncBackendConnector {
9699
case .put:
97100
var data: [String: AnyCodable] = entry.opData?.mapValues { AnyCodable($0) } ?? [:]
98101
data["id"] = AnyCodable(entry.id)
99-
try await table.upsert(data).execute();
102+
try await table.upsert(data).execute()
100103
case .patch:
101104
guard let opData = entry.opData else { continue }
102105
let encodableData = opData.mapValues { AnyCodable($0) }
103106
try await table.update(encodableData).eq("id", value: entry.id).execute()
104107
case .delete:
105-
try await table.delete().eq( "id", value: entry.id).execute()
108+
try await table.delete().eq("id", value: entry.id).execute()
106109
}
107110
}
108111

109112
_ = try await transaction.complete.invoke(p1: nil)
110113

111114
} catch {
112115
if let errorCode = PostgresFatalCodes.extractErrorCode(from: error),
113-
PostgresFatalCodes.isFatalError(errorCode) {
114-
/// Instead of blocking the queue with these errors,
115-
/// discard the (rest of the) transaction.
116-
///
117-
/// Note that these errors typically indicate a bug in the application.
118-
/// If protecting against data loss is important, save the failing records
119-
/// elsewhere instead of discarding, and/or notify the user.
120-
print("Data upload error: \(error)")
121-
print("Discarding entry: \(lastEntry!)")
122-
_ = try await transaction.complete.invoke(p1: nil)
123-
return
124-
}
116+
PostgresFatalCodes.isFatalError(errorCode)
117+
{
118+
/// Instead of blocking the queue with these errors,
119+
/// discard the (rest of the) transaction.
120+
///
121+
/// Note that these errors typically indicate a bug in the application.
122+
/// If protecting against data loss is important, save the failing records
123+
/// elsewhere instead of discarding, and/or notify the user.
124+
print("Data upload error: \(error)")
125+
print("Discarding entry: \(lastEntry!)")
126+
_ = try await transaction.complete.invoke(p1: nil)
127+
return
128+
}
125129

126130
print("Data upload error - retrying last entry: \(lastEntry!), \(error)")
127131
throw error
128132
}
129133
}
130-
131-
deinit {
132-
observeAuthStateChangesTask?.cancel()
133-
}
134134
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import Foundation
2+
import PowerSync
3+
import Supabase
4+
5+
class SupabaseRemoteStorage: RemoteStorageAdapter {
6+
let storage: Supabase.StorageFileApi
7+
8+
init(storage: Supabase.StorageFileApi) {
9+
self.storage = storage
10+
}
11+
12+
func uploadFile(fileData: Data, attachment: PowerSync.Attachment) async throws {
13+
try await storage.upload(attachment.filename, data: fileData)
14+
}
15+
16+
func downloadFile(attachment: PowerSync.Attachment) async throws -> Data {
17+
try await storage.download(path: attachment.filename)
18+
}
19+
20+
func deleteFile(attachment: PowerSync.Attachment) async throws {
21+
_ = try await storage.remove(paths: [attachment.filename])
22+
}
23+
}

0 commit comments

Comments
 (0)