2023-01-09 22:50:34 -05:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:go_router/go_router.dart';
|
2023-07-23 23:13:21 -04:00
|
|
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
2023-01-09 22:50:34 -05:00
|
|
|
|
2023-08-08 02:03:26 -04:00
|
|
|
import '../pages/chat_only_page.dart';
|
2023-07-29 10:55:35 -04:00
|
|
|
import '../pages/home.dart';
|
|
|
|
import '../pages/index.dart';
|
|
|
|
import '../pages/new_account.dart';
|
2023-08-17 18:10:24 -04:00
|
|
|
import '../pages/settings.dart';
|
2023-08-08 02:03:26 -04:00
|
|
|
import '../providers/chat.dart';
|
2023-07-23 23:13:21 -04:00
|
|
|
import '../providers/local_accounts.dart';
|
2023-08-08 02:03:26 -04:00
|
|
|
import '../tools/responsive.dart';
|
2023-09-26 18:46:02 -04:00
|
|
|
import '../veilid_init.dart';
|
2023-01-09 22:50:34 -05:00
|
|
|
|
2023-07-23 23:13:21 -04:00
|
|
|
part 'router_notifier.g.dart';
|
|
|
|
|
|
|
|
@riverpod
|
|
|
|
class RouterNotifier extends _$RouterNotifier implements Listenable {
|
2023-07-22 23:29:10 -04:00
|
|
|
/// GoRouter listener
|
2023-01-09 22:50:34 -05:00
|
|
|
VoidCallback? routerListener;
|
|
|
|
|
2023-07-23 23:13:21 -04:00
|
|
|
/// Do we need to make or import an account immediately?
|
|
|
|
bool hasAnyAccount = false;
|
2023-08-08 02:03:26 -04:00
|
|
|
bool hasActiveChat = false;
|
2023-07-22 23:29:10 -04:00
|
|
|
|
|
|
|
/// AsyncNotifier build
|
2023-01-09 22:50:34 -05:00
|
|
|
@override
|
|
|
|
Future<void> build() async {
|
2023-07-23 23:13:21 -04:00
|
|
|
hasAnyAccount = await ref.watch(
|
|
|
|
localAccountsProvider.selectAsync((data) => data.isNotEmpty),
|
2023-01-09 22:50:34 -05:00
|
|
|
);
|
2023-09-30 12:45:32 -04:00
|
|
|
hasActiveChat = ref.watch(activeChatStateProvider).value != null;
|
2023-01-09 22:50:34 -05:00
|
|
|
|
2023-07-22 23:29:10 -04:00
|
|
|
// When this notifier's state changes, inform GoRouter
|
2023-01-09 22:50:34 -05:00
|
|
|
ref.listenSelf((_, __) {
|
2023-07-26 17:42:11 -04:00
|
|
|
if (state.isLoading) {
|
|
|
|
return;
|
|
|
|
}
|
2023-01-09 22:50:34 -05:00
|
|
|
routerListener?.call();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-07-22 23:29:10 -04:00
|
|
|
/// Redirects when our state changes
|
2023-01-09 22:50:34 -05:00
|
|
|
String? redirect(BuildContext context, GoRouterState state) {
|
2023-07-26 17:42:11 -04:00
|
|
|
if (this.state.isLoading || this.state.hasError) {
|
|
|
|
return null;
|
|
|
|
}
|
2023-01-09 22:50:34 -05:00
|
|
|
|
2023-07-26 22:38:09 -04:00
|
|
|
// No matter where we are, if there's not
|
2023-09-21 21:00:58 -04:00
|
|
|
switch (state.matchedLocation) {
|
2023-08-17 18:10:24 -04:00
|
|
|
case '/':
|
2023-09-26 18:46:02 -04:00
|
|
|
|
|
|
|
// Wait for veilid to be initialized
|
|
|
|
if (!eventualVeilid.isCompleted) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2023-08-17 18:10:24 -04:00
|
|
|
return hasAnyAccount ? '/home' : '/new_account';
|
|
|
|
case '/new_account':
|
|
|
|
return hasAnyAccount ? '/home' : null;
|
|
|
|
case '/home':
|
2023-08-08 02:03:26 -04:00
|
|
|
if (!hasAnyAccount) {
|
2023-08-17 18:10:24 -04:00
|
|
|
return '/new_account';
|
2023-08-08 02:03:26 -04:00
|
|
|
}
|
|
|
|
if (responsiveVisibility(
|
|
|
|
context: context,
|
|
|
|
tablet: false,
|
|
|
|
tabletLandscape: false,
|
|
|
|
desktop: false)) {
|
|
|
|
if (hasActiveChat) {
|
2023-08-17 18:10:24 -04:00
|
|
|
return '/home/chat';
|
2023-08-08 02:03:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
2023-08-17 18:10:24 -04:00
|
|
|
case '/home/chat':
|
2023-08-08 02:03:26 -04:00
|
|
|
if (!hasAnyAccount) {
|
2023-08-17 18:10:24 -04:00
|
|
|
return '/new_account';
|
2023-08-08 02:03:26 -04:00
|
|
|
}
|
|
|
|
if (responsiveVisibility(
|
|
|
|
context: context,
|
|
|
|
tablet: false,
|
|
|
|
tabletLandscape: false,
|
|
|
|
desktop: false)) {
|
|
|
|
if (!hasActiveChat) {
|
2023-08-17 18:10:24 -04:00
|
|
|
return '/home';
|
2023-08-08 02:03:26 -04:00
|
|
|
}
|
|
|
|
} else {
|
2023-08-17 18:10:24 -04:00
|
|
|
return '/home';
|
2023-08-08 02:03:26 -04:00
|
|
|
}
|
|
|
|
return null;
|
2023-08-17 18:10:24 -04:00
|
|
|
case '/home/settings':
|
|
|
|
case '/new_account/settings':
|
|
|
|
return null;
|
2023-07-22 23:29:10 -04:00
|
|
|
default:
|
2023-08-17 18:10:24 -04:00
|
|
|
return hasAnyAccount ? null : '/new_account';
|
2023-07-04 20:33:47 -04:00
|
|
|
}
|
2023-01-09 22:50:34 -05:00
|
|
|
}
|
|
|
|
|
2023-01-10 21:04:18 -05:00
|
|
|
/// Our application routes
|
2023-01-09 22:50:34 -05:00
|
|
|
List<GoRoute> get routes => [
|
|
|
|
GoRoute(
|
2023-08-17 18:10:24 -04:00
|
|
|
path: '/',
|
2023-01-09 22:50:34 -05:00
|
|
|
builder: (context, state) => const IndexPage(),
|
|
|
|
),
|
|
|
|
GoRoute(
|
2023-08-17 18:10:24 -04:00
|
|
|
path: '/home',
|
2023-01-10 21:04:18 -05:00
|
|
|
builder: (context, state) => const HomePage(),
|
2023-08-17 18:10:24 -04:00
|
|
|
routes: [
|
|
|
|
GoRoute(
|
|
|
|
path: 'settings',
|
|
|
|
builder: (context, state) => const SettingsPage(),
|
|
|
|
),
|
|
|
|
GoRoute(
|
|
|
|
path: 'chat',
|
|
|
|
builder: (context, state) => const ChatOnlyPage(),
|
|
|
|
),
|
|
|
|
],
|
2023-01-09 22:50:34 -05:00
|
|
|
),
|
2023-01-10 21:04:18 -05:00
|
|
|
GoRoute(
|
2023-08-17 18:10:24 -04:00
|
|
|
path: '/new_account',
|
2023-01-10 21:04:18 -05:00
|
|
|
builder: (context, state) => const NewAccountPage(),
|
2023-08-17 18:10:24 -04:00
|
|
|
routes: [
|
|
|
|
GoRoute(
|
|
|
|
path: 'settings',
|
|
|
|
builder: (context, state) => const SettingsPage(),
|
|
|
|
),
|
|
|
|
],
|
2023-08-08 02:03:26 -04:00
|
|
|
),
|
2023-01-09 22:50:34 -05:00
|
|
|
];
|
|
|
|
|
2023-07-22 23:29:10 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
/// Listenable
|
|
|
|
|
2023-01-09 22:50:34 -05:00
|
|
|
/// Adds [GoRouter]'s listener as specified by its [Listenable].
|
|
|
|
/// [GoRouteInformationProvider] uses this method on creation to handle its
|
|
|
|
/// internal [ChangeNotifier].
|
|
|
|
/// Check out the internal implementation of [GoRouter] and
|
|
|
|
/// [GoRouteInformationProvider] to see this in action.
|
|
|
|
@override
|
|
|
|
void addListener(VoidCallback listener) {
|
|
|
|
routerListener = listener;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Removes [GoRouter]'s listener as specified by its [Listenable].
|
|
|
|
/// [GoRouteInformationProvider] uses this method when disposing,
|
|
|
|
/// so that it removes its callback when destroyed.
|
|
|
|
/// Check out the internal implementation of [GoRouter] and
|
|
|
|
/// [GoRouteInformationProvider] to see this in action.
|
|
|
|
@override
|
|
|
|
void removeListener(VoidCallback listener) {
|
|
|
|
routerListener = null;
|
|
|
|
}
|
|
|
|
}
|