Skip to content

Commit 4c07484

Browse files
authored
Sync streams (#317)
1 parent a34349c commit 4c07484

33 files changed

+1782
-442
lines changed

demos/benchmarks/pubspec.lock

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,10 @@ packages:
111111
dependency: "direct main"
112112
description:
113113
name: http
114-
sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
114+
sha256: bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007
115115
url: "https://pub.dev"
116116
source: hosted
117-
version: "1.4.0"
117+
version: "1.5.0"
118118
http_parser:
119119
dependency: transitive
120120
description:
@@ -135,26 +135,26 @@ packages:
135135
dependency: transitive
136136
description:
137137
name: leak_tracker
138-
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
138+
sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0"
139139
url: "https://pub.dev"
140140
source: hosted
141-
version: "10.0.9"
141+
version: "11.0.1"
142142
leak_tracker_flutter_testing:
143143
dependency: transitive
144144
description:
145145
name: leak_tracker_flutter_testing
146-
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
146+
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
147147
url: "https://pub.dev"
148148
source: hosted
149-
version: "3.0.9"
149+
version: "3.0.10"
150150
leak_tracker_testing:
151151
dependency: transitive
152152
description:
153153
name: leak_tracker_testing
154-
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
154+
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
155155
url: "https://pub.dev"
156156
source: hosted
157-
version: "3.0.1"
157+
version: "3.0.2"
158158
lints:
159159
dependency: transitive
160160
description:
@@ -281,21 +281,21 @@ packages:
281281
path: "../../packages/powersync"
282282
relative: true
283283
source: path
284-
version: "1.15.0"
284+
version: "1.15.2"
285285
powersync_core:
286286
dependency: "direct overridden"
287287
description:
288288
path: "../../packages/powersync_core"
289289
relative: true
290290
source: path
291-
version: "1.5.0"
291+
version: "1.5.2"
292292
powersync_flutter_libs:
293293
dependency: "direct overridden"
294294
description:
295295
path: "../../packages/powersync_flutter_libs"
296296
relative: true
297297
source: path
298-
version: "0.4.10"
298+
version: "0.4.11"
299299
pub_semver:
300300
dependency: transitive
301301
description:
@@ -337,10 +337,10 @@ packages:
337337
dependency: transitive
338338
description:
339339
name: sqlite3
340-
sha256: "310af39c40dd0bb2058538333c9d9840a2725ae0b9f77e4fd09ad6696aa8f66e"
340+
sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
341341
url: "https://pub.dev"
342342
source: hosted
343-
version: "2.7.5"
343+
version: "2.9.0"
344344
sqlite3_flutter_libs:
345345
dependency: transitive
346346
description:
@@ -353,18 +353,18 @@ packages:
353353
dependency: transitive
354354
description:
355355
name: sqlite3_web
356-
sha256: "967e076442f7e1233bd7241ca61f3efe4c7fc168dac0f38411bdb3bdf471eb3c"
356+
sha256: "0f6ebcb4992d1892ac5c8b5ecd22a458ab9c5eb6428b11ae5ecb5d63545844da"
357357
url: "https://pub.dev"
358358
source: hosted
359-
version: "0.3.1"
359+
version: "0.3.2"
360360
sqlite_async:
361361
dependency: "direct main"
362362
description:
363363
name: sqlite_async
364-
sha256: a60e8d5c8df8e694933bd5a312c38393e79ad77d784bb91c6f38ba627bfb7aec
364+
sha256: "6116bfc6aef6ce77730b478385ba4a58873df45721f6a9bc6ffabf39b6576e36"
365365
url: "https://pub.dev"
366366
source: hosted
367-
version: "0.11.4"
367+
version: "0.12.1"
368368
stack_trace:
369369
dependency: transitive
370370
description:
@@ -401,10 +401,10 @@ packages:
401401
dependency: transitive
402402
description:
403403
name: test_api
404-
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
404+
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
405405
url: "https://pub.dev"
406406
source: hosted
407-
version: "0.7.4"
407+
version: "0.7.6"
408408
typed_data:
409409
dependency: transitive
410410
description:
@@ -433,10 +433,10 @@ packages:
433433
dependency: transitive
434434
description:
435435
name: vector_math
436-
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
436+
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
437437
url: "https://pub.dev"
438438
source: hosted
439-
version: "2.1.4"
439+
version: "2.2.0"
440440
vm_service:
441441
dependency: transitive
442442
description:
@@ -470,5 +470,5 @@ packages:
470470
source: hosted
471471
version: "3.1.3"
472472
sdks:
473-
dart: ">=3.7.0 <4.0.0"
473+
dart: ">=3.8.0-0 <4.0.0"
474474
flutter: ">=3.27.0"

demos/django-todolist/lib/widgets/guard_by_sync.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import 'package:powersync_django_todolist_demo/powersync.dart';
77
class GuardBySync extends StatelessWidget {
88
final Widget child;
99

10-
/// When set, wait only for a complete sync within the [BucketPriority]
10+
/// When set, wait only for a complete sync within the [StreamPriority]
1111
/// instead of a full sync.
12-
final BucketPriority? priority;
12+
final StreamPriority? priority;
1313

1414
const GuardBySync({
1515
super.key,

demos/supabase-todolist-drift/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

demos/supabase-todolist-drift/lib/powersync/powersync.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,19 @@ Future<PowerSyncDatabase> powerSyncInstance(Ref ref) async {
4747
return db;
4848
}
4949

50-
final _syncStatusInternal = StreamProvider((ref) {
50+
final _syncStatusInternal = StreamProvider<SyncStatus?>((ref) {
5151
return Stream.fromFuture(
5252
ref.watch(powerSyncInstanceProvider.future),
53-
).asyncExpand((db) => db.statusStream).startWith(const SyncStatus());
53+
).asyncExpand<SyncStatus?>((db) => db.statusStream).startWith(null);
5454
});
5555

5656
final syncStatus = Provider((ref) {
57+
// ignore: invalid_use_of_internal_member
5758
return ref.watch(_syncStatusInternal).value ?? const SyncStatus();
5859
});
5960

6061
@riverpod
61-
bool didCompleteSync(Ref ref, [BucketPriority? priority]) {
62+
bool didCompleteSync(Ref ref, [StreamPriority? priority]) {
6263
final status = ref.watch(syncStatus);
6364
if (priority != null) {
6465
return status.statusForPriority(priority).hasSynced ?? false;

demos/supabase-todolist-drift/lib/screens/lists.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ final class _ListsWidget extends ConsumerWidget {
3535
@override
3636
Widget build(BuildContext context, WidgetRef ref) {
3737
final lists = ref.watch(listsNotifierProvider);
38-
final didSync = ref.watch(didCompleteSyncProvider(BucketPriority(1)));
38+
final didSync = ref.watch(didCompleteSyncProvider(StreamPriority(1)));
3939

4040
if (!didSync) {
4141
return const Text('Busy with sync...');

demos/supabase-todolist/lib/app_config_template.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@ class AppConfig {
66
static const String powersyncUrl = 'https://foo.powersync.journeyapps.com';
77
static const String supabaseStorageBucket =
88
''; // Optional. Only required when syncing attachments and using Supabase Storage. See packages/powersync_attachments_helper.
9+
// Whether the PowerSync instance uses sync streams to make fetching todo
10+
// items optional.
11+
static const bool hasSyncStreams = false;
912
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import 'package:powersync_flutter_demo/powersync.dart';
77
class GuardBySync extends StatelessWidget {
88
final Widget child;
99

10-
/// When set, wait only for a complete sync within the [BucketPriority]
10+
/// When set, wait only for a complete sync within the [StreamPriority]
1111
/// instead of a full sync.
12-
final BucketPriority? priority;
12+
final StreamPriority? priority;
1313

1414
const GuardBySync({
1515
super.key,
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import 'package:flutter/material.dart';
2+
3+
import '../powersync.dart';
4+
import './todo_list_page.dart';
5+
import '../models/todo_list.dart';
6+
7+
/// A variant of the `ListItem` that only shows a summary of completed and
8+
/// pending items when the respective list has an active sync stream.
9+
class SyncStreamsAwareListItem extends StatelessWidget {
10+
SyncStreamsAwareListItem({
11+
required this.list,
12+
}) : super(key: ObjectKey(list));
13+
14+
final TodoList list;
15+
16+
Future<void> delete() async {
17+
// Server will take care of deleting related todos
18+
await list.delete();
19+
}
20+
21+
@override
22+
Widget build(BuildContext context) {
23+
viewList() {
24+
var navigator = Navigator.of(context);
25+
26+
navigator.push(
27+
MaterialPageRoute(builder: (context) => TodoListPage(list: list)));
28+
}
29+
30+
return StreamBuilder(
31+
stream: db.statusStream,
32+
initialData: db.currentStatus,
33+
builder: (context, asyncSnapshot) {
34+
final status = asyncSnapshot.requireData;
35+
final stream =
36+
status.forStream(db.syncStream('todos', {'list': list.id}));
37+
38+
String subtext;
39+
if (stream == null || !stream.subscription.active) {
40+
subtext = 'Items not loaded - click to fetch.';
41+
} else {
42+
subtext =
43+
'${list.pendingCount} pending, ${list.completedCount} completed';
44+
}
45+
46+
return Card(
47+
child: Column(
48+
mainAxisSize: MainAxisSize.min,
49+
children: <Widget>[
50+
ListTile(
51+
onTap: viewList,
52+
leading: const Icon(Icons.list),
53+
title: Text(list.name),
54+
subtitle: Text(subtext),
55+
),
56+
Row(
57+
mainAxisAlignment: MainAxisAlignment.end,
58+
children: <Widget>[
59+
IconButton(
60+
iconSize: 30,
61+
icon: const Icon(
62+
Icons.delete,
63+
color: Colors.red,
64+
),
65+
tooltip: 'Delete List',
66+
alignment: Alignment.centerRight,
67+
onPressed: delete,
68+
),
69+
const SizedBox(width: 8),
70+
],
71+
),
72+
],
73+
),
74+
);
75+
},
76+
);
77+
}
78+
}

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import 'package:flutter/material.dart';
22
import 'package:powersync/powersync.dart';
33

4+
import '../app_config.dart';
45
import './list_item.dart';
56
import './list_item_dialog.dart';
67
import '../main.dart';
78
import '../models/todo_list.dart';
89
import 'guard_by_sync.dart';
10+
import 'list_item_sync_stream.dart';
911

1012
void _showAddDialog(BuildContext context) async {
1113
return showDialog<void>(
@@ -55,7 +57,9 @@ class ListsWidget extends StatelessWidget {
5557
return ListView(
5658
padding: const EdgeInsets.symmetric(vertical: 8.0),
5759
children: todoLists.map((list) {
58-
return ListItemWidget(list: list);
60+
return AppConfig.hasSyncStreams
61+
? SyncStreamsAwareListItem(list: list)
62+
: ListItemWidget(list: list);
5963
}).toList(),
6064
);
6165
} else {
@@ -66,5 +70,5 @@ class ListsWidget extends StatelessWidget {
6670
);
6771
}
6872

69-
static final _listsPriority = BucketPriority(1);
73+
static final _listsPriority = StreamPriority(1);
7074
}

0 commit comments

Comments
 (0)