Skip to content

Commit

Permalink
refactor: remove declarative routes (#1288)
Browse files Browse the repository at this point in the history
  • Loading branch information
ookami-kb authored Feb 26, 2024
1 parent e41bd28 commit 9500baa
Show file tree
Hide file tree
Showing 20 changed files with 260 additions and 443 deletions.
54 changes: 15 additions & 39 deletions packages/espressocash_app/lib/app.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';

import 'di.dart';
import 'features/accounts/services/accounts_bloc.dart';
import 'features/accounts/services/account_service.dart';
import 'features/analytics/analytics_manager.dart';
import 'features/app_lock/app_lock.dart';
import 'features/authenticated/screens/authenticated_flow_screen.dart';
import 'features/sign_in/screens/sign_in_flow_screen.dart';
import 'l10n/gen/app_localizations.dart';
import 'routes.dart';
import 'ui/loader.dart';
import 'ui/splash_screen.dart';
import 'ui/theme.dart';

class EspressoCashApp extends StatefulWidget {
Expand All @@ -35,39 +30,20 @@ class _EspressoCashAppState extends State<EspressoCashApp> {
Widget build(BuildContext context) => CpTheme(
theme: const CpThemeData.light(),
child: Builder(
builder: (context) {
final isAuthenticated = context
.select<AccountsBloc, bool>((b) => b.state.account != null);
final isLoading =
context.select<AccountsBloc, bool>((b) => b.state.isProcessing);

return MaterialApp.router(
routeInformationParser: _router.defaultRouteParser(),
routerDelegate: AutoRouterDelegate.declarative(
_router,
routes: (_) => [
if (isAuthenticated)
AuthenticatedFlowScreen.route()
else if (isLoading)
SplashScreen.route()
else
SignInFlowScreen.route(),
],
navigatorObservers: () => [
sl<AnalyticsManager>().analyticsObserver,
],
),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
debugShowCheckedModeBanner: false,
title: 'Espresso Cash',
theme: context.watch<CpThemeData>().toMaterialTheme(),
builder: (context, child) => CpLoader(
isLoading: isLoading,
child: AppLockModule(child: child),
),
);
},
builder: (context) => MaterialApp.router(
routerConfig: _router.config(
reevaluateListenable: sl<AccountService>(),
navigatorObservers: () => [
sl<AnalyticsManager>().analyticsObserver,
],
),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
debugShowCheckedModeBanner: false,
title: 'Espresso Cash',
theme: context.watch<CpThemeData>().toMaterialTheme(),
builder: (context, child) => AppLockModule(child: child),
),
),
);
}
84 changes: 38 additions & 46 deletions packages/espressocash_app/lib/features/accounts/module.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,29 @@ import 'dart:async';

import 'package:dfunc/dfunc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:nested/nested.dart';
import 'package:solana_seed_vault/solana_seed_vault.dart';

import '../../core/callback.dart';
import '../../core/extensions.dart';
import '../../di.config.dart';
import '../../di.dart';
import '../authenticated/auth_scope.dart';
import 'models/account.dart';
import 'models/ec_wallet.dart';
import 'services/accounts_bloc.dart';
import 'services/account_service.dart';
import 'widgets/account_listener.dart';

class AccountsModule extends SingleChildStatelessWidget {
const AccountsModule({super.key, super.child});

@override
Widget buildWithChild(BuildContext context, Widget? child) => BlocProvider(
create: (context) => sl<AccountsBloc>(
param1: sl.initAuthScope,
param2: () => sl.dropScope(authScope),
)..add(const AccountsEvent.initialize()),
child: Builder(
builder: (context) => SeedVaultListener(
onDeauthorized: () => context
.read<AccountsBloc>()
.add(const AccountsEvent.loggedOut()),
child: child,
),
),
Widget buildWithChild(BuildContext context, Widget? child) =>
SeedVaultListener(
onDeauthorized: () => sl<AccountService>().logOut(),
child: child,
);
}

class LogoutListener extends SingleChildStatelessWidget {
class LogoutListener extends SingleChildStatefulWidget {
const LogoutListener({
super.key,
super.child,
Expand All @@ -44,17 +33,22 @@ class LogoutListener extends SingleChildStatelessWidget {

final Callback1<BuildContext> onLogout;

@override
State<StatefulWidget> createState() => _LogoutListenerState();
}

class _LogoutListenerState extends SingleChildState<LogoutListener>
with AccountListener {
@override
void handleAccountChanged(MyAccount? account) {
if (account == null) {
widget.onLogout(context);
}
}

@override
Widget buildWithChild(BuildContext context, Widget? child) =>
BlocListener<AccountsBloc, AccountsState>(
listenWhen: (s1, s2) => s1.account != s2.account,
listener: (context, state) {
if (state.account == null) {
onLogout(context);
}
},
child: child,
);
child ?? const SizedBox.shrink();
}

/// In case of a Saga Wallet, this component will notify if the Seed Vault
Expand All @@ -72,7 +66,8 @@ class SeedVaultListener extends SingleChildStatefulWidget {
State<StatefulWidget> createState() => _SeedVaultListenerState();
}

class _SeedVaultListenerState extends SingleChildState<SeedVaultListener> {
class _SeedVaultListenerState extends SingleChildState<SeedVaultListener>
with AccountListener {
StreamSubscription<SeedVaultNotification>? _subscription;

@override
Expand All @@ -81,19 +76,6 @@ class _SeedVaultListenerState extends SingleChildState<SeedVaultListener> {
super.dispose();
}

void _handleUpdateAccount(MyAccount? account) {
_subscription?.cancel();

final sagaWallet =
account?.wallet.let((it) => it is SagaWallet ? it : null);

if (sagaWallet == null) return;

_subscription = sl<SeedVault>()
.notificationStream
.listen((event) => _onNotification(event, sagaWallet));
}

Future<void> _onNotification(
SeedVaultNotification event,
SagaWallet wallet,
Expand All @@ -106,13 +88,23 @@ class _SeedVaultListenerState extends SingleChildState<SeedVaultListener> {
if (!accountExistsAndIsAuthorized) widget.onDeauthorized();
}

@override
void handleAccountChanged(MyAccount? account) {
_subscription?.cancel();

final sagaWallet =
account?.wallet.let((it) => it is SagaWallet ? it : null);

if (sagaWallet == null) return;

_subscription = sl<SeedVault>()
.notificationStream
.listen((event) => _onNotification(event, sagaWallet));
}

@override
Widget buildWithChild(BuildContext context, Widget? child) =>
BlocListener<AccountsBloc, AccountsState>(
listenWhen: (prev, cur) => prev.account != cur.account,
listener: (_, state) => _handleUpdateAccount(state.account),
child: child,
);
child ?? const SizedBox.shrink();
}

final _affectedUris = WalletContractV1().let(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:injectable/injectable.dart';
import 'package:sentry_flutter/sentry_flutter.dart';

import '../../../di.config.dart';
import '../../../di.dart';
import '../../analytics/analytics_manager.dart';
import '../../authenticated/auth_scope.dart';
import '../data/account_repository.dart';
import '../models/account.dart';
import '../models/mnemonic.dart';

@Singleton()
class AccountService extends ChangeNotifier
implements ValueListenable<MyAccount?> {
AccountService(
this._repository,
this._analyticsManager,
this._storage,
);

final AccountRepository _repository;
final AnalyticsManager _analyticsManager;
final FlutterSecureStorage _storage;

MyAccount? _value;

@override
MyAccount? get value => _value;

void _update(MyAccount? value) {
if (value == _value) return;

_value = value;
notifyListeners();
}

Future<void> initialize() async {
final account = await _repository.loadAccount();
if (account != null) {
await _processLogIn(account);
}
}

Future<void> logIn({
required AccountSource source,
required MyAccount account,
}) async {
await _repository.saveAccountSource(source);
await _processLogIn(account);
}

Future<void> logOut() async {
if (_value == null) return;

_analyticsManager.setWalletAddress(null);
Sentry.configureScope((scope) => scope.removeExtra('walletAddress'));

await _storage.deleteAll();
await sl.dropScope(authScope);

_update(null);
}

Future<void> _processLogIn(MyAccount account) async {
Sentry.configureScope(
(scope) => scope.setExtra('walletAddress', account.address),
);
_analyticsManager.setWalletAddress(account.address);
await sl.initAuthScope();

_update(account);
}
}

This file was deleted.

Loading

0 comments on commit 9500baa

Please sign in to comment.