Skip to content

Commit 830d133

Browse files
committed
Refactor login
1 parent 48ca600 commit 830d133

28 files changed

+650
-509
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
include: package:flutter_lints/flutter.yaml
22
analyzer:
33
exclude: [lib/**.g.dart]
4+
5+
linter:
6+
rules:
7+
- prefer_relative_imports

demos/supabase-todolist-drift/lib/attachments/photo_widget.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
77
import 'package:supabase_todolist_drift/attachments/camera_helpers.dart';
88
import 'package:supabase_todolist_drift/attachments/photo_capture_widget.dart';
99
import 'package:supabase_todolist_drift/attachments/queue.dart';
10-
import 'package:supabase_todolist_drift/database.dart';
10+
import 'package:supabase_todolist_drift/powersync/database.dart';
1111

1212
part 'photo_widget.g.dart';
1313

demos/supabase-todolist-drift/lib/widgets/status_app_bar.dart renamed to demos/supabase-todolist-drift/lib/components/app_bar.dart

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@ import 'package:flutter/foundation.dart';
22
import 'package:flutter/material.dart';
33
import 'package:flutter_riverpod/flutter_riverpod.dart';
44
import 'package:powersync/powersync.dart';
5-
import 'package:supabase_todolist_drift/widgets/fts_search_delegate.dart';
6-
import '../powersync.dart';
5+
6+
import '../powersync/powersync.dart';
7+
8+
final appBar = AppBar(
9+
title: const Text('PowerSync Flutter Demo'),
10+
);
711

812
final class StatusAppBar extends ConsumerWidget implements PreferredSizeWidget {
9-
final String title;
13+
final Widget title;
1014

1115
const StatusAppBar({super.key, required this.title});
1216

@@ -19,11 +23,11 @@ final class StatusAppBar extends ConsumerWidget implements PreferredSizeWidget {
1923
final statusIcon = _getStatusIcon(syncState);
2024

2125
return AppBar(
22-
title: Text(title),
26+
title: title,
2327
actions: <Widget>[
2428
IconButton(
2529
onPressed: () {
26-
showSearch(context: context, delegate: FtsSearchDelegate());
30+
// showSearch(context: context, delegate: FtsSearchDelegate());
2731
},
2832
icon: const Icon(Icons.search),
2933
),
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:hooks_riverpod/hooks_riverpod.dart';
3+
4+
import '../supabase.dart';
5+
import 'app_bar.dart';
6+
7+
final class PageLayout extends ConsumerWidget {
8+
final Widget content;
9+
final Widget? title;
10+
final Widget? floatingActionButton;
11+
12+
const PageLayout({
13+
super.key,
14+
required this.content,
15+
this.title,
16+
this.floatingActionButton,
17+
});
18+
19+
@override
20+
Widget build(BuildContext context, WidgetRef ref) {
21+
return Scaffold(
22+
appBar: StatusAppBar(title: title ?? const Text('PowerSync Demo')),
23+
body: Center(child: content),
24+
floatingActionButton: floatingActionButton,
25+
drawer: Drawer(
26+
// Add a ListView to the drawer. This ensures the user can scroll
27+
// through the options in the drawer if there isn't enough vertical
28+
// space to fit everything.
29+
child: ListView(
30+
// Important: Remove any padding from the ListView.
31+
padding: EdgeInsets.zero,
32+
children: [
33+
const DrawerHeader(
34+
decoration: BoxDecoration(
35+
color: Colors.blue,
36+
),
37+
child: Text(''),
38+
),
39+
ListTile(
40+
title: const Text('SQL Console'),
41+
onTap: () {},
42+
),
43+
ListTile(
44+
title: const Text('Sign Out'),
45+
onTap: () async {
46+
ref.read(authNotifierProvider.notifier).signOut();
47+
},
48+
),
49+
],
50+
),
51+
),
52+
);
53+
}
54+
}
Lines changed: 26 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
1+
import 'dart:async';
2+
13
import 'package:flutter/foundation.dart';
24
import 'package:flutter/material.dart';
3-
import 'package:flutter_riverpod/flutter_riverpod.dart';
5+
import 'package:flutter_hooks/flutter_hooks.dart';
6+
import 'package:hooks_riverpod/hooks_riverpod.dart';
47
import 'package:logging/logging.dart';
5-
import 'package:supabase_flutter/supabase_flutter.dart';
6-
import 'package:supabase_todolist_drift/models/schema.dart';
7-
import 'package:supabase_todolist_drift/supabase.dart';
88

9-
import 'powersync.dart';
10-
import 'widgets/lists_page.dart';
11-
import 'widgets/login_page.dart';
12-
import 'widgets/query_widget.dart';
13-
import 'widgets/signup_page.dart';
14-
import 'widgets/status_app_bar.dart';
9+
import 'navigation.dart';
10+
import 'supabase.dart';
1511

1612
void main() async {
1713
Logger.root.level = Level.INFO;
@@ -36,93 +32,34 @@ void main() async {
3632
runApp(const ProviderScope(child: MyApp()));
3733
}
3834

39-
const defaultQuery = 'SELECT * from $todosTable';
40-
41-
const listsPage = ListsPage();
42-
const homePage = listsPage;
43-
44-
const sqlConsolePage = Scaffold(
45-
appBar: StatusAppBar(title: 'SQL Console'),
46-
body: QueryWidget(defaultQuery: defaultQuery));
47-
48-
const loginPage = LoginPage();
49-
50-
const signupPage = SignupPage();
51-
52-
class MyApp extends ConsumerWidget {
35+
class MyApp extends HookConsumerWidget {
5336
const MyApp({super.key});
5437

5538
@override
5639
Widget build(BuildContext context, WidgetRef ref) {
57-
return MaterialApp(
40+
final router = ref.watch(appRouter);
41+
42+
// Bridge riverpod session provider to the listenable that auto_route wants
43+
// to re-evaluate route guards.
44+
final sessionNotifier = useValueNotifier(ref.read(isLoggedInProvider));
45+
ref.listen(isLoggedInProvider, (prev, now) {
46+
if (sessionNotifier.value != now) {
47+
// Using Timer.run() here to work around an issue with auto_route during
48+
// initialization.
49+
Timer.run(() {
50+
sessionNotifier.value = now;
51+
});
52+
}
53+
});
54+
55+
return MaterialApp.router(
56+
routerConfig: router.config(
57+
reevaluateListenable: sessionNotifier,
58+
),
5859
title: 'PowerSync Flutter Demo',
5960
theme: ThemeData(
6061
primarySwatch: Colors.blue,
6162
),
62-
home: ref.watch(isLoggedInProvider) ? homePage : loginPage,
63-
);
64-
}
65-
}
66-
67-
class MyHomePage extends ConsumerWidget {
68-
const MyHomePage(
69-
{super.key,
70-
required this.title,
71-
required this.content,
72-
this.floatingActionButton});
73-
74-
final String title;
75-
final Widget content;
76-
final Widget? floatingActionButton;
77-
78-
@override
79-
Widget build(BuildContext context, WidgetRef ref) {
80-
return Scaffold(
81-
appBar: StatusAppBar(title: title),
82-
body: Center(child: content),
83-
floatingActionButton: floatingActionButton,
84-
drawer: Drawer(
85-
// Add a ListView to the drawer. This ensures the user can scroll
86-
// through the options in the drawer if there isn't enough vertical
87-
// space to fit everything.
88-
child: ListView(
89-
// Important: Remove any padding from the ListView.
90-
padding: EdgeInsets.zero,
91-
children: [
92-
const DrawerHeader(
93-
decoration: BoxDecoration(
94-
color: Colors.blue,
95-
),
96-
child: Text(''),
97-
),
98-
ListTile(
99-
title: const Text('SQL Console'),
100-
onTap: () {
101-
var navigator = Navigator.of(context);
102-
navigator.pop();
103-
104-
navigator.push(MaterialPageRoute(
105-
builder: (context) => sqlConsolePage,
106-
));
107-
},
108-
),
109-
ListTile(
110-
title: const Text('Sign Out'),
111-
onTap: () async {
112-
var navigator = Navigator.of(context);
113-
navigator.pop();
114-
await Supabase.instance.client.auth.signOut();
115-
await (await ref.read(powerSyncInstanceProvider.future))
116-
.disconnectAndClear();
117-
118-
navigator.pushReplacement(MaterialPageRoute(
119-
builder: (context) => loginPage,
120-
));
121-
},
122-
),
123-
],
124-
),
125-
),
12663
);
12764
}
12865
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import 'package:auto_route/auto_route.dart';
2+
import 'package:flutter_riverpod/flutter_riverpod.dart';
3+
4+
import 'navigation.gr.dart';
5+
import 'supabase.dart';
6+
7+
export 'navigation.gr.dart';
8+
9+
@AutoRouterConfig()
10+
final class AppRouter extends RootStackRouter {
11+
final _AuthGuard _authGuard;
12+
13+
AppRouter(Ref ref) : _authGuard = _AuthGuard(ref);
14+
15+
@override
16+
RouteType get defaultRouteType => const RouteType.material();
17+
18+
@override
19+
List<AutoRoute> get routes => [
20+
AutoRoute(page: LoginRoute.page),
21+
AutoRoute(page: SignupRoute.page),
22+
AutoRoute(
23+
initial: true,
24+
page: ListsRoute.page,
25+
guards: [_authGuard],
26+
),
27+
];
28+
}
29+
30+
final class _AuthGuard extends AutoRouteGuard {
31+
final Ref _ref;
32+
33+
_AuthGuard(this._ref);
34+
35+
@override
36+
void onNavigation(NavigationResolver resolver, StackRouter router) {
37+
if (_ref.read(isLoggedInProvider)) {
38+
resolver.next(true);
39+
} else {
40+
resolver.redirectUntil(const LoginRoute());
41+
}
42+
}
43+
}
44+
45+
final appRouter = Provider((ref) => AppRouter(ref));

demos/supabase-todolist-drift/lib/navigation.gr.dart

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

0 commit comments

Comments
 (0)