Changed the main example with code gen tools

This commit is contained in:
venir.dev
2022-11-17 17:11:40 +01:00
parent 7f2f782b08
commit 0e7f5e8140
15 changed files with 1116 additions and 176 deletions

View File

@ -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
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:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
analyzer:
errors:
invalid_annotation_target: ignore
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
linter:
rules:

View File

@ -1,108 +1,111 @@
import 'dart:async';
import 'dart:math';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shared_preferences/shared_preferences.dart';
class User {
const User({
required this.displayName,
required this.email,
required this.token,
});
import 'user.dart';
final String displayName;
final String email;
final String token;
}
part 'auth.g.dart';
// TODO in the next version: Use Freezed to generate states.
typedef AsyncUser = AsyncValue<User?>;
final authProvider = AsyncNotifierProvider<AuthNotifier, User?>(() {
return AuthNotifier();
});
class AuthNotifier extends AsyncNotifier<User?> {
AuthNotifier();
static const _key = 'token';
@override
FutureOr<User?> build() async {
final sharedPreferences = await SharedPreferences.getInstance();
ref.listenSelf((_, next) {
final val = next.valueOrNull;
if (val == null) {
sharedPreferences.remove(_key);
return;
}
sharedPreferences.setString(_key, val.email);
});
try {
// This operation might fail for... reasons
final savedToken = sharedPreferences.getString(_key);
if (savedToken == null) return null;
// This request might also fail
return await _loginWithToken(savedToken);
} catch (error, stackTrace) {
// If anything goes wrong, give a non-authenticated outcome
await sharedPreferences.remove(_key);
print(error);
print(stackTrace);
return null;
}
}
Future<User?> _loginWithToken(String token) async {
// here the token should be used to perform a login request
final logInAttempt = await Future.delayed(
const Duration(milliseconds: 750),
() => Random().nextBool(), // mock
);
// If the attempts succeeds, return the result out
if (logInAttempt) {
return const User(
/// A mock of an Authenticated User
const _dummyUser = User.signedIn(
id: 0,
displayName: "My Name",
email: "My Email",
token: "some-updated-secret-auth-token",
);
@riverpod
class AuthNotifier extends _$AuthNotifier {
late SharedPreferences sharedPreferences;
static const _sharedPrefsKey = 'token';
/// Mock of the duration of a network request
final _networkRoundTripTime = Random().nextInt(750);
@override
FutureOr<User> build() async {
sharedPreferences = await SharedPreferences.getInstance();
_persistenceRefreshLogic();
return await _loginRecoveryAttempt();
}
// If the attempt fails, or returns 401, or whatever, this should fail.
throw const UnauthorizedException('401 Unauthorized or something');
/// 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 {
final savedToken = sharedPreferences.getString(_sharedPrefsKey);
if (savedToken == null) {
throw const UnauthorizedException(
"Couldn't find the authentication token");
}
return await _loginWithToken(savedToken);
} catch (_, __) {
await sharedPreferences.remove(_sharedPrefsKey);
return const User.signedOut();
}
}
/// Mock of a request performed on logout (might be common, or not, whatevs).
Future<void> logout() async {
final sharedPreferences = await SharedPreferences.getInstance();
// Remove the token from persistence, first
await sharedPreferences.remove(_key);
// No request is mocked here but I guess we could: logout
state = const AsyncUser.data(null);
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 {
// Simple mock of a successful login attempt
state = await AsyncUser.guard(() async {
state = await AsyncValue.guard<User>(() async {
return Future.delayed(
Duration(milliseconds: Random().nextInt(750)),
() => const User(
displayName: "My Name",
email: "My Email",
token: 'someToken',
),
Duration(milliseconds: _networkRoundTripTime),
() => _dummyUser,
);
});
}
bool get isAuthenticated => state.valueOrNull != null;
bool get isLoading => state.isLoading;
/// 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(
Duration(milliseconds: _networkRoundTripTime),
() => true,
);
if (logInAttempt) return _dummyUser;
throw const UnauthorizedException('401 Unauthorized or something');
}
/// Internal method used to listen authentication state changes.
/// 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;
}
final val = next.requireValue;
val.map<void>(
signedIn: (signedIn) {
sharedPreferences.setString(_sharedPrefsKey, signedIn.token);
},
signedOut: (signedOut) {
sharedPreferences.remove(_sharedPrefsKey);
},
);
});
}
}
/// Simple mock of a 401 exception
class UnauthorizedException implements Exception {
final String message;
const UnauthorizedException(this.message);

View 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();
}

View File

@ -16,35 +16,20 @@ class MyAwesomeApp extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final asyncRouter = ref.watch(routerProvider);
final router = ref.watch(routerProvider);
if (asyncRouter.hasValue) {
final router = asyncRouter.requireValue;
return MaterialApp.router(
routeInformationParser: router.routeInformationParser,
routerDelegate: router.routerDelegate,
routeInformationProvider: router.routeInformationProvider,
routerConfig: router,
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 {
const HomePage({super.key});
static String get routeName => 'home';
static String get routeLocation => '/';
@override
Widget build(BuildContext context, WidgetRef ref) {
@ -58,7 +43,7 @@ class HomePage extends ConsumerWidget {
const Text("Home Page"),
ElevatedButton(
onPressed: () {
ref.read(authProvider.notifier).logout();
ref.read(authNotifierProvider.notifier).logout();
},
child: const Text("Logout"),
),
@ -71,8 +56,6 @@ class HomePage extends ConsumerWidget {
class LoginPage extends ConsumerWidget {
const LoginPage({super.key});
static String get routeName => 'login';
static String get routeLocation => '/$routeName';
@override
Widget build(BuildContext context, WidgetRef ref) {
@ -86,7 +69,7 @@ class LoginPage extends ConsumerWidget {
const Text("Login Page"),
ElevatedButton(
onPressed: () async {
ref.read(authProvider.notifier).login(
ref.read(authNotifierProvider.notifier).login(
"myEmail",
"myPassword",
);
@ -102,8 +85,6 @@ class LoginPage extends ConsumerWidget {
class SplashPage extends StatelessWidget {
const SplashPage({super.key});
static String get routeName => 'splash';
static String get routeLocation => '/$routeName';
@override
Widget build(BuildContext context) {

View File

@ -9,11 +9,12 @@ class RiverpodLogger extends ProviderObserver {
Object? newValue,
ProviderContainer container,
) {
// TODO use a proper logger
print('''
{
provider: ${provider.name ?? provider.runtimeType},
oldValue: ${previousValue ?? 'None'},
newValue: ${newValue ?? 'None'}
oldValue: $previousValue,
newValue: $newValue
}
''');
super.didUpdateProvider(provider, previousValue, newValue, container);

View File

@ -1,57 +1,25 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'auth.dart';
import 'main.dart';
import 'router_notifier.dart';
import 'routes.dart';
final _key = GlobalKey<NavigatorState>();
part 'router.g.dart';
final routerProvider = FutureProvider<GoRouter>((ref) async {
final isAuth = await ref.watch(
authProvider.selectAsync((value) => value != null),
);
final _key = GlobalKey<NavigatorState>(debugLabel: 'routerKey');
@riverpod
GoRouter router(RouterRef ref) {
ref.watch(routerNotifierProvider);
final notifier = ref.read(routerNotifierProvider.notifier);
return GoRouter(
navigatorKey: _key,
refreshListenable: notifier,
debugLogDiagnostics: true,
initialLocation: SplashPage.routeLocation,
routes: [
GoRoute(
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;
},
initialLocation: SplashRoute.path,
routes: notifier.routes,
redirect: notifier.redirect,
);
});
}

View 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>;

View 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;
}
}

View 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();
}

View 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();
}
}

View 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);
}

View 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;
}

View 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;
}

View File

@ -1,6 +1,27 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
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:
dependency: transitive
description:
@ -15,6 +36,62 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
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:
dependency: transitive
description:
@ -22,6 +99,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
clock:
dependency: transitive
description:
@ -29,6 +113,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
code_builder:
dependency: transitive
description:
name: code_builder
url: "https://pub.dartlang.org"
source: hosted
version: "4.3.0"
collection:
dependency: transitive
description:
@ -36,6 +127,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
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:
dependency: transitive
description:
@ -57,6 +169,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.4"
fixnum:
dependency: transitive
description:
name: fixnum
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
flutter:
dependency: "direct main"
description: flutter
@ -86,13 +205,76 @@ packages:
description: flutter
source: sdk
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:
dependency: "direct main"
description:
name: go_router
url: "https://pub.dartlang.org"
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:
dependency: transitive
description:
@ -100,6 +282,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
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:
dependency: transitive
description:
@ -135,6 +331,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
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:
dependency: transitive
description:
@ -163,6 +373,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
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:
dependency: transitive
description:
@ -177,6 +394,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
pool:
dependency: transitive
description:
name: pool
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.1"
process:
dependency: transitive
description:
@ -184,6 +408,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
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:
dependency: transitive
description:
@ -191,6 +429,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
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:
dependency: "direct main"
description:
@ -247,11 +499,39 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
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:
dependency: transitive
description: flutter
source: sdk
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:
dependency: transitive
description:
@ -280,6 +560,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
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:
dependency: transitive
description:
@ -301,6 +588,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
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:
dependency: transitive
description:
@ -308,6 +609,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
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:
dependency: transitive
description:
@ -322,6 +637,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0+2"
yaml:
dependency: transitive
description:
name: yaml
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.1"
sdks:
dart: ">=2.18.0 <3.0.0"
flutter: ">=3.3.0"

View File

@ -11,14 +11,22 @@ environment:
dependencies:
flutter:
sdk: flutter
go_router: ^5.0.5
go_router: ^5.1.9
flutter_riverpod: ^2.1.1
riverpod_annotation: ^1.0.6
shared_preferences: ^2.0.15
freezed_annotation: ^2.2.0
json_annotation: ^4.7.0
dev_dependencies:
build_runner: ^2.3.2
flutter_test:
sdk: flutter
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:
uses-material-design: true