Nikolas Rimikis
2 years ago
8 changed files with 171 additions and 39 deletions
@ -1,41 +1,63 @@ |
|||||||
// ignore: prefer_mixin |
// ignore: prefer_mixin |
||||||
import 'package:flutter/material.dart'; |
import 'package:flutter/material.dart'; |
||||||
|
import 'package:go_router/go_router.dart'; |
||||||
import 'package:neon/neon.dart'; |
import 'package:neon/neon.dart'; |
||||||
|
import 'package:provider/provider.dart'; |
||||||
|
|
||||||
class AppRouter extends RouterDelegate<Account> with ChangeNotifier, PopNavigatorRouterDelegateMixin<Account> { |
part 'router.g.dart'; |
||||||
|
|
||||||
|
class AppRouter extends GoRouter { |
||||||
AppRouter({ |
AppRouter({ |
||||||
required this.navigatorKey, |
required final GlobalKey<NavigatorState> navigatorKey, |
||||||
required this.accountsBloc, |
required final AccountsBloc accountsBloc, |
||||||
}); |
}) : super( |
||||||
|
refreshListenable: StreamListenable.behaviorSubject(accountsBloc.activeAccount), |
||||||
|
navigatorKey: navigatorKey, |
||||||
|
initialLocation: const HomeRoute().location, |
||||||
|
redirect: (final context, final state) { |
||||||
|
final account = accountsBloc.activeAccount.valueOrNull; |
||||||
|
|
||||||
final AccountsBloc accountsBloc; |
if (account == null) { |
||||||
|
return const LoginRoute().location; |
||||||
|
} |
||||||
|
|
||||||
@override |
if (state.location == const LoginRoute().location) { |
||||||
final GlobalKey<NavigatorState> navigatorKey; |
return const HomeRoute().location; |
||||||
|
} |
||||||
|
|
||||||
@override |
return null; |
||||||
Future setNewRoutePath(final Account? configuration) async {} |
}, |
||||||
|
routes: $appRoutes, |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
@TypedGoRoute<LoginRoute>( |
||||||
|
path: '/login', |
||||||
|
name: 'login', |
||||||
|
) |
||||||
|
@immutable |
||||||
|
class LoginRoute extends GoRouteData { |
||||||
|
const LoginRoute({this.server}); |
||||||
|
|
||||||
|
final String? server; |
||||||
|
|
||||||
@override |
@override |
||||||
Account? get currentConfiguration => accountsBloc.activeAccount.valueOrNull; |
Widget build(final BuildContext context, final GoRouterState state) => LoginPage(serverURL: server); |
||||||
|
} |
||||||
|
|
||||||
|
@TypedGoRoute<HomeRoute>( |
||||||
|
path: '/', |
||||||
|
name: 'home', |
||||||
|
) |
||||||
|
@immutable |
||||||
|
class HomeRoute extends GoRouteData { |
||||||
|
const HomeRoute(); |
||||||
|
|
||||||
@override |
@override |
||||||
Widget build(final BuildContext context) => Navigator( |
Widget build(final BuildContext context, final GoRouterState state) { |
||||||
key: navigatorKey, |
final accountsBloc = Provider.of<AccountsBloc>(context, listen: false); |
||||||
onPopPage: (final route, final result) => route.didPop(result), |
final account = accountsBloc.activeAccount.valueOrNull!; |
||||||
pages: [ |
|
||||||
if (currentConfiguration == null) ...[ |
return HomePage(key: Key(account.id)); |
||||||
const MaterialPage( |
} |
||||||
child: LoginPage(), |
|
||||||
), |
|
||||||
] else ...[ |
|
||||||
MaterialPage( |
|
||||||
name: 'home', |
|
||||||
child: HomePage( |
|
||||||
key: Key(currentConfiguration!.id), |
|
||||||
), |
|
||||||
), |
|
||||||
], |
|
||||||
], |
|
||||||
); |
|
||||||
} |
} |
||||||
|
@ -0,0 +1,57 @@ |
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND |
||||||
|
|
||||||
|
part of 'router.dart'; |
||||||
|
|
||||||
|
// ************************************************************************** |
||||||
|
// GoRouterGenerator |
||||||
|
// ************************************************************************** |
||||||
|
|
||||||
|
List<RouteBase> get $appRoutes => [ |
||||||
|
$loginRoute, |
||||||
|
$homeRoute, |
||||||
|
]; |
||||||
|
|
||||||
|
RouteBase get $loginRoute => GoRouteData.$route( |
||||||
|
path: '/login', |
||||||
|
name: 'login', |
||||||
|
factory: $LoginRouteExtension._fromState, |
||||||
|
); |
||||||
|
|
||||||
|
extension $LoginRouteExtension on LoginRoute { |
||||||
|
static LoginRoute _fromState(GoRouterState state) => LoginRoute( |
||||||
|
server: state.queryParameters['server'], |
||||||
|
); |
||||||
|
|
||||||
|
String get location => GoRouteData.$location( |
||||||
|
'/login', |
||||||
|
queryParams: { |
||||||
|
if (server != null) 'server': server, |
||||||
|
}, |
||||||
|
); |
||||||
|
|
||||||
|
void go(BuildContext context) => context.go(location); |
||||||
|
|
||||||
|
Future<T?> push<T>(BuildContext context) => context.push<T>(location); |
||||||
|
|
||||||
|
void pushReplacement(BuildContext context) => context.pushReplacement(location); |
||||||
|
} |
||||||
|
|
||||||
|
RouteBase get $homeRoute => GoRouteData.$route( |
||||||
|
path: '/', |
||||||
|
name: 'home', |
||||||
|
factory: $HomeRouteExtension._fromState, |
||||||
|
); |
||||||
|
|
||||||
|
extension $HomeRouteExtension on HomeRoute { |
||||||
|
static HomeRoute _fromState(GoRouterState state) => const HomeRoute(); |
||||||
|
|
||||||
|
String get location => GoRouteData.$location( |
||||||
|
'/', |
||||||
|
); |
||||||
|
|
||||||
|
void go(BuildContext context) => context.go(location); |
||||||
|
|
||||||
|
Future<T?> push<T>(BuildContext context) => context.push<T>(location); |
||||||
|
|
||||||
|
void pushReplacement(BuildContext context) => context.pushReplacement(location); |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
part of '../../neon.dart'; |
||||||
|
|
||||||
|
/// Listenable Stream |
||||||
|
/// |
||||||
|
/// A class that implements [Listenable] for a stream. |
||||||
|
/// Objects need to be manually disposed. |
||||||
|
class StreamListenable extends ChangeNotifier { |
||||||
|
/// Listenable Stream |
||||||
|
/// |
||||||
|
/// Implementation for all types of [Stream]s. |
||||||
|
/// For an implementation tailored towards [BehaviorSubject] have a look at [StreamListenable.behaviorSubject]. |
||||||
|
StreamListenable(final Stream<dynamic> stream) { |
||||||
|
notifyListeners(); |
||||||
|
|
||||||
|
_subscription = stream.asBroadcastStream().listen((final value) { |
||||||
|
notifyListeners(); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/// Listenable BehaviorSubject |
||||||
|
/// |
||||||
|
/// Implementation for a [BehaviorSubject]. It ensures to not unececcary notify listeners. |
||||||
|
/// For an implementation tailored towards otnher kinds of [Stream] have a look at [StreamListenable]. |
||||||
|
StreamListenable.behaviorSubject(final BehaviorSubject<dynamic> subject) { |
||||||
|
_subscription = subject.listen((final value) { |
||||||
|
notifyListeners(); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
late final StreamSubscription<dynamic> _subscription; |
||||||
|
|
||||||
|
@override |
||||||
|
void dispose() { |
||||||
|
unawaited(_subscription.cancel()); |
||||||
|
|
||||||
|
super.dispose(); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue