Skip to content

Commit bd3b435

Browse files
committed
Adopt in example
1 parent 61a4c4d commit bd3b435

File tree

8 files changed

+117
-27
lines changed

8 files changed

+117
-27
lines changed

demos/supabase-todolist/lib/widgets/todo_list_page.dart

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:flutter/material.dart';
2+
import 'package:powersync/powersync.dart';
23

34
import '../powersync.dart';
45
import './status_app_bar.dart';
@@ -38,30 +39,82 @@ class TodoListPage extends StatelessWidget {
3839
}
3940
}
4041

41-
class TodoListWidget extends StatelessWidget {
42+
class TodoListWidget extends StatefulWidget {
4243
final TodoList list;
4344

4445
const TodoListWidget({super.key, required this.list});
4546

47+
@override
48+
State<TodoListWidget> createState() => _TodoListWidgetState();
49+
}
50+
51+
class _TodoListWidgetState extends State<TodoListWidget> {
52+
SyncStreamSubscription? _listSubscription;
53+
54+
void _subscribe(String listId) {
55+
db
56+
.syncStream('todos', {'list': listId})
57+
.subscribe(ttl: const Duration(hours: 1))
58+
.then((sub) {
59+
if (mounted && widget.list.id == listId) {
60+
setState(() {
61+
_listSubscription = sub;
62+
});
63+
} else {
64+
sub.unsubscribe();
65+
}
66+
});
67+
}
68+
69+
@override
70+
void initState() {
71+
super.initState();
72+
_subscribe(widget.list.id);
73+
}
74+
75+
@override
76+
void didUpdateWidget(covariant TodoListWidget oldWidget) {
77+
super.didUpdateWidget(oldWidget);
78+
_subscribe(widget.list.id);
79+
}
80+
81+
@override
82+
void dispose() {
83+
super.dispose();
84+
_listSubscription?.unsubscribe();
85+
}
86+
4687
@override
4788
Widget build(BuildContext context) {
4889
return StreamBuilder(
49-
stream: TodoList.watchSyncStatus().map((e) => e.hasSynced),
50-
initialData: db.currentStatus.hasSynced,
90+
stream: db.statusStream,
91+
initialData: db.currentStatus,
5192
builder: (context, snapshot) {
52-
return StreamBuilder(
53-
stream: list.watchItems(),
54-
builder: (context, snapshot) {
55-
final items = snapshot.data ?? const [];
56-
57-
return ListView(
58-
padding: const EdgeInsets.symmetric(vertical: 8.0),
59-
children: items.map((todo) {
60-
return TodoItemWidget(todo: todo);
61-
}).toList(),
62-
);
63-
},
64-
);
93+
final hasSynced = switch (_listSubscription) {
94+
null => null,
95+
final sub => snapshot.requireData.statusFor(sub),
96+
}
97+
?.subscription
98+
.hasSynced ??
99+
false;
100+
101+
if (!hasSynced) {
102+
return const CircularProgressIndicator();
103+
} else {
104+
return StreamBuilder(
105+
stream: widget.list.watchItems(),
106+
builder: (context, snapshot) {
107+
final items = snapshot.data ?? const [];
108+
109+
return ListView(
110+
padding: const EdgeInsets.symmetric(vertical: 8.0),
111+
children: items.map((todo) {
112+
return TodoItemWidget(todo: todo);
113+
}).toList(),
114+
);
115+
},
116+
);
117+
}
65118
},
66119
);
67120
}

demos/supabase-todolist/pubspec.lock

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -605,10 +605,10 @@ packages:
605605
dependency: transitive
606606
description:
607607
name: sqlite3
608-
sha256: "310af39c40dd0bb2058538333c9d9840a2725ae0b9f77e4fd09ad6696aa8f66e"
608+
sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
609609
url: "https://pub.dev"
610610
source: hosted
611-
version: "2.7.5"
611+
version: "2.9.0"
612612
sqlite3_flutter_libs:
613613
dependency: transitive
614614
description:
@@ -621,18 +621,17 @@ packages:
621621
dependency: transitive
622622
description:
623623
name: sqlite3_web
624-
sha256: "967e076442f7e1233bd7241ca61f3efe4c7fc168dac0f38411bdb3bdf471eb3c"
624+
sha256: "0f6ebcb4992d1892ac5c8b5ecd22a458ab9c5eb6428b11ae5ecb5d63545844da"
625625
url: "https://pub.dev"
626626
source: hosted
627-
version: "0.3.1"
627+
version: "0.3.2"
628628
sqlite_async:
629629
dependency: "direct main"
630630
description:
631-
name: sqlite_async
632-
sha256: "9332aedd311a19dd215dcb55729bc68dc587dc7655b569ab8819b68ee0be0082"
633-
url: "https://pub.dev"
634-
source: hosted
635-
version: "0.11.7"
631+
path: "/Users/simon/src/sqlite_async.dart/packages/sqlite_async"
632+
relative: false
633+
source: path
634+
version: "0.12.1"
636635
stack_trace:
637636
dependency: transitive
638637
description:

packages/powersync_core/lib/src/database/native/native_powersync_database.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ Future<void> _syncIsolate(_PowerSyncDatabaseIsolateArgs args) async {
376376
await shutdown();
377377
} else if (action == 'changed_subscriptions') {
378378
openedStreamingSync
379-
?.updateSubscriptions(action[1] as List<SubscribedStream>);
379+
?.updateSubscriptions(message[1] as List<SubscribedStream>);
380380
}
381381
}
382382
});

packages/powersync_core/lib/src/sync/options.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,15 @@ extension type ResolvedSyncOptions(SyncOptions source) {
107107
crudThrottleTime: other.crudThrottleTime ?? crudThrottleTime,
108108
retryDelay: other.retryDelay ?? retryDelay,
109109
params: other.params ?? params,
110+
syncImplementation: other.syncImplementation,
110111
includeDefaultStreams:
111112
other.includeDefaultStreams ?? includeDefaultStreams,
112113
);
113114

114115
final didChange = !_mapEquality.equals(newOptions.params, params) ||
115116
newOptions.crudThrottleTime != crudThrottleTime ||
116117
newOptions.retryDelay != retryDelay ||
118+
newOptions.syncImplementation != source.syncImplementation ||
117119
newOptions.includeDefaultStreams != includeDefaultStreams;
118120
return (ResolvedSyncOptions(newOptions), didChange);
119121
}

packages/powersync_core/lib/src/sync/stream.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,24 @@ final class CoreActiveStreamSubscription implements SyncSubscriptionDefinition {
144144
},
145145
);
146146
}
147+
148+
Map<String, Object?> toJson() {
149+
return {
150+
'name': name,
151+
'parameters': parameters,
152+
'priority': priority.priorityNumber,
153+
'associated_buckets': associatedBuckets,
154+
'active': active,
155+
'is_default': isDefault,
156+
'has_explicit_subscription': hasExplicitSubscription,
157+
'expires_at': switch (expiresAt) {
158+
null => null,
159+
final expiresAt => expiresAt.millisecondsSinceEpoch / 1000,
160+
},
161+
'last_synced_at': switch (lastSyncedAt) {
162+
null => null,
163+
final lastSyncedAt => lastSyncedAt.millisecondsSinceEpoch / 1000,
164+
}
165+
};
166+
}
147167
}

packages/powersync_core/lib/src/sync/sync_status.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ final class SyncStatus {
5858

5959
final List<CoreActiveStreamSubscription>? _internalSubscriptions;
6060

61+
@internal
6162
const SyncStatus({
6263
this.connected = false,
6364
this.connecting = false,

packages/powersync_core/lib/src/web/sync_worker.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ class _ConnectedClient {
109109
_runner = null;
110110
return (JSObject(), null);
111111
case SyncWorkerMessageType.updateSubscriptions:
112+
_runner?.updateClientSubscriptions(
113+
this, (payload as UpdateSubscriptions).toDart);
112114
return (JSObject(), null);
113115
default:
114116
throw StateError('Unexpected message type $type');

packages/powersync_core/lib/src/web/sync_worker_protocol.dart

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'dart:js_interop';
55
import 'package:logging/logging.dart';
66
import 'package:powersync_core/src/schema.dart';
77
import 'package:powersync_core/src/sync/options.dart';
8+
import 'package:powersync_core/src/sync/stream.dart';
89
import 'package:web/web.dart';
910

1011
import '../connector.dart';
@@ -247,6 +248,7 @@ extension type SerializedSyncStatus._(JSObject _) implements JSObject {
247248
required String? downloadError,
248249
required JSArray? priorityStatusEntries,
249250
required JSArray<SerializedBucketProgress>? syncProgress,
251+
required JSString streamSubscriptions,
250252
});
251253

252254
factory SerializedSyncStatus.from(SyncStatus status) {
@@ -272,6 +274,7 @@ extension type SerializedSyncStatus._(JSObject _) implements JSObject {
272274
var other => SerializedBucketProgress.serialize(
273275
InternalSyncDownloadProgress.ofPublic(other).buckets),
274276
},
277+
streamSubscriptions: json.encode(status.internalSubscriptions).toJS,
275278
);
276279
}
277280

@@ -285,8 +288,11 @@ extension type SerializedSyncStatus._(JSObject _) implements JSObject {
285288
external String? downloadError;
286289
external JSArray? priorityStatusEntries;
287290
external JSArray<SerializedBucketProgress>? syncProgress;
291+
external JSString? streamSubscriptions;
288292

289293
SyncStatus asSyncStatus() {
294+
final streamSubscriptions = this.streamSubscriptions?.toDart;
295+
290296
return SyncStatus(
291297
connected: connected,
292298
connecting: connecting,
@@ -306,7 +312,7 @@ extension type SerializedSyncStatus._(JSObject _) implements JSObject {
306312
final syncedMillis = (rawSynced as JSNumber?)?.toDartInt;
307313

308314
return (
309-
priority: BucketPriority((rawPriority as JSNumber).toDartInt),
315+
priority: StreamPriority((rawPriority as JSNumber).toDartInt),
310316
lastSyncedAt: syncedMillis != null
311317
? DateTime.fromMicrosecondsSinceEpoch(syncedMillis)
312318
: null,
@@ -320,6 +326,13 @@ extension type SerializedSyncStatus._(JSObject _) implements JSObject {
320326
SerializedBucketProgress.deserialize(serializedProgress))
321327
.asSyncDownloadProgress,
322328
},
329+
streamSubscriptions: switch (streamSubscriptions) {
330+
null => null,
331+
final serialized => (json.decode(serialized) as List)
332+
.map((e) => CoreActiveStreamSubscription.fromJson(
333+
e as Map<String, Object?>))
334+
.toList(),
335+
},
323336
);
324337
}
325338
}

0 commit comments

Comments
 (0)