diff --git a/demos/supabase-todolist-drift/.gitignore b/demos/supabase-todolist-drift/.gitignore index b5e97dcc..f4850867 100644 --- a/demos/supabase-todolist-drift/.gitignore +++ b/demos/supabase-todolist-drift/.gitignore @@ -5,9 +5,11 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ migrate_working_dir/ # IntelliJ related diff --git a/demos/supabase-todolist-drift/lib/attachments/photo_capture_widget.dart b/demos/supabase-todolist-drift/lib/attachments/photo_capture_widget.dart index aa742c42..441b286c 100644 --- a/demos/supabase-todolist-drift/lib/attachments/photo_capture_widget.dart +++ b/demos/supabase-todolist-drift/lib/attachments/photo_capture_widget.dart @@ -2,11 +2,12 @@ import 'dart:async'; import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:powersync/powersync.dart' as powersync; import 'package:supabase_todolist_drift/attachments/queue.dart'; import 'package:supabase_todolist_drift/powersync.dart'; -class TakePhotoWidget extends StatefulWidget { +class TakePhotoWidget extends ConsumerStatefulWidget { final String todoId; final CameraDescription camera; @@ -14,12 +15,12 @@ class TakePhotoWidget extends StatefulWidget { {super.key, required this.todoId, required this.camera}); @override - State createState() { + ConsumerState createState() { return _TakePhotoWidgetState(); } } -class _TakePhotoWidgetState extends State { +class _TakePhotoWidgetState extends ConsumerState { late CameraController _cameraController; late Future _initializeControllerFuture; @@ -56,7 +57,7 @@ class _TakePhotoWidgetState extends State { int photoSize = await photo.length(); - await appDb.addTodoPhoto(widget.todoId, photoId); + await ref.read(driftDatabase).addTodoPhoto(widget.todoId, photoId); await attachmentQueue.saveFile(photoId, photoSize); } catch (e) { log.info('Error taking photo: $e'); diff --git a/demos/supabase-todolist-drift/lib/database.dart b/demos/supabase-todolist-drift/lib/database.dart index cf307d72..66553e0d 100644 --- a/demos/supabase-todolist-drift/lib/database.dart +++ b/demos/supabase-todolist-drift/lib/database.dart @@ -1,7 +1,5 @@ import 'package:drift/drift.dart'; -import 'package:powersync/powersync.dart' show PowerSyncDatabase, uuid; -import 'package:drift_sqlite_async/drift_sqlite_async.dart'; -import 'package:supabase_todolist_drift/powersync.dart'; +import 'package:powersync/powersync.dart' show uuid; part 'database.g.dart'; @@ -32,21 +30,21 @@ class ListItems extends Table { TextColumn get ownerId => text().nullable().named('owner_id')(); } -class ListItemWithStats { - late ListItem self; - int completedCount; - int pendingCount; +final class ListItemWithStats { + final ListItem self; + final int completedCount; + final int pendingCount; - ListItemWithStats( + const ListItemWithStats( this.self, this.completedCount, this.pendingCount, ); } -@DriftDatabase(tables: [TodoItems, ListItems], include: {'queries.drift'}) +@DriftDatabase(tables: [TodoItems, ListItems]) class AppDatabase extends _$AppDatabase { - AppDatabase(PowerSyncDatabase db) : super(SqliteAsyncDriftConnection(db)); + AppDatabase(super.e); @override int get schemaVersion => 1; @@ -57,13 +55,9 @@ class AppDatabase extends _$AppDatabase { .watch(); } - Stream> watchListsWithStats() { - return listsWithStats().watch(); - } - - Future createList(String name) async { + Future createList(String name, String? userId) async { return into(listItems).insertReturning( - ListItemsCompanion.insert(name: name, ownerId: Value(getUserId()))); + ListItemsCompanion.insert(name: name, ownerId: Value(userId))); } Future deleteList(ListItem list) async { @@ -81,21 +75,23 @@ class AppDatabase extends _$AppDatabase { await (delete(todoItems)..where((t) => t.id.equals(todo.id))).go(); } - Future addTodo(ListItem list, String description) async { + Future addTodo( + ListItem list, String description, String? creator) async { return into(todoItems).insertReturning(TodoItemsCompanion.insert( - listId: list.id, - description: description, - completed: const Value(false), - createdBy: Value(getUserId()))); + listId: list.id, + description: description, + completed: const Value(false), + createdBy: Value(creator), + )); } - Future toggleTodo(TodoItem todo) async { + Future toggleTodo(TodoItem todo, String? userId) async { if (todo.completed != true) { await (update(todoItems)..where((t) => t.id.equals(todo.id))).write( TodoItemsCompanion( completed: const Value(true), completedAt: Value(DateTime.now()), - completedBy: Value(getUserId()))); + completedBy: Value(userId))); } else { await (update(todoItems)..where((t) => t.id.equals(todo.id))).write( const TodoItemsCompanion( diff --git a/demos/supabase-todolist-drift/lib/database.g.dart b/demos/supabase-todolist-drift/lib/database.g.dart index 438ea554..7023d8ba 100644 --- a/demos/supabase-todolist-drift/lib/database.g.dart +++ b/demos/supabase-todolist-drift/lib/database.g.dart @@ -763,20 +763,6 @@ abstract class _$AppDatabase extends GeneratedDatabase { $AppDatabaseManager get managers => $AppDatabaseManager(this); late final $ListItemsTable listItems = $ListItemsTable(this); late final $TodoItemsTable todoItems = $TodoItemsTable(this); - Selectable listsWithStats() { - return customSelect( - 'SELECT"self"."id" AS "nested_0.id", "self"."created_at" AS "nested_0.created_at", "self"."name" AS "nested_0.name", "self"."owner_id" AS "nested_0.owner_id", (SELECT count() FROM todos WHERE list_id = self.id AND completed = TRUE) AS completed_count, (SELECT count() FROM todos WHERE list_id = self.id AND completed = FALSE) AS pending_count FROM lists AS self ORDER BY created_at', - variables: [], - readsFrom: { - todoItems, - listItems, - }).asyncMap((QueryRow row) async => ListItemWithStats( - await listItems.mapFromRow(row, tablePrefix: 'nested_0'), - row.read('completed_count'), - row.read('pending_count'), - )); - } - @override Iterable> get allTables => allSchemaEntities.whereType>(); @@ -814,7 +800,7 @@ final class $$ListItemsTableReferences $$TodoItemsTableProcessedTableManager get todoItemsRefs { final manager = $$TodoItemsTableTableManager($_db, $_db.todoItems) - .filter((f) => f.listId.id($_item.id)); + .filter((f) => f.listId.id.sqlEquals($_itemColumn('id')!)); final cache = $_typedResult.readTableOrNull(_todoItemsRefsTable($_db)); return ProcessedTableManager( @@ -823,64 +809,111 @@ final class $$ListItemsTableReferences } class $$ListItemsTableFilterComposer - extends FilterComposer<_$AppDatabase, $ListItemsTable> { - $$ListItemsTableFilterComposer(super.$state); - ColumnFilters get id => $state.composableBuilder( - column: $state.table.id, - builder: (column, joinBuilders) => - ColumnFilters(column, joinBuilders: joinBuilders)); - - ColumnFilters get createdAt => $state.composableBuilder( - column: $state.table.createdAt, - builder: (column, joinBuilders) => - ColumnFilters(column, joinBuilders: joinBuilders)); - - ColumnFilters get name => $state.composableBuilder( - column: $state.table.name, - builder: (column, joinBuilders) => - ColumnFilters(column, joinBuilders: joinBuilders)); - - ColumnFilters get ownerId => $state.composableBuilder( - column: $state.table.ownerId, - builder: (column, joinBuilders) => - ColumnFilters(column, joinBuilders: joinBuilders)); - - ComposableFilter todoItemsRefs( - ComposableFilter Function($$TodoItemsTableFilterComposer f) f) { - final $$TodoItemsTableFilterComposer composer = $state.composerBuilder( + extends Composer<_$AppDatabase, $ListItemsTable> { + $$ListItemsTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, builder: (column) => ColumnFilters(column)); + + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, builder: (column) => ColumnFilters(column)); + + ColumnFilters get name => $composableBuilder( + column: $table.name, builder: (column) => ColumnFilters(column)); + + ColumnFilters get ownerId => $composableBuilder( + column: $table.ownerId, builder: (column) => ColumnFilters(column)); + + Expression todoItemsRefs( + Expression Function($$TodoItemsTableFilterComposer f) f) { + final $$TodoItemsTableFilterComposer composer = $composerBuilder( composer: this, getCurrentColumn: (t) => t.id, - referencedTable: $state.db.todoItems, + referencedTable: $db.todoItems, getReferencedColumn: (t) => t.listId, - builder: (joinBuilder, parentComposers) => - $$TodoItemsTableFilterComposer(ComposerState( - $state.db, $state.db.todoItems, joinBuilder, parentComposers))); + builder: (joinBuilder, + {$addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer}) => + $$TodoItemsTableFilterComposer( + $db: $db, + $table: $db.todoItems, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + )); return f(composer); } } class $$ListItemsTableOrderingComposer - extends OrderingComposer<_$AppDatabase, $ListItemsTable> { - $$ListItemsTableOrderingComposer(super.$state); - ColumnOrderings get id => $state.composableBuilder( - column: $state.table.id, - builder: (column, joinBuilders) => - ColumnOrderings(column, joinBuilders: joinBuilders)); - - ColumnOrderings get createdAt => $state.composableBuilder( - column: $state.table.createdAt, - builder: (column, joinBuilders) => - ColumnOrderings(column, joinBuilders: joinBuilders)); - - ColumnOrderings get name => $state.composableBuilder( - column: $state.table.name, - builder: (column, joinBuilders) => - ColumnOrderings(column, joinBuilders: joinBuilders)); - - ColumnOrderings get ownerId => $state.composableBuilder( - column: $state.table.ownerId, - builder: (column, joinBuilders) => - ColumnOrderings(column, joinBuilders: joinBuilders)); + extends Composer<_$AppDatabase, $ListItemsTable> { + $$ListItemsTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get name => $composableBuilder( + column: $table.name, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get ownerId => $composableBuilder( + column: $table.ownerId, builder: (column) => ColumnOrderings(column)); +} + +class $$ListItemsTableAnnotationComposer + extends Composer<_$AppDatabase, $ListItemsTable> { + $$ListItemsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + GeneratedColumn get name => + $composableBuilder(column: $table.name, builder: (column) => column); + + GeneratedColumn get ownerId => + $composableBuilder(column: $table.ownerId, builder: (column) => column); + + Expression todoItemsRefs( + Expression Function($$TodoItemsTableAnnotationComposer a) f) { + final $$TodoItemsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.todoItems, + getReferencedColumn: (t) => t.listId, + builder: (joinBuilder, + {$addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer}) => + $$TodoItemsTableAnnotationComposer( + $db: $db, + $table: $db.todoItems, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + )); + return f(composer); + } } class $$ListItemsTableTableManager extends RootTableManager< @@ -889,6 +922,7 @@ class $$ListItemsTableTableManager extends RootTableManager< ListItem, $$ListItemsTableFilterComposer, $$ListItemsTableOrderingComposer, + $$ListItemsTableAnnotationComposer, $$ListItemsTableCreateCompanionBuilder, $$ListItemsTableUpdateCompanionBuilder, (ListItem, $$ListItemsTableReferences), @@ -898,10 +932,12 @@ class $$ListItemsTableTableManager extends RootTableManager< : super(TableManagerState( db: db, table: table, - filteringComposer: - $$ListItemsTableFilterComposer(ComposerState(db, table)), - orderingComposer: - $$ListItemsTableOrderingComposer(ComposerState(db, table)), + createFilteringComposer: () => + $$ListItemsTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$ListItemsTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$ListItemsTableAnnotationComposer($db: db, $table: table), updateCompanionCallback: ({ Value id = const Value.absent(), Value createdAt = const Value.absent(), @@ -944,7 +980,8 @@ class $$ListItemsTableTableManager extends RootTableManager< getPrefetchedDataCallback: (items) async { return [ if (todoItemsRefs) - await $_getPrefetchedData( + await $_getPrefetchedData( currentTable: table, referencedTable: $$ListItemsTableReferences._todoItemsRefsTable(db), @@ -968,6 +1005,7 @@ typedef $$ListItemsTableProcessedTableManager = ProcessedTableManager< ListItem, $$ListItemsTableFilterComposer, $$ListItemsTableOrderingComposer, + $$ListItemsTableAnnotationComposer, $$ListItemsTableCreateCompanionBuilder, $$ListItemsTableUpdateCompanionBuilder, (ListItem, $$ListItemsTableReferences), @@ -1005,10 +1043,11 @@ final class $$TodoItemsTableReferences static $ListItemsTable _listIdTable(_$AppDatabase db) => db.listItems .createAlias($_aliasNameGenerator(db.todoItems.listId, db.listItems.id)); - $$ListItemsTableProcessedTableManager? get listId { - if ($_item.listId == null) return null; + $$ListItemsTableProcessedTableManager get listId { + final $_column = $_itemColumn('list_id')!; + final manager = $$ListItemsTableTableManager($_db, $_db.listItems) - .filter((f) => f.id($_item.listId!)); + .filter((f) => f.id.sqlEquals($_column)); final item = $_typedResult.readTableOrNull(_listIdTable($_db)); if (item == null) return manager; return ProcessedTableManager( @@ -1017,113 +1056,163 @@ final class $$TodoItemsTableReferences } class $$TodoItemsTableFilterComposer - extends FilterComposer<_$AppDatabase, $TodoItemsTable> { - $$TodoItemsTableFilterComposer(super.$state); - ColumnFilters get id => $state.composableBuilder( - column: $state.table.id, - builder: (column, joinBuilders) => - ColumnFilters(column, joinBuilders: joinBuilders)); - - ColumnFilters get photoId => $state.composableBuilder( - column: $state.table.photoId, - builder: (column, joinBuilders) => - ColumnFilters(column, joinBuilders: joinBuilders)); - - ColumnFilters get createdAt => $state.composableBuilder( - column: $state.table.createdAt, - builder: (column, joinBuilders) => - ColumnFilters(column, joinBuilders: joinBuilders)); - - ColumnFilters get completedAt => $state.composableBuilder( - column: $state.table.completedAt, - builder: (column, joinBuilders) => - ColumnFilters(column, joinBuilders: joinBuilders)); - - ColumnFilters get completed => $state.composableBuilder( - column: $state.table.completed, - builder: (column, joinBuilders) => - ColumnFilters(column, joinBuilders: joinBuilders)); - - ColumnFilters get description => $state.composableBuilder( - column: $state.table.description, - builder: (column, joinBuilders) => - ColumnFilters(column, joinBuilders: joinBuilders)); - - ColumnFilters get createdBy => $state.composableBuilder( - column: $state.table.createdBy, - builder: (column, joinBuilders) => - ColumnFilters(column, joinBuilders: joinBuilders)); - - ColumnFilters get completedBy => $state.composableBuilder( - column: $state.table.completedBy, - builder: (column, joinBuilders) => - ColumnFilters(column, joinBuilders: joinBuilders)); + extends Composer<_$AppDatabase, $TodoItemsTable> { + $$TodoItemsTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, builder: (column) => ColumnFilters(column)); + + ColumnFilters get photoId => $composableBuilder( + column: $table.photoId, builder: (column) => ColumnFilters(column)); + + ColumnFilters get createdAt => $composableBuilder( + column: $table.createdAt, builder: (column) => ColumnFilters(column)); + + ColumnFilters get completedAt => $composableBuilder( + column: $table.completedAt, builder: (column) => ColumnFilters(column)); + + ColumnFilters get completed => $composableBuilder( + column: $table.completed, builder: (column) => ColumnFilters(column)); + + ColumnFilters get description => $composableBuilder( + column: $table.description, builder: (column) => ColumnFilters(column)); + + ColumnFilters get createdBy => $composableBuilder( + column: $table.createdBy, builder: (column) => ColumnFilters(column)); + + ColumnFilters get completedBy => $composableBuilder( + column: $table.completedBy, builder: (column) => ColumnFilters(column)); $$ListItemsTableFilterComposer get listId { - final $$ListItemsTableFilterComposer composer = $state.composerBuilder( + final $$ListItemsTableFilterComposer composer = $composerBuilder( composer: this, getCurrentColumn: (t) => t.listId, - referencedTable: $state.db.listItems, + referencedTable: $db.listItems, getReferencedColumn: (t) => t.id, - builder: (joinBuilder, parentComposers) => - $$ListItemsTableFilterComposer(ComposerState( - $state.db, $state.db.listItems, joinBuilder, parentComposers))); + builder: (joinBuilder, + {$addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer}) => + $$ListItemsTableFilterComposer( + $db: $db, + $table: $db.listItems, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + )); return composer; } } class $$TodoItemsTableOrderingComposer - extends OrderingComposer<_$AppDatabase, $TodoItemsTable> { - $$TodoItemsTableOrderingComposer(super.$state); - ColumnOrderings get id => $state.composableBuilder( - column: $state.table.id, - builder: (column, joinBuilders) => - ColumnOrderings(column, joinBuilders: joinBuilders)); - - ColumnOrderings get photoId => $state.composableBuilder( - column: $state.table.photoId, - builder: (column, joinBuilders) => - ColumnOrderings(column, joinBuilders: joinBuilders)); - - ColumnOrderings get createdAt => $state.composableBuilder( - column: $state.table.createdAt, - builder: (column, joinBuilders) => - ColumnOrderings(column, joinBuilders: joinBuilders)); - - ColumnOrderings get completedAt => $state.composableBuilder( - column: $state.table.completedAt, - builder: (column, joinBuilders) => - ColumnOrderings(column, joinBuilders: joinBuilders)); - - ColumnOrderings get completed => $state.composableBuilder( - column: $state.table.completed, - builder: (column, joinBuilders) => - ColumnOrderings(column, joinBuilders: joinBuilders)); - - ColumnOrderings get description => $state.composableBuilder( - column: $state.table.description, - builder: (column, joinBuilders) => - ColumnOrderings(column, joinBuilders: joinBuilders)); - - ColumnOrderings get createdBy => $state.composableBuilder( - column: $state.table.createdBy, - builder: (column, joinBuilders) => - ColumnOrderings(column, joinBuilders: joinBuilders)); - - ColumnOrderings get completedBy => $state.composableBuilder( - column: $state.table.completedBy, - builder: (column, joinBuilders) => - ColumnOrderings(column, joinBuilders: joinBuilders)); + extends Composer<_$AppDatabase, $TodoItemsTable> { + $$TodoItemsTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get photoId => $composableBuilder( + column: $table.photoId, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get createdAt => $composableBuilder( + column: $table.createdAt, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get completedAt => $composableBuilder( + column: $table.completedAt, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get completed => $composableBuilder( + column: $table.completed, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get description => $composableBuilder( + column: $table.description, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get createdBy => $composableBuilder( + column: $table.createdBy, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get completedBy => $composableBuilder( + column: $table.completedBy, builder: (column) => ColumnOrderings(column)); $$ListItemsTableOrderingComposer get listId { - final $$ListItemsTableOrderingComposer composer = $state.composerBuilder( + final $$ListItemsTableOrderingComposer composer = $composerBuilder( composer: this, getCurrentColumn: (t) => t.listId, - referencedTable: $state.db.listItems, + referencedTable: $db.listItems, getReferencedColumn: (t) => t.id, - builder: (joinBuilder, parentComposers) => - $$ListItemsTableOrderingComposer(ComposerState( - $state.db, $state.db.listItems, joinBuilder, parentComposers))); + builder: (joinBuilder, + {$addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer}) => + $$ListItemsTableOrderingComposer( + $db: $db, + $table: $db.listItems, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + )); + return composer; + } +} + +class $$TodoItemsTableAnnotationComposer + extends Composer<_$AppDatabase, $TodoItemsTable> { + $$TodoItemsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get photoId => + $composableBuilder(column: $table.photoId, builder: (column) => column); + + GeneratedColumn get createdAt => + $composableBuilder(column: $table.createdAt, builder: (column) => column); + + GeneratedColumn get completedAt => $composableBuilder( + column: $table.completedAt, builder: (column) => column); + + GeneratedColumn get completed => + $composableBuilder(column: $table.completed, builder: (column) => column); + + GeneratedColumn get description => $composableBuilder( + column: $table.description, builder: (column) => column); + + GeneratedColumn get createdBy => + $composableBuilder(column: $table.createdBy, builder: (column) => column); + + GeneratedColumn get completedBy => $composableBuilder( + column: $table.completedBy, builder: (column) => column); + + $$ListItemsTableAnnotationComposer get listId { + final $$ListItemsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.listId, + referencedTable: $db.listItems, + getReferencedColumn: (t) => t.id, + builder: (joinBuilder, + {$addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer}) => + $$ListItemsTableAnnotationComposer( + $db: $db, + $table: $db.listItems, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + )); return composer; } } @@ -1134,6 +1223,7 @@ class $$TodoItemsTableTableManager extends RootTableManager< TodoItem, $$TodoItemsTableFilterComposer, $$TodoItemsTableOrderingComposer, + $$TodoItemsTableAnnotationComposer, $$TodoItemsTableCreateCompanionBuilder, $$TodoItemsTableUpdateCompanionBuilder, (TodoItem, $$TodoItemsTableReferences), @@ -1143,10 +1233,12 @@ class $$TodoItemsTableTableManager extends RootTableManager< : super(TableManagerState( db: db, table: table, - filteringComposer: - $$TodoItemsTableFilterComposer(ComposerState(db, table)), - orderingComposer: - $$TodoItemsTableOrderingComposer(ComposerState(db, table)), + createFilteringComposer: () => + $$TodoItemsTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$TodoItemsTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$TodoItemsTableAnnotationComposer($db: db, $table: table), updateCompanionCallback: ({ Value id = const Value.absent(), Value listId = const Value.absent(), @@ -1216,6 +1308,7 @@ class $$TodoItemsTableTableManager extends RootTableManager< dynamic, dynamic, dynamic, + dynamic, dynamic>>(state) { if (listId) { state = state.withJoin( @@ -1244,6 +1337,7 @@ typedef $$TodoItemsTableProcessedTableManager = ProcessedTableManager< TodoItem, $$TodoItemsTableFilterComposer, $$TodoItemsTableOrderingComposer, + $$TodoItemsTableAnnotationComposer, $$TodoItemsTableCreateCompanionBuilder, $$TodoItemsTableUpdateCompanionBuilder, (TodoItem, $$TodoItemsTableReferences), diff --git a/demos/supabase-todolist-drift/lib/fts_helpers.dart b/demos/supabase-todolist-drift/lib/fts_helpers.dart index 5e5ad5c3..52382c1e 100644 --- a/demos/supabase-todolist-drift/lib/fts_helpers.dart +++ b/demos/supabase-todolist-drift/lib/fts_helpers.dart @@ -1,5 +1,9 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:supabase_todolist_drift/powersync.dart'; +part 'fts_helpers.g.dart'; + String _createSearchTermWithOptions(String searchTerm) { // adding * to the end of the search term will match any word that starts with the search term // e.g. searching bl will match blue, black, etc. @@ -9,8 +13,10 @@ String _createSearchTermWithOptions(String searchTerm) { } /// Search the FTS table for the given searchTerm -Future search(String searchTerm, String tableName) async { +@riverpod +Future search(Ref ref, String searchTerm, String tableName) async { String searchTermWithOptions = _createSearchTermWithOptions(searchTerm); + final db = await ref.read(initializePowerSyncProvider.future); return await db.getAll( 'SELECT * FROM fts_$tableName WHERE fts_$tableName MATCH ? ORDER BY rank', [searchTermWithOptions]); diff --git a/demos/supabase-todolist-drift/lib/fts_helpers.g.dart b/demos/supabase-todolist-drift/lib/fts_helpers.g.dart new file mode 100644 index 00000000..0f0957a5 --- /dev/null +++ b/demos/supabase-todolist-drift/lib/fts_helpers.g.dart @@ -0,0 +1,188 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'fts_helpers.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$searchHash() => r'007a62d1af172ec30f3aecf71bd6e53cbcf6e00e'; + +/// Copied from Dart SDK +class _SystemHash { + _SystemHash._(); + + static int combine(int hash, int value) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + value); + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); + return hash ^ (hash >> 6); + } + + static int finish(int hash) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); + // ignore: parameter_assignments + hash = hash ^ (hash >> 11); + return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); + } +} + +/// Search the FTS table for the given searchTerm +/// +/// Copied from [search]. +@ProviderFor(search) +const searchProvider = SearchFamily(); + +/// Search the FTS table for the given searchTerm +/// +/// Copied from [search]. +class SearchFamily extends Family> { + /// Search the FTS table for the given searchTerm + /// + /// Copied from [search]. + const SearchFamily(); + + /// Search the FTS table for the given searchTerm + /// + /// Copied from [search]. + SearchProvider call( + String searchTerm, + String tableName, + ) { + return SearchProvider( + searchTerm, + tableName, + ); + } + + @override + SearchProvider getProviderOverride( + covariant SearchProvider provider, + ) { + return call( + provider.searchTerm, + provider.tableName, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'searchProvider'; +} + +/// Search the FTS table for the given searchTerm +/// +/// Copied from [search]. +class SearchProvider extends AutoDisposeFutureProvider { + /// Search the FTS table for the given searchTerm + /// + /// Copied from [search]. + SearchProvider( + String searchTerm, + String tableName, + ) : this._internal( + (ref) => search( + ref as SearchRef, + searchTerm, + tableName, + ), + from: searchProvider, + name: r'searchProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$searchHash, + dependencies: SearchFamily._dependencies, + allTransitiveDependencies: SearchFamily._allTransitiveDependencies, + searchTerm: searchTerm, + tableName: tableName, + ); + + SearchProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.searchTerm, + required this.tableName, + }) : super.internal(); + + final String searchTerm; + final String tableName; + + @override + Override overrideWith( + FutureOr Function(SearchRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: SearchProvider._internal( + (ref) => create(ref as SearchRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + searchTerm: searchTerm, + tableName: tableName, + ), + ); + } + + @override + AutoDisposeFutureProviderElement createElement() { + return _SearchProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is SearchProvider && + other.searchTerm == searchTerm && + other.tableName == tableName; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, searchTerm.hashCode); + hash = _SystemHash.combine(hash, tableName.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin SearchRef on AutoDisposeFutureProviderRef { + /// The parameter `searchTerm` of this provider. + String get searchTerm; + + /// The parameter `tableName` of this provider. + String get tableName; +} + +class _SearchProviderElement extends AutoDisposeFutureProviderElement + with SearchRef { + _SearchProviderElement(super.provider); + + @override + String get searchTerm => (origin as SearchProvider).searchTerm; + @override + String get tableName => (origin as SearchProvider).tableName; +} +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/demos/supabase-todolist-drift/lib/main.dart b/demos/supabase-todolist-drift/lib/main.dart index fe48f040..4defadfc 100644 --- a/demos/supabase-todolist-drift/lib/main.dart +++ b/demos/supabase-todolist-drift/lib/main.dart @@ -1,9 +1,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:logging/logging.dart'; import 'package:supabase_todolist_drift/app_config.dart'; -import 'package:supabase_todolist_drift/attachments/queue.dart'; import 'package:supabase_todolist_drift/models/schema.dart'; +import 'package:supabase_todolist_drift/supabase.dart'; import 'powersync.dart'; import 'widgets/lists_page.dart'; @@ -30,14 +31,13 @@ void main() async { WidgetsFlutterBinding .ensureInitialized(); //required to get sqlite filepath from path_provider before UI has initialized - await openDatabase(); + await loadSupabase(); if (AppConfig.supabaseStorageBucket.isNotEmpty) { - initializeAttachmentQueue(db); +// initializeAttachmentQueue(db); } - final loggedIn = isLoggedIn(); - runApp(MyApp(loggedIn: loggedIn)); + runApp(const ProviderScope(child: MyApp())); } const defaultQuery = 'SELECT * from $todosTable'; @@ -53,19 +53,18 @@ const loginPage = LoginPage(); const signupPage = SignupPage(); -class MyApp extends StatelessWidget { - final bool loggedIn; - - const MyApp({super.key, required this.loggedIn}); +class MyApp extends ConsumerWidget { + const MyApp({super.key}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { return MaterialApp( - title: 'PowerSync Flutter Demo', - theme: ThemeData( - primarySwatch: Colors.blue, - ), - home: loggedIn ? homePage : loginPage); + title: 'PowerSync Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: ref.watch(isLoggedInProvider) ? homePage : loginPage, + ); } } diff --git a/demos/supabase-todolist-drift/lib/powersync.dart b/demos/supabase-todolist-drift/lib/powersync.dart index 71a16c8d..188d5875 100644 --- a/demos/supabase-todolist-drift/lib/powersync.dart +++ b/demos/supabase-todolist-drift/lib/powersync.dart @@ -1,16 +1,23 @@ // This file performs setup of the PowerSync database +import 'dart:async'; + +import 'package:drift/drift.dart'; +import 'package:drift_sqlite_async/drift_sqlite_async.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:logging/logging.dart'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; import 'package:powersync/powersync.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:supabase_todolist_drift/database.dart'; -import 'package:supabase_todolist_drift/migrations/fts_setup.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; +import 'package:supabase_todolist_drift/utils/stateful_provider.dart'; import 'app_config.dart'; import 'models/schema.dart'; -import 'supabase.dart'; + +part 'powersync.g.dart'; final log = Logger('powersync-supabase'); @@ -132,50 +139,22 @@ class SupabaseConnector extends PowerSyncBackendConnector { } } -/// Global reference to the database -late final PowerSyncDatabase db; -late final AppDatabase appDb; - -bool isLoggedIn() { - return Supabase.instance.client.auth.currentSession?.accessToken != null; -} - -/// id of the user currently logged in -String? getUserId() { - return Supabase.instance.client.auth.currentSession?.user.id; -} - -Future getDatabasePath() async { - const dbFilename = 'powersync-demo.db'; - // getApplicationSupportDirectory is not supported on Web - if (kIsWeb) { - return dbFilename; - } - final dir = await getApplicationSupportDirectory(); - return join(dir.path, dbFilename); -} - -Future openDatabase() async { - // Open the local database - db = PowerSyncDatabase( - schema: schema, path: await getDatabasePath(), logger: attachedLogger); +@Riverpod(keepAlive: true) +Future initializePowerSync(Ref ref) async { + final db = PowerSyncDatabase( + schema: schema, path: await _getDatabasePath(), logger: attachedLogger); await db.initialize(); - // Initialize the Drift database - appDb = AppDatabase(db); - - await loadSupabase(); SupabaseConnector? currentConnector; - if (isLoggedIn()) { - // If the user is already logged in, connect immediately. - // Otherwise, connect once logged in. + if (ref.read(session) != null) { currentConnector = SupabaseConnector(); db.connect(connector: currentConnector); } - Supabase.instance.client.auth.onAuthStateChange.listen((data) async { - final AuthChangeEvent event = data.event; + final instance = Supabase.instance.client.auth; + final sub = instance.onAuthStateChange.listen((data) async { + final event = data.event; if (event == AuthChangeEvent.signedIn) { // Connect to PowerSync when the user is signed in currentConnector = SupabaseConnector(); @@ -189,14 +168,66 @@ Future openDatabase() async { currentConnector?.prefetchCredentials(); } }); + ref.onDispose(sub.cancel); - // Demo using SQLite Full-Text Search with PowerSync. - // See https://docs.powersync.com/usage-examples/full-text-search for more details - await configureFts(db); + return db; +} + +final session = statefulProvider((ref, change) { + final instance = Supabase.instance.client.auth; + + final sub = instance.onAuthStateChange.listen((data) { + change(instance.currentSession); + }); + ref.onDispose(sub.cancel); + + return instance.currentSession; +}); + +final syncStatus = statefulProvider((ref, change) { + final status = Stream.fromFuture(ref.read(initializePowerSyncProvider.future)) + .asyncExpand((db) => db.statusStream); + final sub = status.listen(change); + ref.onDispose(sub.cancel); + + return const SyncStatus(); +}); + +final driftDatabase = Provider((ref) { + final powerSync = ref.read(initializePowerSyncProvider.future); + return AppDatabase(DatabaseConnection.delayed(Future(() async { + return SqliteAsyncDriftConnection(await powerSync); + }))); +}); + +@riverpod +bool isLoggedIn(Ref ref) { + return ref.watch(session) != null; +} + +@riverpod +String? userId(Ref ref) { + return ref.watch(session)?.user.id; +} + +@riverpod +bool didCompleteSync(Ref ref) { + final status = ref.watch(syncStatus); + return status.hasSynced ?? false; +} + +Future _getDatabasePath() async { + const dbFilename = 'powersync-demo.db'; + // getApplicationSupportDirectory is not supported on Web + if (kIsWeb) { + return dbFilename; + } + final dir = await getApplicationSupportDirectory(); + return join(dir.path, dbFilename); } /// Explicit sign out - clear database and log out. Future logout() async { await Supabase.instance.client.auth.signOut(); - await db.disconnectAndClear(); +// await db.disconnectAndClear(); } diff --git a/demos/supabase-todolist-drift/lib/powersync.g.dart b/demos/supabase-todolist-drift/lib/powersync.g.dart new file mode 100644 index 00000000..bb9bccd6 --- /dev/null +++ b/demos/supabase-todolist-drift/lib/powersync.g.dart @@ -0,0 +1,77 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'powersync.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$initializePowerSyncHash() => + r'a047d3d19c415d66c6a35371bc3f8b56575ea4da'; + +/// See also [initializePowerSync]. +@ProviderFor(initializePowerSync) +final initializePowerSyncProvider = FutureProvider.internal( + initializePowerSync, + name: r'initializePowerSyncProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$initializePowerSyncHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef InitializePowerSyncRef = FutureProviderRef; +String _$isLoggedInHash() => r'4de54b56ee8d5bba766f81dcbcfe033f3c905250'; + +/// See also [isLoggedIn]. +@ProviderFor(isLoggedIn) +final isLoggedInProvider = AutoDisposeProvider.internal( + isLoggedIn, + name: r'isLoggedInProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$isLoggedInHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef IsLoggedInRef = AutoDisposeProviderRef; +String _$userIdHash() => r'0489ac84e34b0d0da777bbd4a46a72db1c065963'; + +/// See also [userId]. +@ProviderFor(userId) +final userIdProvider = AutoDisposeProvider.internal( + userId, + name: r'userIdProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$userIdHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef UserIdRef = AutoDisposeProviderRef; +String _$didCompleteSyncHash() => r'bf10133683f82127499f21bbeec63792a2cb791b'; + +/// See also [didCompleteSync]. +@ProviderFor(didCompleteSync) +final didCompleteSyncProvider = AutoDisposeProvider.internal( + didCompleteSync, + name: r'didCompleteSyncProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$didCompleteSyncHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef DidCompleteSyncRef = AutoDisposeProviderRef; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/demos/supabase-todolist-drift/lib/queries.drift b/demos/supabase-todolist-drift/lib/queries.drift index 5ac70ceb..cd0d24ce 100644 --- a/demos/supabase-todolist-drift/lib/queries.drift +++ b/demos/supabase-todolist-drift/lib/queries.drift @@ -6,4 +6,4 @@ listsWithStats WITH ListItemWithStats: (SELECT count() FROM todos WHERE list_id = self.id AND completed = TRUE) as completed_count, (SELECT count() FROM todos WHERE list_id = self.id AND completed = FALSE) as pending_count FROM lists as self - ORDER BY created_at; \ No newline at end of file + ORDER BY created_at; diff --git a/demos/supabase-todolist-drift/lib/utils/stateful_provider.dart b/demos/supabase-todolist-drift/lib/utils/stateful_provider.dart new file mode 100644 index 00000000..59981322 --- /dev/null +++ b/demos/supabase-todolist-drift/lib/utils/stateful_provider.dart @@ -0,0 +1,19 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final class _StatefulNotifier extends Notifier { + T? _currentValue; + final T Function(Ref, void Function(T)) _initial; + + _StatefulNotifier(this._initial); + + @override + T build() => _currentValue ??= _initial(ref, (updated) { + _currentValue = state = updated; + }); +} + +NotifierProvider, T> statefulProvider( + T Function(Ref ref, void Function(T) change) initialValue, +) { + return NotifierProvider(() => _StatefulNotifier(initialValue)); +} diff --git a/demos/supabase-todolist-drift/lib/widgets/fts_search_delegate.dart b/demos/supabase-todolist-drift/lib/widgets/fts_search_delegate.dart index 521ef0e6..f24576b9 100644 --- a/demos/supabase-todolist-drift/lib/widgets/fts_search_delegate.dart +++ b/demos/supabase-todolist-drift/lib/widgets/fts_search_delegate.dart @@ -1,11 +1,15 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:logging/logging.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:supabase_todolist_drift/database.dart'; import 'package:supabase_todolist_drift/fts_helpers.dart' as fts_helpers; import 'package:supabase_todolist_drift/powersync.dart'; import 'todo_list_page.dart'; +part 'fts_search_delegate.g.dart'; + final log = Logger('powersync-supabase'); class FtsSearchDelegate extends SearchDelegate { @@ -33,80 +37,86 @@ class FtsSearchDelegate extends SearchDelegate { @override Widget buildResults(BuildContext context) { - return FutureBuilder( - future: _search(), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.done) { + return Consumer(builder: (context, ref, _) { + final results = ref.watch(_searchProvider(query)); + + return results.maybeWhen( + data: (rows) { return ListView.builder( itemBuilder: (context, index) { return ListTile( - title: Text(snapshot.data?[index].name), + title: Text(rows[index]['name']), onTap: () { close(context, null); }, ); }, - itemCount: snapshot.data?.length, + itemCount: rows.length, ); - } else { - return const Center( - child: CircularProgressIndicator(), - ); - } - }, - ); + }, + orElse: () => const Center( + child: CircularProgressIndicator(), + ), + ); + }); } @override Widget buildSuggestions(BuildContext context) { NavigatorState navigator = Navigator.of(context); - return FutureBuilder( - future: _search(), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - return ListView.builder( - itemBuilder: (context, index) { - return ListTile( - title: Text(snapshot.data?[index]['name'] ?? ''), - onTap: () async { - ListItem list = - await appDb.findList(snapshot.data![index]['id']); - navigator.push(MaterialPageRoute( - builder: (context) => TodoListPage(list: list), - )); - }, - ); - }, - itemCount: snapshot.data?.length, - ); - } else { - return const Center( + return Consumer( + builder: (context, ref, _) { + final results = ref.watch(_searchProvider(query)); + final appDb = ref.watch(driftDatabase); + + return results.maybeWhen( + data: (rows) { + return ListView.builder( + itemBuilder: (context, index) { + return ListTile( + title: Text(rows[index]['name'] ?? ''), + onTap: () async { + ListItem list = await appDb.findList(rows[index]['id']); + navigator.push(MaterialPageRoute( + builder: (context) => TodoListPage(list: list), + )); + }, + ); + }, + itemCount: rows.length, + ); + }, + orElse: () => const Center( child: CircularProgressIndicator(), - ); - } + ), + ); }, ); } +} - Future _search() async { - if (query.isEmpty) return []; - List listsSearchResults = await fts_helpers.search(query, 'lists'); - List todoItemsSearchResults = await fts_helpers.search(query, 'todos'); - List formattedListResults = listsSearchResults - .map((result) => {"id": result['id'], "name": result['name']}) - .toList(); - List formattedTodoItemsResults = todoItemsSearchResults - .map((result) => { - // Use list_id so the navigation goes to the list page - "id": result['list_id'], - "name": result['description'], - }) - .toList(); - List formattedResults = [ - ...formattedListResults, - ...formattedTodoItemsResults - ]; - return formattedResults; - } +@riverpod +Future _search(Ref ref, String query) async { + if (query.isEmpty) return []; + final listsSearchResults = + await ref.watch(fts_helpers.searchProvider(query, 'lists').future); + final todoItemsSearchResults = + await ref.watch(fts_helpers.searchProvider(query, 'todos').future); + + List formattedListResults = listsSearchResults + .map((result) => {"id": result['id'], "name": result['name']}) + .toList(); + List formattedTodoItemsResults = todoItemsSearchResults + .map((result) => { + // Use list_id so the navigation goes to the list page + "id": result['list_id'], + "name": result['description'], + }) + .toList(); + List formattedResults = [ + ...formattedListResults, + ...formattedTodoItemsResults + ]; + return formattedResults; } diff --git a/demos/supabase-todolist-drift/lib/widgets/fts_search_delegate.g.dart b/demos/supabase-todolist-drift/lib/widgets/fts_search_delegate.g.dart new file mode 100644 index 00000000..092e3076 --- /dev/null +++ b/demos/supabase-todolist-drift/lib/widgets/fts_search_delegate.g.dart @@ -0,0 +1,159 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'fts_search_delegate.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$searchHash() => r'22f755afc645f10c862d9aece9f392958c10d086'; + +/// Copied from Dart SDK +class _SystemHash { + _SystemHash._(); + + static int combine(int hash, int value) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + value); + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); + return hash ^ (hash >> 6); + } + + static int finish(int hash) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); + // ignore: parameter_assignments + hash = hash ^ (hash >> 11); + return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); + } +} + +/// See also [_search]. +@ProviderFor(_search) +const _searchProvider = _SearchFamily(); + +/// See also [_search]. +class _SearchFamily extends Family> { + /// See also [_search]. + const _SearchFamily(); + + /// See also [_search]. + _SearchProvider call( + String query, + ) { + return _SearchProvider( + query, + ); + } + + @override + _SearchProvider getProviderOverride( + covariant _SearchProvider provider, + ) { + return call( + provider.query, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'_searchProvider'; +} + +/// See also [_search]. +class _SearchProvider extends AutoDisposeFutureProvider { + /// See also [_search]. + _SearchProvider( + String query, + ) : this._internal( + (ref) => _search( + ref as _SearchRef, + query, + ), + from: _searchProvider, + name: r'_searchProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$searchHash, + dependencies: _SearchFamily._dependencies, + allTransitiveDependencies: _SearchFamily._allTransitiveDependencies, + query: query, + ); + + _SearchProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.query, + }) : super.internal(); + + final String query; + + @override + Override overrideWith( + FutureOr Function(_SearchRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: _SearchProvider._internal( + (ref) => create(ref as _SearchRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + query: query, + ), + ); + } + + @override + AutoDisposeFutureProviderElement createElement() { + return _SearchProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is _SearchProvider && other.query == query; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, query.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin _SearchRef on AutoDisposeFutureProviderRef { + /// The parameter `query` of this provider. + String get query; +} + +class _SearchProviderElement extends AutoDisposeFutureProviderElement + with _SearchRef { + _SearchProviderElement(super.provider); + + @override + String get query => (origin as _SearchProvider).query; +} +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/demos/supabase-todolist-drift/lib/widgets/list_item.dart b/demos/supabase-todolist-drift/lib/widgets/list_item.dart index 19c5d798..b21fc0a0 100644 --- a/demos/supabase-todolist-drift/lib/widgets/list_item.dart +++ b/demos/supabase-todolist-drift/lib/widgets/list_item.dart @@ -1,24 +1,26 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:supabase_todolist_drift/database.dart'; import 'package:supabase_todolist_drift/powersync.dart'; import 'todo_list_page.dart'; -class ListItemWidget extends StatelessWidget { +class ListItemWidget extends ConsumerWidget { ListItemWidget({ required this.list, }) : super(key: ObjectKey(list)); final ListItemWithStats list; - Future delete() async { - // Server will take care of deleting related todos - await appDb.deleteList(list.self); - } - @override - Widget build(BuildContext context) { - viewList() { + Widget build(BuildContext context, WidgetRef ref) { + Future delete() async { + // Server will take care of deleting related todos + final db = ref.read(driftDatabase); + await db.deleteList(list.self); + } + + void viewList() { var navigator = Navigator.of(context); navigator.push(MaterialPageRoute( diff --git a/demos/supabase-todolist-drift/lib/widgets/list_item_dialog.dart b/demos/supabase-todolist-drift/lib/widgets/list_item_dialog.dart index 50d0009c..78f64f89 100644 --- a/demos/supabase-todolist-drift/lib/widgets/list_item_dialog.dart +++ b/demos/supabase-todolist-drift/lib/widgets/list_item_dialog.dart @@ -1,36 +1,25 @@ import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:supabase_todolist_drift/powersync.dart'; -class ListItemDialog extends StatefulWidget { +final class ListItemDialog extends HookConsumerWidget { const ListItemDialog({super.key}); @override - State createState() { - return _ListItemDialogState(); - } -} - -class _ListItemDialogState extends State { - final TextEditingController _textFieldController = TextEditingController(); + Widget build(BuildContext context, WidgetRef ref) { + final textController = useTextEditingController(); - _ListItemDialogState(); + Future add() async { + await ref + .read(driftDatabase) + .createList(textController.text, ref.read(userIdProvider)); + } - @override - void dispose() { - super.dispose(); - _textFieldController.dispose(); - } - - Future add() async { - await appDb.createList(_textFieldController.text); - } - - @override - Widget build(BuildContext context) { return AlertDialog( title: const Text('Add a new list'), content: TextField( - controller: _textFieldController, + controller: textController, decoration: const InputDecoration(hintText: 'List name'), onSubmitted: (value) async { Navigator.of(context).pop(); @@ -42,7 +31,7 @@ class _ListItemDialogState extends State { OutlinedButton( child: const Text('Cancel'), onPressed: () { - _textFieldController.clear(); + textController.clear(); Navigator.of(context).pop(); }, ), diff --git a/demos/supabase-todolist-drift/lib/widgets/lists_page.dart b/demos/supabase-todolist-drift/lib/widgets/lists_page.dart index 52e3beed..4142915c 100644 --- a/demos/supabase-todolist-drift/lib/widgets/lists_page.dart +++ b/demos/supabase-todolist-drift/lib/widgets/lists_page.dart @@ -1,13 +1,27 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:supabase_todolist_drift/database.dart'; import 'package:supabase_todolist_drift/powersync.dart'; +import 'package:drift_riverpod/drift_riverpod.dart'; import 'list_item.dart'; import 'list_item_dialog.dart'; import '../main.dart'; +part 'lists_page.g.dart'; + +@QueryProvider() +final listsWithStats = driftDatabase.stats(''' + SELECT + self.**, + (SELECT count() FROM todos WHERE list_id = self.id AND completed = TRUE) as completed_count, + (SELECT count() FROM todos WHERE list_id = self.id AND completed = FALSE) as pending_count + FROM lists as self + ORDER BY created_at; +'''); + void _showAddDialog(BuildContext context) async { return showDialog( context: context, @@ -42,61 +56,29 @@ class ListsPage extends StatelessWidget { } } -class ListsWidget extends StatefulWidget { +final class ListsWidget extends ConsumerWidget { const ListsWidget({super.key}); @override - State createState() { - return _ListsWidgetState(); - } -} + Widget build(BuildContext context, WidgetRef ref) { + final lists = ref.watch(listsWithStats); + final didSync = ref.watch(didCompleteSyncProvider); -class _ListsWidgetState extends State { - List _data = []; - bool hasSynced = false; - StreamSubscription? _subscription; - StreamSubscription? _syncStatusSubscription; - - _ListsWidgetState(); - - @override - void initState() { - super.initState(); - final stream = appDb.watchListsWithStats(); - _subscription = stream.listen((data) { - if (!context.mounted) { - return; - } - setState(() { - _data = data; - }); - }); - _syncStatusSubscription = db.statusStream.listen((status) { - if (!context.mounted) { - return; - } - setState(() { - hasSynced = status.hasSynced ?? false; - }); - }); - } + if (!didSync) { + return const Text('Busy with sync...'); + } - @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 lists.map( + data: (data) { + return ListView( + padding: const EdgeInsets.symmetric(vertical: 8.0), + children: data.value.map((list) { + return ListItemWidget(list: list); + }).toList(), + ); + }, + error: (_) => const Text('Error loading lists'), + loading: (_) => const CircularProgressIndicator(), + ); } } diff --git a/demos/supabase-todolist-drift/lib/widgets/lists_page.g.dart b/demos/supabase-todolist-drift/lib/widgets/lists_page.g.dart new file mode 100644 index 00000000..60ca7a70 --- /dev/null +++ b/demos/supabase-todolist-drift/lib/widgets/lists_page.g.dart @@ -0,0 +1,30 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'lists_page.dart'; + +// ************************************************************************** +// DriftRiverpodGenerator +// ************************************************************************** + +extension on AppDatabase { + Selectable listsWithStats() { + return customSelect( + 'SELECT"self"."id" AS "nested_0.id", "self"."created_at" AS "nested_0.created_at", "self"."name" AS "nested_0.name", "self"."owner_id" AS "nested_0.owner_id", (SELECT count() FROM todos WHERE list_id = self.id AND completed = TRUE) AS completed_count, (SELECT count() FROM todos WHERE list_id = self.id AND completed = FALSE) AS pending_count FROM lists AS self ORDER BY created_at', + variables: [], + readsFrom: { + todoItems, + listItems, + }).asyncMap((QueryRow row) async => ListItemWithStats( + await listItems.mapFromRow(row, tablePrefix: 'nested_0'), + row.read('completed_count'), + row.read('pending_count'), + )); + } +} + +extension on DatabaseProvider { + SelectableProvider> stats(String _) { + return queryProviderImpl( + (ref) => ref.watch(driftDatabase).listsWithStats()); + } +} diff --git a/demos/supabase-todolist-drift/lib/widgets/query_widget.dart b/demos/supabase-todolist-drift/lib/widgets/query_widget.dart index a3ea9654..bcd14f13 100644 --- a/demos/supabase-todolist-drift/lib/widgets/query_widget.dart +++ b/demos/supabase-todolist-drift/lib/widgets/query_widget.dart @@ -1,88 +1,48 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:powersync/sqlite3_common.dart' as sqlite; +import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'resultset_table.dart'; import '../powersync.dart'; -class QueryWidget extends StatefulWidget { - final String defaultQuery; - - const QueryWidget({super.key, required this.defaultQuery}); +part 'query_widget.g.dart'; - @override - State createState() { - return QueryWidgetState(); - } +@riverpod +Stream _watch(Ref ref, String sql) async* { + final db = await ref.read(initializePowerSyncProvider.future); + yield* db.watch(sql); } -class QueryWidgetState extends State { - sqlite.ResultSet? _data; - late TextEditingController _controller; - late String _query; - String? _error; - StreamSubscription? _subscription; - - QueryWidgetState(); +final class QueryWidget extends HookConsumerWidget { + final String defaultQuery; - @override - void initState() { - super.initState(); - _error = null; - _controller = TextEditingController(text: widget.defaultQuery); - _query = _controller.text; - _refresh(); - } + const QueryWidget({super.key, required this.defaultQuery}); @override - void dispose() { - super.dispose(); - _controller.dispose(); - _subscription?.cancel(); - } + Widget build(BuildContext context, WidgetRef ref) { + final query = useState(defaultQuery); + final controller = useTextEditingController(); + final rows = ref.watch(_watchProvider(query.value)); - _refresh() async { - _subscription?.cancel(); - final stream = db.watch(_query); - _subscription = stream.listen((data) { - if (!context.mounted) { - return; - } - setState(() { - _data = data; - _error = null; - }); - }, onError: (e) { - setState(() { - if (e is sqlite.SqliteException) { - _error = "${e.message}!"; - } else { - _error = e.toString(); - } - }); - }); - } - - @override - Widget build(BuildContext context) { return Column( children: [ Padding( padding: const EdgeInsets.all(12), child: TextField( - controller: _controller, + controller: controller, onEditingComplete: () { - setState(() { - _query = _controller.text; - _refresh(); - }); + query.value = controller.text; }, decoration: InputDecoration( - isDense: false, - border: const OutlineInputBorder(), - labelText: 'Query', - errorText: _error), + isDense: false, + border: const OutlineInputBorder(), + labelText: 'Query', + errorText: rows.error?.toString(), + ), ), ), Expanded( @@ -90,7 +50,7 @@ class QueryWidgetState extends State { scrollDirection: Axis.horizontal, child: SingleChildScrollView( scrollDirection: Axis.vertical, - child: ResultSetTable(data: _data), + child: ResultSetTable(data: rows.value), ), )) ], diff --git a/demos/supabase-todolist-drift/lib/widgets/query_widget.g.dart b/demos/supabase-todolist-drift/lib/widgets/query_widget.g.dart new file mode 100644 index 00000000..51b818ea --- /dev/null +++ b/demos/supabase-todolist-drift/lib/widgets/query_widget.g.dart @@ -0,0 +1,159 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'query_widget.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$watchHash() => r'd9e40928647c0aef884c58d0a41758ab9340c912'; + +/// Copied from Dart SDK +class _SystemHash { + _SystemHash._(); + + static int combine(int hash, int value) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + value); + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); + return hash ^ (hash >> 6); + } + + static int finish(int hash) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); + // ignore: parameter_assignments + hash = hash ^ (hash >> 11); + return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); + } +} + +/// See also [_watch]. +@ProviderFor(_watch) +const _watchProvider = _WatchFamily(); + +/// See also [_watch]. +class _WatchFamily extends Family> { + /// See also [_watch]. + const _WatchFamily(); + + /// See also [_watch]. + _WatchProvider call( + String sql, + ) { + return _WatchProvider( + sql, + ); + } + + @override + _WatchProvider getProviderOverride( + covariant _WatchProvider provider, + ) { + return call( + provider.sql, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'_watchProvider'; +} + +/// See also [_watch]. +class _WatchProvider extends AutoDisposeStreamProvider { + /// See also [_watch]. + _WatchProvider( + String sql, + ) : this._internal( + (ref) => _watch( + ref as _WatchRef, + sql, + ), + from: _watchProvider, + name: r'_watchProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$watchHash, + dependencies: _WatchFamily._dependencies, + allTransitiveDependencies: _WatchFamily._allTransitiveDependencies, + sql: sql, + ); + + _WatchProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.sql, + }) : super.internal(); + + final String sql; + + @override + Override overrideWith( + Stream Function(_WatchRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: _WatchProvider._internal( + (ref) => create(ref as _WatchRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + sql: sql, + ), + ); + } + + @override + AutoDisposeStreamProviderElement createElement() { + return _WatchProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is _WatchProvider && other.sql == sql; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, sql.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin _WatchRef on AutoDisposeStreamProviderRef { + /// The parameter `sql` of this provider. + String get sql; +} + +class _WatchProviderElement + extends AutoDisposeStreamProviderElement with _WatchRef { + _WatchProviderElement(super.provider); + + @override + String get sql => (origin as _WatchProvider).sql; +} +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/demos/supabase-todolist-drift/lib/widgets/status_app_bar.dart b/demos/supabase-todolist-drift/lib/widgets/status_app_bar.dart index 75098d69..de86d689 100644 --- a/demos/supabase-todolist-drift/lib/widgets/status_app_bar.dart +++ b/demos/supabase-todolist-drift/lib/widgets/status_app_bar.dart @@ -1,50 +1,25 @@ -import 'dart:async'; - import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:powersync/powersync.dart'; import 'package:supabase_todolist_drift/widgets/fts_search_delegate.dart'; import '../powersync.dart'; -class StatusAppBar extends StatefulWidget implements PreferredSizeWidget { - const StatusAppBar({super.key, required this.title}); - +final class StatusAppBar extends ConsumerWidget implements PreferredSizeWidget { final String title; - @override - State createState() => _StatusAppBarState(); + const StatusAppBar({super.key, required this.title}); @override Size get preferredSize => const Size.fromHeight(kToolbarHeight); -} - -class _StatusAppBarState extends State { - late SyncStatus _connectionState; - StreamSubscription? _syncStatusSubscription; - - @override - void initState() { - super.initState(); - _connectionState = db.currentStatus; - _syncStatusSubscription = db.statusStream.listen((event) { - setState(() { - _connectionState = db.currentStatus; - }); - }); - } - - @override - void dispose() { - super.dispose(); - _syncStatusSubscription?.cancel(); - } @override - Widget build(BuildContext context) { - final statusIcon = _getStatusIcon(_connectionState); + Widget build(BuildContext context, WidgetRef ref) { + final syncState = ref.watch(syncStatus); + final statusIcon = _getStatusIcon(syncState); return AppBar( - title: Text(widget.title), + title: Text(title), actions: [ IconButton( onPressed: () { diff --git a/demos/supabase-todolist-drift/lib/widgets/todo_item_dialog.dart b/demos/supabase-todolist-drift/lib/widgets/todo_item_dialog.dart index 269fcf65..07b1250b 100644 --- a/demos/supabase-todolist-drift/lib/widgets/todo_item_dialog.dart +++ b/demos/supabase-todolist-drift/lib/widgets/todo_item_dialog.dart @@ -1,19 +1,20 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:supabase_todolist_drift/database.dart'; import 'package:supabase_todolist_drift/powersync.dart'; -class TodoItemDialog extends StatefulWidget { +class TodoItemDialog extends ConsumerStatefulWidget { final ListItem list; const TodoItemDialog({super.key, required this.list}); @override - State createState() { + ConsumerState createState() { return _TodoItemDialogState(); } } -class _TodoItemDialogState extends State { +class _TodoItemDialogState extends ConsumerState { final TextEditingController _textFieldController = TextEditingController(); _TodoItemDialogState(); @@ -31,8 +32,10 @@ class _TodoItemDialogState extends State { Future add() async { Navigator.of(context).pop(); + final db = ref.read(driftDatabase); - await appDb.addTodo(widget.list, _textFieldController.text); + await db.addTodo( + widget.list, _textFieldController.text, ref.read(userIdProvider)); } @override diff --git a/demos/supabase-todolist-drift/lib/widgets/todo_item_widget.dart b/demos/supabase-todolist-drift/lib/widgets/todo_item_widget.dart index 374e9e6f..8592152a 100644 --- a/demos/supabase-todolist-drift/lib/widgets/todo_item_widget.dart +++ b/demos/supabase-todolist-drift/lib/widgets/todo_item_widget.dart @@ -1,11 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:supabase_todolist_drift/app_config.dart'; import 'package:supabase_todolist_drift/attachments/photo_widget.dart'; import 'package:supabase_todolist_drift/attachments/queue.dart'; import 'package:supabase_todolist_drift/database.dart'; import 'package:supabase_todolist_drift/powersync.dart'; -class TodoItemWidget extends StatelessWidget { +class TodoItemWidget extends ConsumerWidget { TodoItemWidget({ required this.todo, }) : super(key: ObjectKey(todo.id)); @@ -21,21 +22,23 @@ class TodoItemWidget extends StatelessWidget { ); } - Future deleteTodo(TodoItem todo) async { + Future deleteTodo(AppDatabase db, TodoItem todo) async { if (todo.photoId != null) { attachmentQueue.deleteFile(todo.photoId!); } - await appDb.deleteTodo(todo); + await db.deleteTodo(todo); } @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { + final appDb = ref.watch(driftDatabase); + return ListTile( - onTap: () => appDb.toggleTodo(todo), + onTap: () => appDb.toggleTodo(todo, ref.read(userIdProvider)), leading: Checkbox( value: todo.completed, onChanged: (_) { - appDb.toggleTodo(todo); + appDb.toggleTodo(todo, ref.read(userIdProvider)); }, ), title: Row( @@ -50,7 +53,7 @@ class TodoItemWidget extends StatelessWidget { color: Colors.red, ), alignment: Alignment.centerRight, - onPressed: () async => await deleteTodo(todo), + onPressed: () async => await deleteTodo(appDb, todo), tooltip: 'Delete Item', ), AppConfig.supabaseStorageBucket.isEmpty diff --git a/demos/supabase-todolist-drift/lib/widgets/todo_list_page.dart b/demos/supabase-todolist-drift/lib/widgets/todo_list_page.dart index f9687bd7..2d70cb91 100644 --- a/demos/supabase-todolist-drift/lib/widgets/todo_list_page.dart +++ b/demos/supabase-todolist-drift/lib/widgets/todo_list_page.dart @@ -1,6 +1,8 @@ import 'dart:async'; +import 'package:drift_riverpod/drift_riverpod.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:supabase_todolist_drift/database.dart'; import 'package:supabase_todolist_drift/powersync.dart'; @@ -8,6 +10,12 @@ import 'status_app_bar.dart'; import 'todo_item_dialog.dart'; import 'todo_item_widget.dart'; +part 'todo_list_page.g.dart'; + +@queryProvider +final _todosIn = driftDatabase + .watchTodos((list) => 'SELECT * FROM todos WHERE list_id = $list;'); + void _showAddDialog(BuildContext context, ListItem list) async { return showDialog( context: context, @@ -34,56 +42,30 @@ class TodoListPage extends StatelessWidget { ); return Scaffold( - appBar: StatusAppBar(title: list.name), - floatingActionButton: button, - body: TodoListWidget(list: list)); + appBar: StatusAppBar(title: list.name), + floatingActionButton: button, + body: TodoListWidget(list: list), + ); } } -class TodoListWidget extends StatefulWidget { +final class TodoListWidget extends ConsumerWidget { final ListItem list; const TodoListWidget({super.key, required this.list}); @override - State createState() { - return TodoListWidgetState(); - } -} - -class TodoListWidgetState extends State { - List _data = []; - StreamSubscription? _subscription; + Widget build(BuildContext context, WidgetRef ref) { + final items = ref.watch(_todosIn((list.id,))); - TodoListWidgetState(); - - @override - void initState() { - super.initState(); - final stream = appDb.watchTodoItems(widget.list); - _subscription = stream.listen((data) { - if (!context.mounted) { - return; - } - setState(() { - _data = data; - }); - }); - } - - @override - void dispose() { - super.dispose(); - _subscription?.cancel(); - } - - @override - Widget build(BuildContext context) { - return ListView( - padding: const EdgeInsets.symmetric(vertical: 8.0), - children: _data.map((todo) { - return TodoItemWidget(todo: todo); - }).toList(), + return items.maybeWhen( + data: (items) => ListView( + padding: const EdgeInsets.symmetric(vertical: 8.0), + children: items.map((todo) { + return TodoItemWidget(todo: todo); + }).toList(), + ), + orElse: () => const CircularProgressIndicator(), ); } } diff --git a/demos/supabase-todolist-drift/lib/widgets/todo_list_page.g.dart b/demos/supabase-todolist-drift/lib/widgets/todo_list_page.g.dart new file mode 100644 index 00000000..0e125a6a --- /dev/null +++ b/demos/supabase-todolist-drift/lib/widgets/todo_list_page.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'todo_list_page.dart'; + +// ************************************************************************** +// DriftRiverpodGenerator +// ************************************************************************** + +extension on AppDatabase { + Selectable _todosIn(String var1) { + return customSelect('SELECT * FROM todos WHERE list_id = ?1', variables: [ + Variable(var1) + ], readsFrom: { + todoItems, + }).asyncMap(todoItems.mapFromRow); + } +} + +extension on DatabaseProvider { + SelectableProviderFamily, (String list,)> watchTodos( + Object _) { + return queryProviderFamilyImpl( + (ref, args) => ref.watch(driftDatabase)._todosIn( + args.$1, + )); + } +} diff --git a/demos/supabase-todolist-drift/macos/Podfile.lock b/demos/supabase-todolist-drift/macos/Podfile.lock new file mode 100644 index 00000000..2367f5f4 --- /dev/null +++ b/demos/supabase-todolist-drift/macos/Podfile.lock @@ -0,0 +1,80 @@ +PODS: + - app_links (1.0.0): + - FlutterMacOS + - FlutterMacOS (1.0.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - powersync-sqlite-core (0.3.9) + - powersync_flutter_libs (0.0.1): + - FlutterMacOS + - powersync-sqlite-core (~> 0.3.8) + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - sqlite3 (3.49.0): + - sqlite3/common (= 3.49.0) + - sqlite3/common (3.49.0) + - sqlite3/dbstatvtab (3.49.0): + - sqlite3/common + - sqlite3/fts5 (3.49.0): + - sqlite3/common + - sqlite3/perf-threadsafe (3.49.0): + - sqlite3/common + - sqlite3/rtree (3.49.0): + - sqlite3/common + - sqlite3_flutter_libs (0.0.1): + - Flutter + - FlutterMacOS + - sqlite3 (~> 3.49.0) + - sqlite3/dbstatvtab + - sqlite3/fts5 + - sqlite3/perf-threadsafe + - sqlite3/rtree + - url_launcher_macos (0.0.1): + - FlutterMacOS + +DEPENDENCIES: + - app_links (from `Flutter/ephemeral/.symlinks/plugins/app_links/macos`) + - FlutterMacOS (from `Flutter/ephemeral`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - powersync_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/powersync_flutter_libs/macos`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + - sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin`) + - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + +SPEC REPOS: + trunk: + - powersync-sqlite-core + - sqlite3 + +EXTERNAL SOURCES: + app_links: + :path: Flutter/ephemeral/.symlinks/plugins/app_links/macos + FlutterMacOS: + :path: Flutter/ephemeral + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + powersync_flutter_libs: + :path: Flutter/ephemeral/.symlinks/plugins/powersync_flutter_libs/macos + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + sqlite3_flutter_libs: + :path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin + url_launcher_macos: + :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + +SPEC CHECKSUMS: + app_links: 9028728e32c83a0831d9db8cf91c526d16cc5468 + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 + powersync-sqlite-core: 7515d321eb8e3c08b5259cdadb9d19b1876fe13a + powersync_flutter_libs: 330d8309223a121ec15a7334d9edc105053e5f82 + shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 + sqlite3: 4922312598b67e1825c6a6c821296dcbf6783046 + sqlite3_flutter_libs: 3c323550ef3b928bc0aa9513c841e45a7d242832 + url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673 + +PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 + +COCOAPODS: 1.16.2 diff --git a/demos/supabase-todolist-drift/macos/Runner.xcodeproj/project.pbxproj b/demos/supabase-todolist-drift/macos/Runner.xcodeproj/project.pbxproj index c2cf4ce2..b05094c1 100644 --- a/demos/supabase-todolist-drift/macos/Runner.xcodeproj/project.pbxproj +++ b/demos/supabase-todolist-drift/macos/Runner.xcodeproj/project.pbxproj @@ -27,6 +27,8 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 97E03A02958A40BBB235A3B7 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98085818E9010CC9F6063310 /* Pods_RunnerTests.framework */; }; + EE36C25E7B403574F34F5BCA /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9280692C7A8FA996D29C1A /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -60,11 +62,12 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0C9280692C7A8FA996D29C1A /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* supabase_todolist_drift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "supabase_todolist_drift.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* supabase_todolist_drift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = supabase_todolist_drift.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -76,8 +79,15 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 45FD24A08F75F2683B97BB90 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 48935ECCC795329512FEEA42 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 7060E736BA1ED7031A9A0481 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 742DE5BA5839E723067F2811 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 8A349FECF32D8F1DB75DAD33 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + 98085818E9010CC9F6063310 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + A6A6E7B16F53ECD8850D54CE /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -85,6 +95,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 97E03A02958A40BBB235A3B7 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -92,6 +103,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + EE36C25E7B403574F34F5BCA /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -125,6 +137,7 @@ 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, + 3D665F9DC6AE3F417BC75905 /* Pods */, ); sourceTree = ""; }; @@ -172,9 +185,25 @@ path = Runner; sourceTree = ""; }; + 3D665F9DC6AE3F417BC75905 /* Pods */ = { + isa = PBXGroup; + children = ( + 7060E736BA1ED7031A9A0481 /* Pods-Runner.debug.xcconfig */, + 742DE5BA5839E723067F2811 /* Pods-Runner.release.xcconfig */, + 48935ECCC795329512FEEA42 /* Pods-Runner.profile.xcconfig */, + 8A349FECF32D8F1DB75DAD33 /* Pods-RunnerTests.debug.xcconfig */, + A6A6E7B16F53ECD8850D54CE /* Pods-RunnerTests.release.xcconfig */, + 45FD24A08F75F2683B97BB90 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( + 0C9280692C7A8FA996D29C1A /* Pods_Runner.framework */, + 98085818E9010CC9F6063310 /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -186,6 +215,7 @@ isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + 6AE5802D36B24DA663873231 /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, @@ -204,11 +234,13 @@ isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + D3F61ADBC528506C06A2DA0B /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, + C0126805F168DFB4DEB2DFF3 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -329,6 +361,67 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; + 6AE5802D36B24DA663873231 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + C0126805F168DFB4DEB2DFF3 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + D3F61ADBC528506C06A2DA0B /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -380,6 +473,7 @@ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 8A349FECF32D8F1DB75DAD33 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -394,6 +488,7 @@ }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = A6A6E7B16F53ECD8850D54CE /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -408,6 +503,7 @@ }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 45FD24A08F75F2683B97BB90 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; diff --git a/demos/supabase-todolist-drift/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/demos/supabase-todolist-drift/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 906d1c2b..0b9a896d 100644 --- a/demos/supabase-todolist-drift/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/demos/supabase-todolist-drift/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -59,6 +59,7 @@ ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" + enableGPUValidationMode = "1" allowLocationSimulation = "YES"> diff --git a/demos/supabase-todolist-drift/macos/Runner.xcworkspace/contents.xcworkspacedata b/demos/supabase-todolist-drift/macos/Runner.xcworkspace/contents.xcworkspacedata index 1d526a16..21a3cc14 100644 --- a/demos/supabase-todolist-drift/macos/Runner.xcworkspace/contents.xcworkspacedata +++ b/demos/supabase-todolist-drift/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/demos/supabase-todolist-drift/macos/Runner/AppDelegate.swift b/demos/supabase-todolist-drift/macos/Runner/AppDelegate.swift index d53ef643..b3c17614 100644 --- a/demos/supabase-todolist-drift/macos/Runner/AppDelegate.swift +++ b/demos/supabase-todolist-drift/macos/Runner/AppDelegate.swift @@ -1,9 +1,13 @@ import Cocoa import FlutterMacOS -@NSApplicationMain +@main class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } } diff --git a/demos/supabase-todolist-drift/macos/Runner/DebugProfile.entitlements b/demos/supabase-todolist-drift/macos/Runner/DebugProfile.entitlements index dddb8a30..08c3ab17 100644 --- a/demos/supabase-todolist-drift/macos/Runner/DebugProfile.entitlements +++ b/demos/supabase-todolist-drift/macos/Runner/DebugProfile.entitlements @@ -8,5 +8,7 @@ com.apple.security.network.server + com.apple.security.network.client + diff --git a/demos/supabase-todolist-drift/macos/Runner/Release.entitlements b/demos/supabase-todolist-drift/macos/Runner/Release.entitlements index 852fa1a4..ee95ab7e 100644 --- a/demos/supabase-todolist-drift/macos/Runner/Release.entitlements +++ b/demos/supabase-todolist-drift/macos/Runner/Release.entitlements @@ -4,5 +4,7 @@ com.apple.security.app-sandbox + com.apple.security.network.client + diff --git a/demos/supabase-todolist-drift/pubspec.lock b/demos/supabase-todolist-drift/pubspec.lock index 6b1c7f66..b8103ffe 100644 --- a/demos/supabase-todolist-drift/pubspec.lock +++ b/demos/supabase-todolist-drift/pubspec.lock @@ -5,34 +5,34 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + sha256: dc27559385e905ad30838356c5f5d574014ba39872d732111cd07ac0beff4c57 url: "https://pub.dev" source: hosted - version: "67.0.0" + version: "80.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + sha256: "192d1c5b944e7e53b24b5586db760db934b177d4147c42fbca8c8c5f1eb8d11e" url: "https://pub.dev" source: hosted - version: "6.4.1" + version: "7.3.0" analyzer_plugin: dependency: transitive description: name: analyzer_plugin - sha256: "9661b30b13a685efaee9f02e5d01ed9f2b423bd889d28a304d02d704aee69161" + sha256: "1d460d14e3c2ae36dc2b32cef847c4479198cf87704f63c3c3c8150ee50c3916" url: "https://pub.dev" source: hosted - version: "0.11.3" + version: "0.12.0" app_links: dependency: transitive description: name: app_links - sha256: ae5f9a1b7d40d26178f605414be81ed4260350b4fae8259fe5ca4f89fe70c4af + sha256: "433df2e61b10519407475d7f69e470789d23d593f28224c38ba1068597be7950" url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "6.3.3" app_links_linux: dependency: transitive description: @@ -61,10 +61,10 @@ packages: dependency: transitive description: name: archive - sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + sha256: "6199c74e3db4fbfbd04f66d739e72fe11c8a8957d5f219f1f4482dbde6420b5a" url: "https://pub.dev" source: hosted - version: "3.6.1" + version: "4.0.2" args: dependency: transitive description: @@ -77,66 +77,66 @@ packages: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.12.0" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" build: dependency: transitive description: name: build - sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0 url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" build_config: dependency: transitive description: name: build_config - sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" build_daemon: dependency: transitive description: name: build_daemon - sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" + sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.0.4" build_resolvers: dependency: transitive description: name: build_resolvers - sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0 url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.4" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "644dc98a0f179b872f612d3eb627924b578897c629788e858157fa5e704ca0c7" + sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99" url: "https://pub.dev" source: hosted - version: "2.4.11" + version: "2.4.15" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: e3c79f69a64bdfcd8a776a3c28db4eb6e3fb5356d013ae5eb2e52007706d5dbe + sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021" url: "https://pub.dev" source: hosted - version: "7.3.1" + version: "8.0.0" built_collection: dependency: transitive description: @@ -149,10 +149,10 @@ packages: dependency: transitive description: name: built_value - sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb + sha256: "28a712df2576b63c6c005c465989a348604960c0958d28be5303ba9baa841ac2" url: "https://pub.dev" source: hosted - version: "8.9.2" + version: "8.9.3" camera: dependency: "direct main" description: @@ -165,50 +165,50 @@ packages: dependency: transitive description: name: camera_android - sha256: "134b83167cc3c83199e8d75e5bcfde677fec843e7b2ca6b754a5b0b96d00d921" + sha256: "007c57cdcace4751014071e3d42f2eb8a64a519254abed35b714223d81d66234" url: "https://pub.dev" source: hosted - version: "0.10.9+10" + version: "0.10.10" camera_avfoundation: dependency: transitive description: name: camera_avfoundation - sha256: b5093a82537b64bb88d4244f8e00b5ba69e822a5994f47b31d11400e1db975e5 + sha256: "49cc403dc2aec719cc70ba23419c932f1245d990e43f3c8336014b895751454a" url: "https://pub.dev" source: hosted - version: "0.9.17+1" + version: "0.9.18+4" camera_platform_interface: dependency: transitive description: name: camera_platform_interface - sha256: b3ede1f171532e0d83111fe0980b46d17f1aa9788a07a2fbed07366bbdbb9061 + sha256: "953e7baed3a7c8fae92f7200afeb2be503ff1a17c3b4e4ed7b76f008c2810a31" url: "https://pub.dev" source: hosted - version: "2.8.0" + version: "2.9.0" camera_web: dependency: transitive description: name: camera_web - sha256: b9235ec0a2ce949daec546f1f3d86f05c3921ed31c7d9ab6b7c03214d152fc2d + sha256: "595f28c89d1fb62d77c73c633193755b781c6d2e0ebcd8dc25b763b514e6ba8f" url: "https://pub.dev" source: hosted - version: "0.3.4" + version: "0.3.5" characters: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" charcode: dependency: transitive description: name: charcode - sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 + sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.4.0" checked_yaml: dependency: transitive description: @@ -221,42 +221,42 @@ packages: dependency: transitive description: name: cli_util - sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c url: "https://pub.dev" source: hosted - version: "0.4.1" + version: "0.4.2" clock: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" code_builder: dependency: transitive description: name: code_builder - sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" url: "https://pub.dev" source: hosted - version: "4.10.0" + version: "4.10.1" collection: dependency: transitive description: name: collection - sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.19.0" + version: "1.19.1" convert: dependency: transitive description: name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" cross_file: dependency: transitive description: @@ -269,50 +269,72 @@ packages: dependency: transitive description: name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.6" + custom_lint_core: + dependency: transitive + description: + name: custom_lint_core + sha256: "6dcee8a017181941c51a110da7e267c1d104dc74bec8862eeb8c85b5c8759a9e" + url: "https://pub.dev" + source: hosted + version: "0.7.1" + custom_lint_visitor: + dependency: transitive + description: + name: custom_lint_visitor + sha256: "36282d85714af494ee2d7da8c8913630aa6694da99f104fb2ed4afcf8fc857d8" + url: "https://pub.dev" + source: hosted + version: "1.0.0+7.3.0" dart_style: dependency: transitive description: name: dart_style - sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + sha256: "27eb0ae77836989a3bc541ce55595e8ceee0992807f14511552a898ddd0d88ac" url: "https://pub.dev" source: hosted - version: "2.3.6" + version: "3.0.1" drift: dependency: "direct main" description: name: drift - sha256: d6ff1ec6a0f3fa097dda6b776cf601f1f3d88b53b287288e09c1306f394fb1b3 + sha256: ab4d0e7aa1793829b1dd8e72d71bbf0b53bf4ff84b184045d1ab71b0832e632e url: "https://pub.dev" source: hosted - version: "2.20.3" + version: "2.25.0" drift_dev: dependency: "direct dev" description: - name: drift_dev - sha256: "3ee987578ca2281b5ff91eadd757cd6dd36001458d6e33784f990d67ff38f756" - url: "https://pub.dev" - source: hosted - version: "2.20.3" + path: "/Users/simon/src/drift/drift_dev" + relative: false + source: path + version: "2.25.1" + drift_riverpod: + dependency: "direct main" + description: + path: "/Users/simon/src/drift/extras/drift_riverpod" + relative: false + source: path + version: "0.1.0" drift_sqlite_async: dependency: "direct main" description: name: drift_sqlite_async - sha256: b29c9a838d2ed3f285c5964bc57c157af2a826cfa6dd3bf1b46121b15bb1212d + sha256: "486235b75ac10793ced906bc8d7107995ca02933f8d6bd4ddeb5d6ec20d1932c" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.2.1" fake_async: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" fetch_api: dependency: transitive description: @@ -333,31 +355,39 @@ packages: dependency: transitive description: name: ffi - sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" file: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" fixnum: dependency: transitive description: name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_hooks: + dependency: "direct main" + description: + name: flutter_hooks + sha256: cde36b12f7188c85286fba9b38cc5a902e7279f36dd676967106c041dc9dde70 + url: "https://pub.dev" + source: hosted + version: "0.20.5" flutter_lints: dependency: "direct dev" description: @@ -370,10 +400,18 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "9d98bd47ef9d34e803d438f17fd32b116d31009f534a6fa5ce3a1167f189a6de" + sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e" url: "https://pub.dev" source: hosted - version: "2.0.21" + version: "2.0.24" + flutter_riverpod: + dependency: "direct main" + description: + name: flutter_riverpod + sha256: "9532ee6db4a943a1ed8383072a2e3eeda041db5657cdf6d2acecf3c21ecbe7e1" + url: "https://pub.dev" + source: hosted + version: "2.6.1" flutter_test: dependency: "direct dev" description: flutter @@ -384,6 +422,14 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 + url: "https://pub.dev" + source: hosted + version: "2.4.4" frontend_server_client: dependency: transitive description: @@ -396,26 +442,26 @@ packages: dependency: transitive description: name: functions_client - sha256: "229648c4c78e0cb13dfb5e7508a3d2e7058f126ba364b94f8199ba4cead96d4e" + sha256: "61597ed93be197b1be6387855e4b760e6aac2355fcfc4df6d20d2b4579982158" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.4.0" glob: dependency: transitive description: name: glob - sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" gotrue: dependency: transitive description: name: gotrue - sha256: a8784341bcc08f88ba7a4b04a40a37059c7e71c315f058d45c31d09e8a951194 + sha256: d6362dff9a54f8c1c372bb137c858b4024c16407324d34e6473e59623c9b9f50 url: "https://pub.dev" source: hosted - version: "2.8.3" + version: "2.11.1" graphs: dependency: transitive description: @@ -432,46 +478,54 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + hooks_riverpod: + dependency: "direct main" + description: + name: hooks_riverpod + sha256: "70bba33cfc5670c84b796e6929c54b8bc5be7d0fe15bb28c2560500b9ad06966" + url: "https://pub.dev" + source: hosted + version: "2.6.1" http: dependency: transitive description: name: http - sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.3.0" http_multi_server: dependency: transitive description: name: http_multi_server - sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.2" http_parser: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" image: dependency: "direct main" description: name: image - sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8" + sha256: "8346ad4b5173924b5ddddab782fc7d8a6300178c8b1dc427775405a01701c4a6" url: "https://pub.dev" source: hosted - version: "4.2.0" + version: "4.5.2" io: dependency: transitive description: name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" js: dependency: transitive description: @@ -500,18 +554,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec url: "https://pub.dev" source: hosted - version: "10.0.7" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 url: "https://pub.dev" source: hosted - version: "3.0.8" + version: "3.0.9" leak_tracker_testing: dependency: transitive description: @@ -532,18 +586,18 @@ packages: dependency: "direct main" description: name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" matcher: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -556,18 +610,18 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.16.0" mime: dependency: transitive description: name: mime - sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "2.0.0" mutex: dependency: transitive description: @@ -580,42 +634,42 @@ packages: dependency: transitive description: name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" path: dependency: "direct main" description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" path_provider: dependency: "direct main" description: name: path_provider - sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.5" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "490539678396d4c3c0b06efdaab75ae60675c3e0c66f72bc04c2e2c1e0e2abeb" + sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2" url: "https://pub.dev" source: hosted - version: "2.2.9" + version: "2.2.15" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" path_provider_linux: dependency: transitive description: @@ -652,10 +706,10 @@ packages: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -672,14 +726,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + posix: + dependency: transitive + description: + name: posix + sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a + url: "https://pub.dev" + source: hosted + version: "6.0.1" postgrest: dependency: transitive description: name: postgrest - sha256: "675540a5e93e89fc28cc4ef0999ed2916c00a1c73de73f3a0d5067ce36dd41a2" + sha256: b74dc0f57b5dca5ce9f57a54b08110bf41d6fc8a0483c0fec10c79e9aa0fb2bb url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.4.1" powersync: dependency: "direct main" description: @@ -712,26 +774,26 @@ packages: dependency: transitive description: name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" pubspec_parse: dependency: transitive description: name: pubspec_parse - sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.5.0" realtime_client: dependency: transitive description: name: realtime_client - sha256: a99b7817e203c57ada746e9fe113820410cf84d9029f4310c57737aae890b0f7 + sha256: "1bfcb7455fdcf15953bf18ac2817634ea5b8f7f350c7e8c9873141a3ee2c3e9c" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.4.1" recase: dependency: transitive description: @@ -748,54 +810,86 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + riverpod: + dependency: transitive + description: + name: riverpod + sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959" + url: "https://pub.dev" + source: hosted + version: "2.6.1" + riverpod_analyzer_utils: + dependency: transitive + description: + name: riverpod_analyzer_utils + sha256: "837a6dc33f490706c7f4632c516bcd10804ee4d9ccc8046124ca56388715fdf3" + url: "https://pub.dev" + source: hosted + version: "0.5.9" + riverpod_annotation: + dependency: "direct main" + description: + name: riverpod_annotation + sha256: e14b0bf45b71326654e2705d462f21b958f987087be850afd60578fcd502d1b8 + url: "https://pub.dev" + source: hosted + version: "2.6.1" + riverpod_generator: + dependency: "direct dev" + description: + name: riverpod_generator + sha256: "120d3310f687f43e7011bb213b90a436f1bbc300f0e4b251a72c39bccb017a4f" + url: "https://pub.dev" + source: hosted + version: "2.6.4" rxdart: dependency: transitive description: name: rxdart - sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" url: "https://pub.dev" source: hosted - version: "0.27.7" + version: "0.28.0" shared_preferences: dependency: transitive description: name: shared_preferences - sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 + sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.5.2" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "3d4571b3c5eb58ce52a419d86e655493d0bc3020672da79f72fa0c16ca3a8ec1" + sha256: ea86be7b7114f9e94fddfbb52649e59a03d6627ccd2387ebddcd6624719e9f16 url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.4.5" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7" + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.5.4" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "034650b71e73629ca08a0bd789fd1d83cc63c2d1e405946f7cef7bc37432f93a" + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" shared_preferences_web: dependency: transitive description: @@ -808,26 +902,26 @@ packages: dependency: transitive description: name: shared_preferences_windows - sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" shelf: dependency: transitive description: name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.2" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "3.0.0" sky_engine: dependency: transitive description: flutter @@ -837,18 +931,18 @@ packages: dependency: transitive description: name: source_gen - sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b" url: "https://pub.dev" source: hosted - version: "1.5.0" + version: "2.0.0" source_span: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.10.1" sprintf: dependency: transitive description: @@ -861,18 +955,18 @@ packages: dependency: transitive description: name: sqlite3 - sha256: "35d3726fe18ab1463403a5cc8d97dbc81f2a0b08082e8173851363fcc97b6627" + sha256: decd58236d7c59e01ae81b34ebd158e6a1b61e0ae5397fc428736eb91ab82808 url: "https://pub.dev" source: hosted - version: "2.7.2" + version: "2.7.3" sqlite3_flutter_libs: dependency: transitive description: name: sqlite3_flutter_libs - sha256: "62bbb4073edbcdf53f40c80775f33eea01d301b7b81417e5b3fb7395416258c1" + sha256: "57fafacd815c981735406215966ff7caaa8eab984b094f52e692accefcbd9233" url: "https://pub.dev" source: hosted - version: "0.5.24" + version: "0.5.30" sqlite3_web: dependency: transitive description: @@ -893,98 +987,106 @@ packages: dependency: transitive description: name: sqlparser - sha256: "852cf80f9e974ac8e1b613758a8aa640215f7701352b66a7f468e95711eb570b" + sha256: "27dd0a9f0c02e22ac0eb42a23df9ea079ce69b52bb4a3b478d64e0ef34a263ee" url: "https://pub.dev" source: hosted - version: "0.38.1" + version: "0.41.0" stack_trace: dependency: transitive description: name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.12.1" + state_notifier: + dependency: transitive + description: + name: state_notifier + sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb + url: "https://pub.dev" + source: hosted + version: "1.0.0" storage_client: dependency: transitive description: name: storage_client - sha256: e37f1b9d40f43078d12bd2d1b6b08c2c16fbdbafc58b57bc44922da6ea3f5625 + sha256: d80d34f0aa60e5199646bc301f5750767ee37310c2ecfe8d4bbdd29351e09ab0 url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.3.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" stream_transform: dependency: transitive description: name: stream_transform - sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.1" supabase: dependency: transitive description: name: supabase - sha256: f6d21d0b555aa997d8170afd112407df0aaf44820cbe93b3520e2f7ea3ec0904 + sha256: "270f63cd87a16578fee87e40cbf61062e8cdbce68d5e723e665f4651d70ddd8c" url: "https://pub.dev" source: hosted - version: "2.2.7" + version: "2.6.2" supabase_flutter: dependency: "direct main" description: name: supabase_flutter - sha256: bcac7745e423ffe4aea86fefc3ccef259f979005c7a40558089c11f8606fd085 + sha256: ca8dfe3d4b109e7338cdf7778f3ec2c660a0178006876bfac343eb39b0f3d1e3 url: "https://pub.dev" source: hosted - version: "2.5.11" + version: "2.8.3" term_glyph: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.4" timing: dependency: transitive description: name: timing - sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.0.2" typed_data: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" universal_io: dependency: "direct main" description: @@ -997,42 +1099,42 @@ packages: dependency: transitive description: name: url_launcher - sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3" + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.3.1" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "678979703e10d7862c551c736fe6b9f185261bddf141b46672063b99790bc700" + sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193" url: "https://pub.dev" source: hosted - version: "6.3.7" + version: "6.3.14" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e + sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626" url: "https://pub.dev" source: hosted - version: "6.3.1" + version: "6.3.2" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.2.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.2" url_launcher_platform_interface: dependency: transitive description: @@ -1045,26 +1147,26 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" + sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.4.0" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185" + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.4" uuid: dependency: transitive description: name: uuid - sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90" + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff url: "https://pub.dev" source: hosted - version: "4.4.2" + version: "4.5.1" vector_math: dependency: transitive description: @@ -1077,18 +1179,18 @@ packages: dependency: transitive description: name: vm_service - sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "14.3.0" + version: "14.3.1" watcher: dependency: transitive description: name: watcher - sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" web: dependency: transitive description: @@ -1097,22 +1199,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "3.0.2" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.1.0" xml: dependency: transitive description: @@ -1125,18 +1235,18 @@ packages: dependency: transitive description: name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.3" yet_another_json_isolate: dependency: transitive description: name: yet_another_json_isolate - sha256: "381dd593e4199fe41a7b6467cef77a41d91fa8ef41465e135f12c99a76be463b" + sha256: "56155e9e0002cc51ea7112857bbcdc714d4c35e176d43e4d3ee233009ff410c9" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.3" sdks: - dart: ">=3.5.0 <4.0.0" - flutter: ">=3.22.0" + dart: ">=3.7.0-0 <4.0.0" + flutter: ">=3.27.0" diff --git a/demos/supabase-todolist-drift/pubspec.yaml b/demos/supabase-todolist-drift/pubspec.yaml index 317d60c1..061334be 100644 --- a/demos/supabase-todolist-drift/pubspec.yaml +++ b/demos/supabase-todolist-drift/pubspec.yaml @@ -21,6 +21,12 @@ dependencies: sqlite_async: ^0.11.0 drift: ^2.20.2 drift_sqlite_async: ^0.2.0 + flutter_riverpod: ^2.6.1 + riverpod_annotation: ^2.6.1 + drift_riverpod: + path: /Users/simon/src/drift/extras/drift_riverpod + flutter_hooks: ^0.20.5 + hooks_riverpod: ^2.6.1 dev_dependencies: flutter_test: @@ -29,6 +35,12 @@ dev_dependencies: flutter_lints: ^3.0.1 drift_dev: ^2.20.3 build_runner: ^2.4.8 + riverpod_generator: ^2.6.4 + +dependency_overrides: + drift_dev: + path: /Users/simon/src/drift/drift_dev + flutter: uses-material-design: true