diff --git a/demos/supabase-todolist/README.md b/demos/supabase-todolist/README.md index 4845b3e1..55241dde 100644 --- a/demos/supabase-todolist/README.md +++ b/demos/supabase-todolist/README.md @@ -43,7 +43,8 @@ bucket_definitions: - select * from todos where list_id = bucket.list_id ``` -The rules synchronize list with a higher priority the items within the list. This can be +**Note**: These rules showcase [prioritized sync](https://docs.powersync.com/usage/use-case-examples/prioritized-sync), +by syncing a user's lists with a higher priority than the items within a list (todos). This can be useful to keep the list overview page reactive during a large sync cycle affecting many rows in the `user_todos` bucket. The two buckets can also be unified into a single one if priorities are not important (the app will work without changes): diff --git a/demos/supabase-todolist/lib/widgets/lists_page.dart b/demos/supabase-todolist/lib/widgets/lists_page.dart index 5b237b4e..d60cb9f5 100644 --- a/demos/supabase-todolist/lib/widgets/lists_page.dart +++ b/demos/supabase-todolist/lib/widgets/lists_page.dart @@ -1,7 +1,6 @@ -import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:powersync/powersync.dart'; +import 'package:powersync_flutter_demo/powersync.dart'; import './list_item.dart'; import './list_item_dialog.dart'; @@ -42,63 +41,36 @@ class ListsPage extends StatelessWidget { } } -class ListsWidget extends StatefulWidget { +final class ListsWidget extends StatelessWidget { const ListsWidget({super.key}); - @override - State createState() { - return _ListsWidgetState(); - } -} - -class _ListsWidgetState extends State { - static final _listsPriority = BucketPriority(1); - - List _data = []; - bool hasSynced = false; - StreamSubscription? _subscription; - StreamSubscription? _syncStatusSubscription; - - _ListsWidgetState(); - - @override - void initState() { - super.initState(); - final stream = TodoList.watchListsWithStats(); - _subscription = stream.listen((data) { - if (!context.mounted) { - return; - } - setState(() { - _data = data; - }); - }); - _syncStatusSubscription = TodoList.watchSyncStatus().listen((status) { - if (!context.mounted) { - return; - } - setState(() { - hasSynced = status.statusForPriority(_listsPriority).hasSynced ?? false; - }); - }); - } - - @override - void dispose() { - super.dispose(); - _subscription?.cancel(); - _syncStatusSubscription?.cancel(); - } - @override Widget build(BuildContext context) { - return !hasSynced - ? const Text("Busy with sync...") - : ListView( - padding: const EdgeInsets.symmetric(vertical: 8.0), - children: _data.map((list) { - return ListItemWidget(list: list); - }).toList(), + return FutureBuilder( + future: db.waitForFirstSync(priority: _listsPriority), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + return StreamBuilder( + stream: TodoList.watchListsWithStats(), + builder: (context, snapshot) { + if (snapshot.data case final todoLists?) { + return ListView( + padding: const EdgeInsets.symmetric(vertical: 8.0), + children: todoLists.map((list) { + return ListItemWidget(list: list); + }).toList(), + ); + } else { + return const CircularProgressIndicator(); + } + }, ); + } else { + return const Text('Busy with sync...'); + } + }, + ); } + + static final _listsPriority = BucketPriority(1); }