mirror of
https://github.com/lucavenir/go_router_riverpod.git
synced 2025-05-18 04:35:54 +08:00
Changed the main example with code gen tools
This commit is contained in:
@ -1,29 +1,8 @@
|
|||||||
# This file configures the analyzer, which statically analyzes Dart code to
|
|
||||||
# check for errors, warnings, and lints.
|
|
||||||
#
|
|
||||||
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
|
||||||
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
|
||||||
# invoked from the command line by running `flutter analyze`.
|
|
||||||
|
|
||||||
# The following line activates a set of recommended lints for Flutter apps,
|
|
||||||
# packages, and plugins designed to encourage good coding practices.
|
|
||||||
include: package:flutter_lints/flutter.yaml
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
|
analyzer:
|
||||||
|
errors:
|
||||||
|
invalid_annotation_target: ignore
|
||||||
|
|
||||||
linter:
|
linter:
|
||||||
# The lint rules applied to this project can be customized in the
|
|
||||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
|
||||||
# included above or to enable additional rules. A list of all available lints
|
|
||||||
# and their documentation is published at
|
|
||||||
# https://dart-lang.github.io/linter/lints/index.html.
|
|
||||||
#
|
|
||||||
# Instead of disabling a lint rule for the entire project in the
|
|
||||||
# section below, it can also be suppressed for a single line of code
|
|
||||||
# or a specific dart file by using the `// ignore: name_of_lint` and
|
|
||||||
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
|
||||||
# producing the lint.
|
|
||||||
rules:
|
rules:
|
||||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
|
||||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
|
||||||
|
|
||||||
# Additional information about this file can be found at
|
|
||||||
# https://dart.dev/guides/language/analysis-options
|
|
||||||
|
@ -1,108 +1,111 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
class User {
|
import 'user.dart';
|
||||||
const User({
|
|
||||||
required this.displayName,
|
|
||||||
required this.email,
|
|
||||||
required this.token,
|
|
||||||
});
|
|
||||||
|
|
||||||
final String displayName;
|
part 'auth.g.dart';
|
||||||
final String email;
|
|
||||||
final String token;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO in the next version: Use Freezed to generate states.
|
/// A mock of an Authenticated User
|
||||||
typedef AsyncUser = AsyncValue<User?>;
|
const _dummyUser = User.signedIn(
|
||||||
|
id: 0,
|
||||||
|
displayName: "My Name",
|
||||||
|
email: "My Email",
|
||||||
|
token: "some-updated-secret-auth-token",
|
||||||
|
);
|
||||||
|
|
||||||
final authProvider = AsyncNotifierProvider<AuthNotifier, User?>(() {
|
@riverpod
|
||||||
return AuthNotifier();
|
class AuthNotifier extends _$AuthNotifier {
|
||||||
});
|
late SharedPreferences sharedPreferences;
|
||||||
|
static const _sharedPrefsKey = 'token';
|
||||||
|
|
||||||
class AuthNotifier extends AsyncNotifier<User?> {
|
/// Mock of the duration of a network request
|
||||||
AuthNotifier();
|
final _networkRoundTripTime = Random().nextInt(750);
|
||||||
static const _key = 'token';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<User?> build() async {
|
FutureOr<User> build() async {
|
||||||
final sharedPreferences = await SharedPreferences.getInstance();
|
sharedPreferences = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
ref.listenSelf((_, next) {
|
_persistenceRefreshLogic();
|
||||||
final val = next.valueOrNull;
|
|
||||||
if (val == null) {
|
|
||||||
sharedPreferences.remove(_key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sharedPreferences.setString(_key, val.email);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
return await _loginRecoveryAttempt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to perform a login with the saved token on the persistant storage.
|
||||||
|
/// If _anything_ goes wrong, deletes the internal token and returns a [User.signedOut].
|
||||||
|
Future<User> _loginRecoveryAttempt() async {
|
||||||
try {
|
try {
|
||||||
// This operation might fail for... reasons
|
final savedToken = sharedPreferences.getString(_sharedPrefsKey);
|
||||||
final savedToken = sharedPreferences.getString(_key);
|
if (savedToken == null) {
|
||||||
if (savedToken == null) return null;
|
throw const UnauthorizedException(
|
||||||
|
"Couldn't find the authentication token");
|
||||||
|
}
|
||||||
|
|
||||||
// This request might also fail
|
|
||||||
return await _loginWithToken(savedToken);
|
return await _loginWithToken(savedToken);
|
||||||
} catch (error, stackTrace) {
|
} catch (_, __) {
|
||||||
// If anything goes wrong, give a non-authenticated outcome
|
await sharedPreferences.remove(_sharedPrefsKey);
|
||||||
await sharedPreferences.remove(_key);
|
return const User.signedOut();
|
||||||
print(error);
|
|
||||||
print(stackTrace);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<User?> _loginWithToken(String token) async {
|
/// Mock of a request performed on logout (might be common, or not, whatevs).
|
||||||
// here the token should be used to perform a login request
|
Future<void> logout() async {
|
||||||
|
await Future.delayed(Duration(milliseconds: _networkRoundTripTime));
|
||||||
|
state = const AsyncValue<User>.data(User.signedOut());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mock of a successful login attempt, which results come from the network.
|
||||||
|
Future<void> login(String email, String password) async {
|
||||||
|
state = await AsyncValue.guard<User>(() async {
|
||||||
|
return Future.delayed(
|
||||||
|
Duration(milliseconds: _networkRoundTripTime),
|
||||||
|
() => _dummyUser,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mock of a login request performed with a saved token.
|
||||||
|
/// If such request fails, this method will throw an [UnauthorizedException].
|
||||||
|
Future<User> _loginWithToken(String token) async {
|
||||||
final logInAttempt = await Future.delayed(
|
final logInAttempt = await Future.delayed(
|
||||||
const Duration(milliseconds: 750),
|
Duration(milliseconds: _networkRoundTripTime),
|
||||||
() => Random().nextBool(), // mock
|
() => true,
|
||||||
);
|
);
|
||||||
|
|
||||||
// If the attempts succeeds, return the result out
|
if (logInAttempt) return _dummyUser;
|
||||||
if (logInAttempt) {
|
|
||||||
return const User(
|
|
||||||
displayName: "My Name",
|
|
||||||
email: "My Email",
|
|
||||||
token: "some-updated-secret-auth-token",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the attempt fails, or returns 401, or whatever, this should fail.
|
|
||||||
throw const UnauthorizedException('401 Unauthorized or something');
|
throw const UnauthorizedException('401 Unauthorized or something');
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> logout() async {
|
/// Internal method used to listen authentication state changes.
|
||||||
final sharedPreferences = await SharedPreferences.getInstance();
|
/// When the auth object is in a loading state, nothing happens.
|
||||||
|
/// When the auth object is in a error state, we choose to remove the token
|
||||||
|
/// Otherwise, we expect the current auth value to be reflected in our persitence API
|
||||||
|
void _persistenceRefreshLogic() {
|
||||||
|
ref.listenSelf((_, next) {
|
||||||
|
if (next.isLoading) return;
|
||||||
|
if (next.hasError) {
|
||||||
|
sharedPreferences.remove(_sharedPrefsKey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove the token from persistence, first
|
final val = next.requireValue;
|
||||||
await sharedPreferences.remove(_key);
|
|
||||||
// No request is mocked here but I guess we could: logout
|
|
||||||
state = const AsyncUser.data(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> login(String email, String password) async {
|
val.map<void>(
|
||||||
// Simple mock of a successful login attempt
|
signedIn: (signedIn) {
|
||||||
state = await AsyncUser.guard(() async {
|
sharedPreferences.setString(_sharedPrefsKey, signedIn.token);
|
||||||
return Future.delayed(
|
},
|
||||||
Duration(milliseconds: Random().nextInt(750)),
|
signedOut: (signedOut) {
|
||||||
() => const User(
|
sharedPreferences.remove(_sharedPrefsKey);
|
||||||
displayName: "My Name",
|
},
|
||||||
email: "My Email",
|
|
||||||
token: 'someToken',
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get isAuthenticated => state.valueOrNull != null;
|
|
||||||
bool get isLoading => state.isLoading;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Simple mock of a 401 exception
|
||||||
class UnauthorizedException implements Exception {
|
class UnauthorizedException implements Exception {
|
||||||
final String message;
|
final String message;
|
||||||
const UnauthorizedException(this.message);
|
const UnauthorizedException(this.message);
|
||||||
|
47
complete_example/lib/auth.g.dart
Normal file
47
complete_example/lib/auth.g.dart
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'auth.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// ignore_for_file: avoid_private_typedef_functions, non_constant_identifier_names, subtype_of_sealed_class, invalid_use_of_internal_member, unused_element, constant_identifier_names, unnecessary_raw_strings, library_private_types_in_public_api
|
||||||
|
|
||||||
|
/// 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String $AuthNotifierHash() => r'587998753a879e6c3f8912f3913c0e2ea5eb1b14';
|
||||||
|
|
||||||
|
/// See also [AuthNotifier].
|
||||||
|
final authNotifierProvider =
|
||||||
|
AutoDisposeAsyncNotifierProvider<AuthNotifier, User>(
|
||||||
|
AuthNotifier.new,
|
||||||
|
name: r'authNotifierProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product') ? null : $AuthNotifierHash,
|
||||||
|
);
|
||||||
|
typedef AuthNotifierRef = AutoDisposeAsyncNotifierProviderRef<User>;
|
||||||
|
|
||||||
|
abstract class _$AuthNotifier extends AutoDisposeAsyncNotifier<User> {
|
||||||
|
@override
|
||||||
|
FutureOr<User> build();
|
||||||
|
}
|
@ -16,35 +16,20 @@ class MyAwesomeApp extends ConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final asyncRouter = ref.watch(routerProvider);
|
final router = ref.watch(routerProvider);
|
||||||
|
|
||||||
if (asyncRouter.hasValue) {
|
return MaterialApp.router(
|
||||||
final router = asyncRouter.requireValue;
|
routerConfig: router,
|
||||||
return MaterialApp.router(
|
title: 'flutter_riverpod + go_router Demo',
|
||||||
routeInformationParser: router.routeInformationParser,
|
theme: ThemeData(
|
||||||
routerDelegate: router.routerDelegate,
|
primarySwatch: Colors.blue,
|
||||||
routeInformationProvider: router.routeInformationProvider,
|
),
|
||||||
title: 'flutter_riverpod + go_router Demo',
|
|
||||||
theme: ThemeData(
|
|
||||||
primarySwatch: Colors.blue,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return asyncRouter.maybeWhen(
|
|
||||||
error: (error, stackTrace) {
|
|
||||||
print(error);
|
|
||||||
return const Text("Something went very, very wrong.");
|
|
||||||
},
|
|
||||||
orElse: () => const CircularProgressIndicator(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HomePage extends ConsumerWidget {
|
class HomePage extends ConsumerWidget {
|
||||||
const HomePage({super.key});
|
const HomePage({super.key});
|
||||||
static String get routeName => 'home';
|
|
||||||
static String get routeLocation => '/';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
@ -58,7 +43,7 @@ class HomePage extends ConsumerWidget {
|
|||||||
const Text("Home Page"),
|
const Text("Home Page"),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ref.read(authProvider.notifier).logout();
|
ref.read(authNotifierProvider.notifier).logout();
|
||||||
},
|
},
|
||||||
child: const Text("Logout"),
|
child: const Text("Logout"),
|
||||||
),
|
),
|
||||||
@ -71,8 +56,6 @@ class HomePage extends ConsumerWidget {
|
|||||||
|
|
||||||
class LoginPage extends ConsumerWidget {
|
class LoginPage extends ConsumerWidget {
|
||||||
const LoginPage({super.key});
|
const LoginPage({super.key});
|
||||||
static String get routeName => 'login';
|
|
||||||
static String get routeLocation => '/$routeName';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
@ -86,7 +69,7 @@ class LoginPage extends ConsumerWidget {
|
|||||||
const Text("Login Page"),
|
const Text("Login Page"),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
ref.read(authProvider.notifier).login(
|
ref.read(authNotifierProvider.notifier).login(
|
||||||
"myEmail",
|
"myEmail",
|
||||||
"myPassword",
|
"myPassword",
|
||||||
);
|
);
|
||||||
@ -102,8 +85,6 @@ class LoginPage extends ConsumerWidget {
|
|||||||
|
|
||||||
class SplashPage extends StatelessWidget {
|
class SplashPage extends StatelessWidget {
|
||||||
const SplashPage({super.key});
|
const SplashPage({super.key});
|
||||||
static String get routeName => 'splash';
|
|
||||||
static String get routeLocation => '/$routeName';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -9,11 +9,12 @@ class RiverpodLogger extends ProviderObserver {
|
|||||||
Object? newValue,
|
Object? newValue,
|
||||||
ProviderContainer container,
|
ProviderContainer container,
|
||||||
) {
|
) {
|
||||||
|
// TODO use a proper logger
|
||||||
print('''
|
print('''
|
||||||
{
|
{
|
||||||
provider: ${provider.name ?? provider.runtimeType},
|
provider: ${provider.name ?? provider.runtimeType},
|
||||||
oldValue: ${previousValue ?? 'None'},
|
oldValue: $previousValue,
|
||||||
newValue: ${newValue ?? 'None'}
|
newValue: $newValue
|
||||||
}
|
}
|
||||||
''');
|
''');
|
||||||
super.didUpdateProvider(provider, previousValue, newValue, container);
|
super.didUpdateProvider(provider, previousValue, newValue, container);
|
||||||
|
@ -1,57 +1,25 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
import 'auth.dart';
|
import 'router_notifier.dart';
|
||||||
import 'main.dart';
|
import 'routes.dart';
|
||||||
|
|
||||||
final _key = GlobalKey<NavigatorState>();
|
part 'router.g.dart';
|
||||||
|
|
||||||
final routerProvider = FutureProvider<GoRouter>((ref) async {
|
final _key = GlobalKey<NavigatorState>(debugLabel: 'routerKey');
|
||||||
final isAuth = await ref.watch(
|
|
||||||
authProvider.selectAsync((value) => value != null),
|
@riverpod
|
||||||
);
|
GoRouter router(RouterRef ref) {
|
||||||
|
ref.watch(routerNotifierProvider);
|
||||||
|
final notifier = ref.read(routerNotifierProvider.notifier);
|
||||||
|
|
||||||
return GoRouter(
|
return GoRouter(
|
||||||
navigatorKey: _key,
|
navigatorKey: _key,
|
||||||
|
refreshListenable: notifier,
|
||||||
debugLogDiagnostics: true,
|
debugLogDiagnostics: true,
|
||||||
initialLocation: SplashPage.routeLocation,
|
initialLocation: SplashRoute.path,
|
||||||
routes: [
|
routes: notifier.routes,
|
||||||
GoRoute(
|
redirect: notifier.redirect,
|
||||||
path: SplashPage.routeLocation,
|
|
||||||
name: SplashPage.routeName,
|
|
||||||
builder: (context, state) {
|
|
||||||
return const SplashPage();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: HomePage.routeLocation,
|
|
||||||
name: HomePage.routeName,
|
|
||||||
builder: (context, state) {
|
|
||||||
return const HomePage();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: LoginPage.routeLocation,
|
|
||||||
name: LoginPage.routeName,
|
|
||||||
builder: (context, state) {
|
|
||||||
return const LoginPage();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
redirect: (context, state) {
|
|
||||||
// If our async state is loading, don't perform redirects, yet
|
|
||||||
if (isAuth == null) return null;
|
|
||||||
|
|
||||||
final isSplash = state.location == SplashPage.routeLocation;
|
|
||||||
if (isSplash) {
|
|
||||||
return isAuth ? HomePage.routeLocation : LoginPage.routeLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
final isLoggingIn = state.location == LoginPage.routeLocation;
|
|
||||||
if (isLoggingIn) return isAuth ? HomePage.routeLocation : null;
|
|
||||||
|
|
||||||
return isAuth ? null : SplashPage.routeLocation;
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
41
complete_example/lib/router.g.dart
Normal file
41
complete_example/lib/router.g.dart
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'router.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// ignore_for_file: avoid_private_typedef_functions, non_constant_identifier_names, subtype_of_sealed_class, invalid_use_of_internal_member, unused_element, constant_identifier_names, unnecessary_raw_strings, library_private_types_in_public_api
|
||||||
|
|
||||||
|
/// 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String $routerHash() => r'f928f86033f77a05a3a9258abeb50e25d044c1a5';
|
||||||
|
|
||||||
|
/// See also [router].
|
||||||
|
final routerProvider = AutoDisposeProvider<GoRouter>(
|
||||||
|
router,
|
||||||
|
name: r'routerProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product') ? null : $routerHash,
|
||||||
|
);
|
||||||
|
typedef RouterRef = AutoDisposeProviderRef<GoRouter>;
|
68
complete_example/lib/router_notifier.dart
Normal file
68
complete_example/lib/router_notifier.dart
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
import 'auth.dart';
|
||||||
|
import 'routes.dart';
|
||||||
|
|
||||||
|
part 'router_notifier.g.dart';
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
class RouterNotifier extends _$RouterNotifier implements Listenable {
|
||||||
|
VoidCallback? routerListener;
|
||||||
|
bool? isAuth;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void build() {
|
||||||
|
ref.listen(
|
||||||
|
authNotifierProvider.select((value) => value),
|
||||||
|
(previous, next) {
|
||||||
|
if (next.isLoading) return;
|
||||||
|
|
||||||
|
isAuth = next.requireValue.map(
|
||||||
|
signedIn: (_) => true,
|
||||||
|
signedOut: (_) => false,
|
||||||
|
);
|
||||||
|
|
||||||
|
routerListener?.call();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String? redirect(BuildContext context, GoRouterState state) {
|
||||||
|
if (isAuth == null) return null;
|
||||||
|
final isSplash = state.location == SplashRoute.path;
|
||||||
|
|
||||||
|
if (isSplash) {
|
||||||
|
return isAuth! ? HomeRoute.path : LoginRoute.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
final isLoggingIn = state.location == LoginRoute.path;
|
||||||
|
if (isLoggingIn) return isAuth! ? HomeRoute.path : null;
|
||||||
|
|
||||||
|
return isAuth! ? null : SplashRoute.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Our application routes. Obtained through code generation
|
||||||
|
List<GoRoute> get routes => $appRoutes;
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
}
|
||||||
|
}
|
48
complete_example/lib/router_notifier.g.dart
Normal file
48
complete_example/lib/router_notifier.g.dart
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'router_notifier.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// ignore_for_file: avoid_private_typedef_functions, non_constant_identifier_names, subtype_of_sealed_class, invalid_use_of_internal_member, unused_element, constant_identifier_names, unnecessary_raw_strings, library_private_types_in_public_api
|
||||||
|
|
||||||
|
/// 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String $RouterNotifierHash() => r'97f2e52207151ab82f78803b85c3016d6c7a90e9';
|
||||||
|
|
||||||
|
/// See also [RouterNotifier].
|
||||||
|
final routerNotifierProvider =
|
||||||
|
AutoDisposeNotifierProvider<RouterNotifier, void>(
|
||||||
|
RouterNotifier.new,
|
||||||
|
name: r'routerNotifierProvider',
|
||||||
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: $RouterNotifierHash,
|
||||||
|
);
|
||||||
|
typedef RouterNotifierRef = AutoDisposeNotifierProviderRef<void>;
|
||||||
|
|
||||||
|
abstract class _$RouterNotifier extends AutoDisposeNotifier<void> {
|
||||||
|
@override
|
||||||
|
void build();
|
||||||
|
}
|
39
complete_example/lib/routes.dart
Normal file
39
complete_example/lib/routes.dart
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
|
import 'main.dart';
|
||||||
|
|
||||||
|
part 'routes.g.dart';
|
||||||
|
|
||||||
|
@TypedGoRoute<SplashRoute>(path: SplashRoute.path)
|
||||||
|
class SplashRoute extends GoRouteData {
|
||||||
|
const SplashRoute();
|
||||||
|
static const path = '/splash';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return const SplashPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypedGoRoute<HomeRoute>(path: HomeRoute.path)
|
||||||
|
class HomeRoute extends GoRouteData {
|
||||||
|
const HomeRoute();
|
||||||
|
static const path = '/home';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return const HomePage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypedGoRoute<LoginRoute>(path: LoginRoute.path)
|
||||||
|
class LoginRoute extends GoRouteData {
|
||||||
|
const LoginRoute();
|
||||||
|
static const path = '/login';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return const LoginPage();
|
||||||
|
}
|
||||||
|
}
|
64
complete_example/lib/routes.g.dart
Normal file
64
complete_example/lib/routes.g.dart
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'routes.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// GoRouterGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
List<GoRoute> get $appRoutes => [
|
||||||
|
$splashRoute,
|
||||||
|
$homeRoute,
|
||||||
|
$loginRoute,
|
||||||
|
];
|
||||||
|
|
||||||
|
GoRoute get $splashRoute => GoRouteData.$route(
|
||||||
|
path: '/splash',
|
||||||
|
factory: $SplashRouteExtension._fromState,
|
||||||
|
);
|
||||||
|
|
||||||
|
extension $SplashRouteExtension on SplashRoute {
|
||||||
|
static SplashRoute _fromState(GoRouterState state) => const SplashRoute();
|
||||||
|
|
||||||
|
String get location => GoRouteData.$location(
|
||||||
|
'/splash',
|
||||||
|
);
|
||||||
|
|
||||||
|
void go(BuildContext context) => context.go(location, extra: this);
|
||||||
|
|
||||||
|
void push(BuildContext context) => context.push(location, extra: this);
|
||||||
|
}
|
||||||
|
|
||||||
|
GoRoute get $homeRoute => GoRouteData.$route(
|
||||||
|
path: '/home',
|
||||||
|
factory: $HomeRouteExtension._fromState,
|
||||||
|
);
|
||||||
|
|
||||||
|
extension $HomeRouteExtension on HomeRoute {
|
||||||
|
static HomeRoute _fromState(GoRouterState state) => const HomeRoute();
|
||||||
|
|
||||||
|
String get location => GoRouteData.$location(
|
||||||
|
'/home',
|
||||||
|
);
|
||||||
|
|
||||||
|
void go(BuildContext context) => context.go(location, extra: this);
|
||||||
|
|
||||||
|
void push(BuildContext context) => context.push(location, extra: this);
|
||||||
|
}
|
||||||
|
|
||||||
|
GoRoute get $loginRoute => GoRouteData.$route(
|
||||||
|
path: '/login',
|
||||||
|
factory: $LoginRouteExtension._fromState,
|
||||||
|
);
|
||||||
|
|
||||||
|
extension $LoginRouteExtension on LoginRoute {
|
||||||
|
static LoginRoute _fromState(GoRouterState state) => const LoginRoute();
|
||||||
|
|
||||||
|
String get location => GoRouteData.$location(
|
||||||
|
'/login',
|
||||||
|
);
|
||||||
|
|
||||||
|
void go(BuildContext context) => context.go(location, extra: this);
|
||||||
|
|
||||||
|
void push(BuildContext context) => context.push(location, extra: this);
|
||||||
|
}
|
15
complete_example/lib/user.dart
Normal file
15
complete_example/lib/user.dart
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'user.freezed.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class User with _$User {
|
||||||
|
const factory User.signedIn({
|
||||||
|
required int id,
|
||||||
|
required String displayName,
|
||||||
|
required String email,
|
||||||
|
required String token,
|
||||||
|
}) = SignedIn;
|
||||||
|
|
||||||
|
const factory User.signedOut() = SignedOut;
|
||||||
|
}
|
356
complete_example/lib/user.freezed.dart
Normal file
356
complete_example/lib/user.freezed.dart
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
// coverage:ignore-file
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
|
||||||
|
|
||||||
|
part of 'user.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
final _privateConstructorUsedError = UnsupportedError(
|
||||||
|
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$User {
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult when<TResult extends Object?>({
|
||||||
|
required TResult Function(
|
||||||
|
int id, String displayName, String email, String token)
|
||||||
|
signedIn,
|
||||||
|
required TResult Function() signedOut,
|
||||||
|
}) =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? whenOrNull<TResult extends Object?>({
|
||||||
|
TResult? Function(int id, String displayName, String email, String token)?
|
||||||
|
signedIn,
|
||||||
|
TResult? Function()? signedOut,
|
||||||
|
}) =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeWhen<TResult extends Object?>({
|
||||||
|
TResult Function(int id, String displayName, String email, String token)?
|
||||||
|
signedIn,
|
||||||
|
TResult Function()? signedOut,
|
||||||
|
required TResult orElse(),
|
||||||
|
}) =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult map<TResult extends Object?>({
|
||||||
|
required TResult Function(SignedIn value) signedIn,
|
||||||
|
required TResult Function(SignedOut value) signedOut,
|
||||||
|
}) =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? mapOrNull<TResult extends Object?>({
|
||||||
|
TResult? Function(SignedIn value)? signedIn,
|
||||||
|
TResult? Function(SignedOut value)? signedOut,
|
||||||
|
}) =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeMap<TResult extends Object?>({
|
||||||
|
TResult Function(SignedIn value)? signedIn,
|
||||||
|
TResult Function(SignedOut value)? signedOut,
|
||||||
|
required TResult orElse(),
|
||||||
|
}) =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $UserCopyWith<$Res> {
|
||||||
|
factory $UserCopyWith(User value, $Res Function(User) then) =
|
||||||
|
_$UserCopyWithImpl<$Res, User>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$UserCopyWithImpl<$Res, $Val extends User>
|
||||||
|
implements $UserCopyWith<$Res> {
|
||||||
|
_$UserCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$SignedInCopyWith<$Res> {
|
||||||
|
factory _$$SignedInCopyWith(
|
||||||
|
_$SignedIn value, $Res Function(_$SignedIn) then) =
|
||||||
|
__$$SignedInCopyWithImpl<$Res>;
|
||||||
|
@useResult
|
||||||
|
$Res call({int id, String displayName, String email, String token});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$SignedInCopyWithImpl<$Res>
|
||||||
|
extends _$UserCopyWithImpl<$Res, _$SignedIn>
|
||||||
|
implements _$$SignedInCopyWith<$Res> {
|
||||||
|
__$$SignedInCopyWithImpl(_$SignedIn _value, $Res Function(_$SignedIn) _then)
|
||||||
|
: super(_value, _then);
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? id = null,
|
||||||
|
Object? displayName = null,
|
||||||
|
Object? email = null,
|
||||||
|
Object? token = null,
|
||||||
|
}) {
|
||||||
|
return _then(_$SignedIn(
|
||||||
|
id: null == id
|
||||||
|
? _value.id
|
||||||
|
: id // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,
|
||||||
|
displayName: null == displayName
|
||||||
|
? _value.displayName
|
||||||
|
: displayName // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
email: null == email
|
||||||
|
? _value.email
|
||||||
|
: email // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
token: null == token
|
||||||
|
? _value.token
|
||||||
|
: token // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
|
||||||
|
class _$SignedIn implements SignedIn {
|
||||||
|
const _$SignedIn(
|
||||||
|
{required this.id,
|
||||||
|
required this.displayName,
|
||||||
|
required this.email,
|
||||||
|
required this.token});
|
||||||
|
|
||||||
|
@override
|
||||||
|
final int id;
|
||||||
|
@override
|
||||||
|
final String displayName;
|
||||||
|
@override
|
||||||
|
final String email;
|
||||||
|
@override
|
||||||
|
final String token;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'User.signedIn(id: $id, displayName: $displayName, email: $email, token: $token)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(dynamic other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$SignedIn &&
|
||||||
|
(identical(other.id, id) || other.id == id) &&
|
||||||
|
(identical(other.displayName, displayName) ||
|
||||||
|
other.displayName == displayName) &&
|
||||||
|
(identical(other.email, email) || other.email == email) &&
|
||||||
|
(identical(other.token, token) || other.token == token));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType, id, displayName, email, token);
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$SignedInCopyWith<_$SignedIn> get copyWith =>
|
||||||
|
__$$SignedInCopyWithImpl<_$SignedIn>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult when<TResult extends Object?>({
|
||||||
|
required TResult Function(
|
||||||
|
int id, String displayName, String email, String token)
|
||||||
|
signedIn,
|
||||||
|
required TResult Function() signedOut,
|
||||||
|
}) {
|
||||||
|
return signedIn(id, displayName, email, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? whenOrNull<TResult extends Object?>({
|
||||||
|
TResult? Function(int id, String displayName, String email, String token)?
|
||||||
|
signedIn,
|
||||||
|
TResult? Function()? signedOut,
|
||||||
|
}) {
|
||||||
|
return signedIn?.call(id, displayName, email, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeWhen<TResult extends Object?>({
|
||||||
|
TResult Function(int id, String displayName, String email, String token)?
|
||||||
|
signedIn,
|
||||||
|
TResult Function()? signedOut,
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
if (signedIn != null) {
|
||||||
|
return signedIn(id, displayName, email, token);
|
||||||
|
}
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult map<TResult extends Object?>({
|
||||||
|
required TResult Function(SignedIn value) signedIn,
|
||||||
|
required TResult Function(SignedOut value) signedOut,
|
||||||
|
}) {
|
||||||
|
return signedIn(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? mapOrNull<TResult extends Object?>({
|
||||||
|
TResult? Function(SignedIn value)? signedIn,
|
||||||
|
TResult? Function(SignedOut value)? signedOut,
|
||||||
|
}) {
|
||||||
|
return signedIn?.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeMap<TResult extends Object?>({
|
||||||
|
TResult Function(SignedIn value)? signedIn,
|
||||||
|
TResult Function(SignedOut value)? signedOut,
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
if (signedIn != null) {
|
||||||
|
return signedIn(this);
|
||||||
|
}
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class SignedIn implements User {
|
||||||
|
const factory SignedIn(
|
||||||
|
{required final int id,
|
||||||
|
required final String displayName,
|
||||||
|
required final String email,
|
||||||
|
required final String token}) = _$SignedIn;
|
||||||
|
|
||||||
|
int get id;
|
||||||
|
String get displayName;
|
||||||
|
String get email;
|
||||||
|
String get token;
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
_$$SignedInCopyWith<_$SignedIn> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$SignedOutCopyWith<$Res> {
|
||||||
|
factory _$$SignedOutCopyWith(
|
||||||
|
_$SignedOut value, $Res Function(_$SignedOut) then) =
|
||||||
|
__$$SignedOutCopyWithImpl<$Res>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$SignedOutCopyWithImpl<$Res>
|
||||||
|
extends _$UserCopyWithImpl<$Res, _$SignedOut>
|
||||||
|
implements _$$SignedOutCopyWith<$Res> {
|
||||||
|
__$$SignedOutCopyWithImpl(
|
||||||
|
_$SignedOut _value, $Res Function(_$SignedOut) _then)
|
||||||
|
: super(_value, _then);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
|
||||||
|
class _$SignedOut implements SignedOut {
|
||||||
|
const _$SignedOut();
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'User.signedOut()';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(dynamic other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType && other is _$SignedOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => runtimeType.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult when<TResult extends Object?>({
|
||||||
|
required TResult Function(
|
||||||
|
int id, String displayName, String email, String token)
|
||||||
|
signedIn,
|
||||||
|
required TResult Function() signedOut,
|
||||||
|
}) {
|
||||||
|
return signedOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? whenOrNull<TResult extends Object?>({
|
||||||
|
TResult? Function(int id, String displayName, String email, String token)?
|
||||||
|
signedIn,
|
||||||
|
TResult? Function()? signedOut,
|
||||||
|
}) {
|
||||||
|
return signedOut?.call();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeWhen<TResult extends Object?>({
|
||||||
|
TResult Function(int id, String displayName, String email, String token)?
|
||||||
|
signedIn,
|
||||||
|
TResult Function()? signedOut,
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
if (signedOut != null) {
|
||||||
|
return signedOut();
|
||||||
|
}
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult map<TResult extends Object?>({
|
||||||
|
required TResult Function(SignedIn value) signedIn,
|
||||||
|
required TResult Function(SignedOut value) signedOut,
|
||||||
|
}) {
|
||||||
|
return signedOut(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? mapOrNull<TResult extends Object?>({
|
||||||
|
TResult? Function(SignedIn value)? signedIn,
|
||||||
|
TResult? Function(SignedOut value)? signedOut,
|
||||||
|
}) {
|
||||||
|
return signedOut?.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeMap<TResult extends Object?>({
|
||||||
|
TResult Function(SignedIn value)? signedIn,
|
||||||
|
TResult Function(SignedOut value)? signedOut,
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
if (signedOut != null) {
|
||||||
|
return signedOut(this);
|
||||||
|
}
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class SignedOut implements User {
|
||||||
|
const factory SignedOut() = _$SignedOut;
|
||||||
|
}
|
@ -1,6 +1,27 @@
|
|||||||
# Generated by pub
|
# Generated by pub
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
packages:
|
packages:
|
||||||
|
_fe_analyzer_shared:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: _fe_analyzer_shared
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "50.0.0"
|
||||||
|
analyzer:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: analyzer
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "5.2.0"
|
||||||
|
args:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: args
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.1"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -15,6 +36,62 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.0"
|
||||||
|
build:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.1"
|
||||||
|
build_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_config
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
|
build_daemon:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_daemon
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.0"
|
||||||
|
build_resolvers:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_resolvers
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
|
build_runner:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: build_runner
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.2"
|
||||||
|
build_runner_core:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_runner_core
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "7.2.7"
|
||||||
|
built_collection:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: built_collection
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "5.1.1"
|
||||||
|
built_value:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: built_value
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "8.4.2"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -22,6 +99,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.1"
|
version: "1.2.1"
|
||||||
|
checked_yaml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: checked_yaml
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -29,6 +113,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.1"
|
||||||
|
code_builder:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: code_builder
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "4.3.0"
|
||||||
collection:
|
collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -36,6 +127,27 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.16.0"
|
version: "1.16.0"
|
||||||
|
convert:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: convert
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.1"
|
||||||
|
crypto:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: crypto
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.2"
|
||||||
|
dart_style:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dart_style
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.4"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -57,6 +169,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.4"
|
version: "6.1.4"
|
||||||
|
fixnum:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fixnum
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -86,13 +205,76 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
freezed:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: freezed
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
|
freezed_annotation:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: freezed_annotation
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.0"
|
||||||
|
frontend_server_client:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: frontend_server_client
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.0"
|
||||||
|
glob:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: glob
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
go_router:
|
go_router:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: go_router
|
name: go_router
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.5"
|
version: "5.1.9"
|
||||||
|
go_router_builder:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: go_router_builder
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.15"
|
||||||
|
graphs:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: graphs
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.0"
|
||||||
|
http_multi_server:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_multi_server
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.1"
|
||||||
|
http_parser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_parser
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.2"
|
||||||
|
io:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: io
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
js:
|
js:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -100,6 +282,20 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.4"
|
version: "0.6.4"
|
||||||
|
json_annotation:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: json_annotation
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "4.7.0"
|
||||||
|
json_serializable:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: json_serializable
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "6.5.4"
|
||||||
lints:
|
lints:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -135,6 +331,20 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.0"
|
version: "1.8.0"
|
||||||
|
mime:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: mime
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.2"
|
||||||
|
package_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_config
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -163,6 +373,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.3"
|
version: "2.1.3"
|
||||||
|
path_to_regexp:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_to_regexp
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.4.0"
|
||||||
platform:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -177,6 +394,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.3"
|
version: "2.1.3"
|
||||||
|
pool:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pool
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.5.1"
|
||||||
process:
|
process:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -184,6 +408,20 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.4"
|
version: "4.2.4"
|
||||||
|
pub_semver:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pub_semver
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.3"
|
||||||
|
pubspec_parse:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pubspec_parse
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.1"
|
||||||
riverpod:
|
riverpod:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -191,6 +429,20 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.1"
|
||||||
|
riverpod_annotation:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: riverpod_annotation
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.6"
|
||||||
|
riverpod_generator:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: riverpod_generator
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.6"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -247,11 +499,39 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.1"
|
||||||
|
shelf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.0"
|
||||||
|
shelf_web_socket:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_web_socket
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.99"
|
version: "0.0.99"
|
||||||
|
source_gen:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_gen
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.6"
|
||||||
|
source_helper:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_helper
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.3"
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -280,6 +560,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.0"
|
||||||
|
stream_transform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stream_transform
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -301,6 +588,20 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.12"
|
version: "0.4.12"
|
||||||
|
timing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: timing
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
|
typed_data:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: typed_data
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.1"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -308,6 +609,20 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.2"
|
||||||
|
watcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: watcher
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.2"
|
||||||
|
web_socket_channel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web_socket_channel
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.0"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -322,6 +637,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0+2"
|
version: "0.2.0+2"
|
||||||
|
yaml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: yaml
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.18.0 <3.0.0"
|
dart: ">=2.18.0 <3.0.0"
|
||||||
flutter: ">=3.3.0"
|
flutter: ">=3.3.0"
|
||||||
|
@ -11,14 +11,22 @@ environment:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
go_router: ^5.0.5
|
go_router: ^5.1.9
|
||||||
flutter_riverpod: ^2.1.1
|
flutter_riverpod: ^2.1.1
|
||||||
|
riverpod_annotation: ^1.0.6
|
||||||
shared_preferences: ^2.0.15
|
shared_preferences: ^2.0.15
|
||||||
|
freezed_annotation: ^2.2.0
|
||||||
|
json_annotation: ^4.7.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
build_runner: ^2.3.2
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_lints: ^2.0.1
|
flutter_lints: ^2.0.1
|
||||||
|
go_router_builder: ^1.0.15
|
||||||
|
riverpod_generator: ^1.0.6
|
||||||
|
freezed: ^2.2.1
|
||||||
|
json_serializable: ^6.5.4
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
Reference in New Issue
Block a user