From e38380144654489934eef13f5467f9bf807a09d3 Mon Sep 17 00:00:00 2001 From: Amaury Date: Wed, 12 Nov 2025 17:09:57 -0300 Subject: [PATCH 1/5] improve app navigation, and save navigation based on the auth state --- app/lib/main/app.dart | 29 ++--- app/lib/main/init.dart | 5 +- app/lib/presentation/navigation/routers.dart | 108 +++++++++++++++--- .../presentation/ui/pages/home/home_view.dart | 2 + .../ui/pages/login/login_page.dart | 1 - .../ui/pages/splash/splash_page.dart | 5 +- app/pubspec.yaml | 7 +- modules/domain/lib/bloc/auth/auth_cubit.dart | 3 + 8 files changed, 114 insertions(+), 46 deletions(-) diff --git a/app/lib/main/app.dart b/app/lib/main/app.dart index 7ed667d..f0ad622 100644 --- a/app/lib/main/app.dart +++ b/app/lib/main/app.dart @@ -1,3 +1,4 @@ +import 'package:app/presentation/ui/custom/loading_screen.dart'; import 'package:common/core/resource.dart'; import 'package:flutter/material.dart'; import 'package:domain/bloc/app/app_cubit.dart'; @@ -10,13 +11,10 @@ import 'package:app/presentation/themes/app_themes.dart'; import 'package:app/presentation/utils/lang_extensions.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; -import 'package:go_router/go_router.dart'; import 'init.dart'; class App extends StatelessWidget { - GoRouter get _goRouter => Routers.authRouter; - const App({super.key}); @override @@ -38,23 +36,14 @@ class App extends StatelessWidget { GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], - builder: (context, child) { - return BlocListener( - listener: (_, state) { - if (state is RSuccess) { - switch (state.data) { - case AuthStateAuthenticated _: - _goRouter.go('/home'); - case AuthStateUnauthenticated _: - _goRouter.go('/login'); - case _: - } - } - }, - child: child, - ); - }, - routerConfig: _goRouter, + builder: (context, child) => + child ?? + const Material( + child: Center( + child: CircularProgressIndicator(), + ), + ), + routerConfig: Routes.router, ); }, ), diff --git a/app/lib/main/init.dart b/app/lib/main/init.dart index 08c6769..7be81c9 100644 --- a/app/lib/main/init.dart +++ b/app/lib/main/init.dart @@ -6,12 +6,13 @@ import 'package:data/init.dart'; import 'package:domain/init.dart'; import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; -import 'package:url_strategy/url_strategy.dart'; +import 'package:flutter_web_plugins/flutter_web_plugins.dart'; + void init() async { WidgetsFlutterBinding.ensureInitialized(); + usePathUrlStrategy(); await initialize(); - setHashUrlStrategy(); runApp(const App()); } diff --git a/app/lib/presentation/navigation/routers.dart b/app/lib/presentation/navigation/routers.dart index 572a59c..e1b27c7 100644 --- a/app/lib/presentation/navigation/routers.dart +++ b/app/lib/presentation/navigation/routers.dart @@ -1,32 +1,102 @@ +import 'package:app/main/init.dart'; import 'package:app/presentation/ui/pages/home/home_page.dart'; import 'package:app/presentation/ui/pages/login/login_page.dart'; import 'package:app/presentation/ui/pages/sign_up/sign_up_page.dart'; import 'package:app/presentation/ui/pages/splash/splash_page.dart'; +import 'package:common/core/resource.dart'; +import 'package:domain/bloc/auth/auth_cubit.dart'; +import 'package:domain/bloc/auth/auth_state.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; +enum Routes { + auth, + login, + signUp, + app, + home; + + String get path => '/$name'; + String get subPath => name; + + void nav({Object? extra}) { + Routers.authRouter.goNamed( + name, + extra: extra, + ); + } + + static GoRouter get router => Routers.authRouter; +} + class Routers { static GoRouter authRouter = GoRouter( - initialLocation: "/splash", + initialLocation: '/', routes: [ GoRoute( - name: "login", - path: "/login", - builder: (context, state) => const LoginPage(), - ), - GoRoute( - name: "splash", - path: "/splash", - builder: (context, state) => const SplashPage(), - ), - GoRoute( - name: "signUp", - path: "/signUp", - builder: (context, state) => const SignUpPage(), - ), - GoRoute( - name: "home", - path: "/home", - builder: (context, state) => const HomePage(), + path: '/', + builder: (context, state) { + return BlocListener( + listener: (_, state) { + if (state is RSuccess) { + switch (state.data) { + case AuthStateAuthenticated _: + Routes.app.nav(); + break; + case AuthStateUnauthenticated _: + Routes.auth.nav(); + break; + case _: + } + } + }, + child: const SplashPage(instant: true), + ); + }, + routes: [ + GoRoute( + name: Routes.auth.name, + path: Routes.auth.path, + redirect: (context, state) { + if (getIt().isLoggedIn()) { + return '${Routes.app.path}${Routes.home.path}'; + } + + return '${Routes.auth.path}${Routes.login.path}'; + }, + routes: [ + GoRoute( + name: Routes.login.name, + path: Routes.login.subPath, + builder: (context, state) => const LoginPage(), + ), + GoRoute( + name: Routes.signUp.name, + path: Routes.signUp.subPath, + builder: (context, state) => const SignUpPage(), + ), + ], + ), + GoRoute( + name: Routes.app.name, + path: Routes.app.path, + builder: (context, state) => const SplashPage(), + redirect: (context, state) { + if (!getIt().isLoggedIn()) { + return '${Routes.auth.path}${Routes.login.path}'; + } + + return '${Routes.app.path}${Routes.home.path}'; + }, + routes: [ + GoRoute( + name: Routes.home.name, + path: Routes.home.subPath, + builder: (context, state) => const HomePage(), + ), + ], + ), + ], ), ], ); diff --git a/app/lib/presentation/ui/pages/home/home_view.dart b/app/lib/presentation/ui/pages/home/home_view.dart index 1edcc29..f0d9eb8 100644 --- a/app/lib/presentation/ui/pages/home/home_view.dart +++ b/app/lib/presentation/ui/pages/home/home_view.dart @@ -14,6 +14,8 @@ class HomeView extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( + title: const Text('Home'), + automaticallyImplyLeading: false, actions: [ IconButton( onPressed: () => _authCubit.logOut(), diff --git a/app/lib/presentation/ui/pages/login/login_page.dart b/app/lib/presentation/ui/pages/login/login_page.dart index 5c9b666..147a1a7 100644 --- a/app/lib/presentation/ui/pages/login/login_page.dart +++ b/app/lib/presentation/ui/pages/login/login_page.dart @@ -1,6 +1,5 @@ import 'package:app/main/init.dart'; import 'package:app/presentation/resources/resources.dart'; -import 'package:app/presentation/themes/app_themes.dart'; import 'package:app/presentation/ui/custom/app_theme_switch.dart'; import 'package:app/presentation/ui/custom/loading_screen.dart'; import 'package:common/core/resource.dart'; diff --git a/app/lib/presentation/ui/pages/splash/splash_page.dart b/app/lib/presentation/ui/pages/splash/splash_page.dart index 9e8a0aa..9b8f1f4 100644 --- a/app/lib/presentation/ui/pages/splash/splash_page.dart +++ b/app/lib/presentation/ui/pages/splash/splash_page.dart @@ -3,7 +3,8 @@ import 'package:domain/bloc/auth/auth_cubit.dart'; import 'package:flutter/material.dart'; class SplashPage extends StatefulWidget { - const SplashPage({super.key}); + final bool instant; + const SplashPage({super.key, this.instant = true}); @override State createState() => _SplashPageState(); @@ -20,7 +21,7 @@ class _SplashPageState extends State { /// Add post frame callback to avoid calling bloc methods during build WidgetsBinding.instance.addPostFrameCallback((_) async { - await Future.delayed(const Duration(seconds: 1)); + await Future.delayed(Duration(seconds: widget.instant ? 0 : 2)); _authCubit.onValidate(); }); } diff --git a/app/pubspec.yaml b/app/pubspec.yaml index c967b0a..8888675 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -18,7 +18,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: '>=3.0.0 <4.0.0' + sdk: ">=3.0.0 <4.0.0" dependencies: flutter: @@ -35,7 +35,7 @@ dependencies: package_info_plus: ^8.3.0 permission_handler: ^11.4.0 universal_html: ^2.2.2 - go_router: ^7.0.1 + go_router: ^17.0.0 equatable: ^2.0.5 firebase_core: ^3.13.0 url_strategy: ^0.2.0 @@ -51,6 +51,9 @@ dependencies: http: ^1.5.0 melos: ^3.4.0 dev: ^1.0.0 + flutter_dotenv: ^5.2.1 + flutter_web_plugins: + sdk: flutter dev_dependencies: bloc_test: ^9.0.2 diff --git a/modules/domain/lib/bloc/auth/auth_cubit.dart b/modules/domain/lib/bloc/auth/auth_cubit.dart index 27d53b1..00a1b89 100644 --- a/modules/domain/lib/bloc/auth/auth_cubit.dart +++ b/modules/domain/lib/bloc/auth/auth_cubit.dart @@ -31,6 +31,9 @@ class AuthCubit extends BaseCubit { isLogOut(); } + bool isLoggedIn() => + state is RSuccess && (state as RSuccess).data is AuthStateAuthenticated; + void isLogin() => isSuccess(AuthStateAuthenticated()); void isLogOut() => isSuccess(AuthStateUnauthenticated()); From b10b72b09434d531d243759d4ea37f87443e115e Mon Sep 17 00:00:00 2001 From: Amaury Date: Wed, 12 Nov 2025 17:21:59 -0300 Subject: [PATCH 2/5] improve auth state ref --- app/lib/main/app.dart | 3 --- app/lib/presentation/navigation/routers.dart | 19 ++++++++++--------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/app/lib/main/app.dart b/app/lib/main/app.dart index f0ad622..4605819 100644 --- a/app/lib/main/app.dart +++ b/app/lib/main/app.dart @@ -1,10 +1,7 @@ -import 'package:app/presentation/ui/custom/loading_screen.dart'; -import 'package:common/core/resource.dart'; import 'package:flutter/material.dart'; import 'package:domain/bloc/app/app_cubit.dart'; import 'package:domain/bloc/app/app_state.dart'; import 'package:domain/bloc/auth/auth_cubit.dart'; -import 'package:domain/bloc/auth/auth_state.dart'; import 'package:app/presentation/navigation/routers.dart'; import 'package:app/presentation/resources/locale/generated/l10n.dart'; import 'package:app/presentation/themes/app_themes.dart'; diff --git a/app/lib/presentation/navigation/routers.dart b/app/lib/presentation/navigation/routers.dart index e1b27c7..97b8b2b 100644 --- a/app/lib/presentation/navigation/routers.dart +++ b/app/lib/presentation/navigation/routers.dart @@ -1,4 +1,3 @@ -import 'package:app/main/init.dart'; import 'package:app/presentation/ui/pages/home/home_page.dart'; import 'package:app/presentation/ui/pages/login/login_page.dart'; import 'package:app/presentation/ui/pages/sign_up/sign_up_page.dart'; @@ -12,7 +11,7 @@ import 'package:go_router/go_router.dart'; enum Routes { auth, login, - signUp, + signup, app, home; @@ -37,6 +36,7 @@ class Routers { path: '/', builder: (context, state) { return BlocListener( + listenWhen: (previous, current) => current is RSuccess, listener: (_, state) { if (state is RSuccess) { switch (state.data) { @@ -58,11 +58,12 @@ class Routers { name: Routes.auth.name, path: Routes.auth.path, redirect: (context, state) { - if (getIt().isLoggedIn()) { + if (context.read().isLoggedIn()) { return '${Routes.app.path}${Routes.home.path}'; } - return '${Routes.auth.path}${Routes.login.path}'; + /// Continue to auth routes + return null; }, routes: [ GoRoute( @@ -71,8 +72,8 @@ class Routers { builder: (context, state) => const LoginPage(), ), GoRoute( - name: Routes.signUp.name, - path: Routes.signUp.subPath, + name: Routes.signup.name, + path: Routes.signup.subPath, builder: (context, state) => const SignUpPage(), ), ], @@ -80,13 +81,13 @@ class Routers { GoRoute( name: Routes.app.name, path: Routes.app.path, - builder: (context, state) => const SplashPage(), redirect: (context, state) { - if (!getIt().isLoggedIn()) { + if (!context.read().isLoggedIn()) { return '${Routes.auth.path}${Routes.login.path}'; } - return '${Routes.app.path}${Routes.home.path}'; + /// Continue to app routes + return null; }, routes: [ GoRoute( From 394ee16c39fec3d2cc153636a6b5e6456cfbc977 Mon Sep 17 00:00:00 2001 From: Amaury Date: Mon, 17 Nov 2025 10:09:50 -0300 Subject: [PATCH 3/5] imrpove go router --- app/lib/presentation/navigation/routers.dart | 41 ++++++++++--------- .../ui/pages/login/login_page.dart | 7 ++-- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/app/lib/presentation/navigation/routers.dart b/app/lib/presentation/navigation/routers.dart index 97b8b2b..db8d28b 100644 --- a/app/lib/presentation/navigation/routers.dart +++ b/app/lib/presentation/navigation/routers.dart @@ -5,6 +5,7 @@ import 'package:app/presentation/ui/pages/splash/splash_page.dart'; import 'package:common/core/resource.dart'; import 'package:domain/bloc/auth/auth_cubit.dart'; import 'package:domain/bloc/auth/auth_state.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; @@ -13,7 +14,8 @@ enum Routes { login, signup, app, - home; + home, + placeholder; String get path => '/$name'; String get subPath => name; @@ -41,60 +43,61 @@ class Routers { if (state is RSuccess) { switch (state.data) { case AuthStateAuthenticated _: + debugPrint('User is authenticated'); Routes.app.nav(); break; case AuthStateUnauthenticated _: + debugPrint('User is unauthenticated'); Routes.auth.nav(); break; case _: } } }, - child: const SplashPage(instant: true), + child: const SplashPage(), ); }, routes: [ - GoRoute( - name: Routes.auth.name, - path: Routes.auth.path, + ShellRoute( + builder: (context, state, child) => child, redirect: (context, state) { if (context.read().isLoggedIn()) { - return '${Routes.app.path}${Routes.home.path}'; + return Routes.app.path; } - - /// Continue to auth routes return null; }, routes: [ GoRoute( - name: Routes.login.name, - path: Routes.login.subPath, + name: Routes.auth.name, + path: Routes.auth.path, builder: (context, state) => const LoginPage(), ), GoRoute( name: Routes.signup.name, - path: Routes.signup.subPath, + path: '${Routes.auth.path}${Routes.signup.path}', builder: (context, state) => const SignUpPage(), ), ], ), - GoRoute( - name: Routes.app.name, - path: Routes.app.path, + ShellRoute( + builder: (context, state, child) => child, redirect: (context, state) { if (!context.read().isLoggedIn()) { - return '${Routes.auth.path}${Routes.login.path}'; + return Routes.auth.path; } - - /// Continue to app routes return null; }, routes: [ GoRoute( - name: Routes.home.name, - path: Routes.home.subPath, + name: Routes.app.name, + path: Routes.app.path, builder: (context, state) => const HomePage(), ), + GoRoute( + name: Routes.placeholder.name, + path: "${Routes.app.path}${Routes.placeholder.path}", + builder: (context, state) => const Placeholder(), + ), ], ), ], diff --git a/app/lib/presentation/ui/pages/login/login_page.dart b/app/lib/presentation/ui/pages/login/login_page.dart index 147a1a7..6df6f7c 100644 --- a/app/lib/presentation/ui/pages/login/login_page.dart +++ b/app/lib/presentation/ui/pages/login/login_page.dart @@ -1,4 +1,5 @@ import 'package:app/main/init.dart'; +import 'package:app/presentation/navigation/routers.dart'; import 'package:app/presentation/resources/resources.dart'; import 'package:app/presentation/ui/custom/app_theme_switch.dart'; import 'package:app/presentation/ui/custom/loading_screen.dart'; @@ -32,10 +33,8 @@ class LoginPage extends StatelessWidget { child: ElevatedButton( child: const Text('Login'), onPressed: () { - _authCubit.login( - 'Rootstrap', - '12345678', - ); + Routes.signup.nav(); + //_authCubit.login('Rootstrap', '12345678'); }, ), ), From 15f9331647b6b3bd97971988adec40014876f4a1 Mon Sep 17 00:00:00 2001 From: Amaury Date: Mon, 17 Nov 2025 11:00:22 -0300 Subject: [PATCH 4/5] add deeplink support --- app/lib/main/app.dart | 100 ++++++++--- app/lib/presentation/navigation/routers.dart | 165 ++++++++++-------- .../ui/pages/login/login_page.dart | 3 +- .../flutter/generated_plugin_registrant.cc | 4 + app/linux/flutter/generated_plugins.cmake | 1 + app/pubspec.yaml | 1 + modules/domain/lib/bloc/auth/auth_cubit.dart | 3 +- pubspec.yaml | 1 + 8 files changed, 181 insertions(+), 97 deletions(-) diff --git a/app/lib/main/app.dart b/app/lib/main/app.dart index 4605819..018ad8b 100644 --- a/app/lib/main/app.dart +++ b/app/lib/main/app.dart @@ -8,12 +8,56 @@ import 'package:app/presentation/themes/app_themes.dart'; import 'package:app/presentation/utils/lang_extensions.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; - +import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:app_links/app_links.dart'; +import 'package:go_router/go_router.dart'; import 'init.dart'; -class App extends StatelessWidget { +class App extends StatefulWidget { const App({super.key}); + @override + State createState() => _AppState(); +} + +class _AppState extends State { + late final GoRouter _router; + bool _isRouterReady = false; + + @override + void initState() { + super.initState(); + _initRouter(); + } + + Future _initRouter() async { + String? initialLocation; + if (kIsWeb) { + final path = Uri.base.path; + if (path.isNotEmpty && path != '/') { + initialLocation = path; + } + } else { + final appLinks = AppLinks(); + final initialUri = await appLinks.getInitialLink(); + if (initialUri != null) { + initialLocation = initialUri.path; + } + } + + debugPrint('App entry point: $initialLocation'); + + if (mounted) { + setState(() { + _router = Routes.init( + context, + initialLocation: initialLocation, + ); + _isRouterReady = true; + }); + } + } + @override Widget build(BuildContext context) { return MultiBlocProvider( @@ -21,29 +65,35 @@ class App extends StatelessWidget { BlocProvider(create: (_) => getIt()), BlocProvider(create: (_) => getIt()), ], - child: BlocBuilder( - builder: (context, state) { - return MaterialApp.router( - theme: AppThemes.getAppTheme(state.themeType).data, - locale: LangExtensions.langLocale[state.appLang], - supportedLocales: LangExtensions.supportedLang, - localizationsDelegates: const [ - S.delegate, - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - builder: (context, child) => - child ?? - const Material( - child: Center( - child: CircularProgressIndicator(), - ), - ), - routerConfig: Routes.router, - ); - }, - ), + child: !_isRouterReady + ? const Material( + child: Center( + child: CircularProgressIndicator(), + ), + ) + : BlocBuilder( + builder: (context, state) { + return MaterialApp.router( + theme: AppThemes.getAppTheme(state.themeType).data, + locale: LangExtensions.langLocale[state.appLang], + supportedLocales: LangExtensions.supportedLang, + localizationsDelegates: const [ + S.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + builder: (context, child) => + child ?? + const Material( + child: Center( + child: CircularProgressIndicator(), + ), + ), + routerConfig: _router, + ); + }, + ), ); } } diff --git a/app/lib/presentation/navigation/routers.dart b/app/lib/presentation/navigation/routers.dart index db8d28b..028a3fc 100644 --- a/app/lib/presentation/navigation/routers.dart +++ b/app/lib/presentation/navigation/routers.dart @@ -20,88 +20,117 @@ enum Routes { String get path => '/$name'; String get subPath => name; - void nav({Object? extra}) { - Routers.authRouter.goNamed( + void nav(BuildContext context, {Object? extra}) { + context.router.goNamed( name, extra: extra, ); } - static GoRouter get router => Routers.authRouter; + static GoRouter init(BuildContext context, {String? initialLocation}) => + Routers.appRouter(context, initialLocation: initialLocation); +} + +extension ContextOnRouter on BuildContext { + GoRouter get router => GoRouter.of(this); } class Routers { - static GoRouter authRouter = GoRouter( - initialLocation: '/', - routes: [ - GoRoute( - path: '/', - builder: (context, state) { - return BlocListener( - listenWhen: (previous, current) => current is RSuccess, - listener: (_, state) { - if (state is RSuccess) { - switch (state.data) { - case AuthStateAuthenticated _: - debugPrint('User is authenticated'); - Routes.app.nav(); - break; - case AuthStateUnauthenticated _: - debugPrint('User is unauthenticated'); - Routes.auth.nav(); - break; - case _: - } - } - }, - child: const SplashPage(), - ); - }, + static GoRouter appRouter( + BuildContext context, { + String? initialLocation, + }) => + GoRouter( + initialLocation: initialLocation ?? + (context.read().isLoggedIn() + ? Routes.app.path + : Routes.auth.path), routes: [ - ShellRoute( - builder: (context, state, child) => child, - redirect: (context, state) { - if (context.read().isLoggedIn()) { - return Routes.app.path; - } - return null; - }, - routes: [ - GoRoute( - name: Routes.auth.name, - path: Routes.auth.path, - builder: (context, state) => const LoginPage(), - ), - GoRoute( - name: Routes.signup.name, - path: '${Routes.auth.path}${Routes.signup.path}', - builder: (context, state) => const SignUpPage(), - ), - ], - ), - ShellRoute( - builder: (context, state, child) => child, - redirect: (context, state) { - if (!context.read().isLoggedIn()) { - return Routes.auth.path; - } - return null; + GoRoute( + path: '/', + builder: (context, state) { + return BlocListener( + listenWhen: (previous, current) => current is RSuccess, + listener: (_, appState) { + if (appState is RSuccess) { + switch (appState.data) { + case AuthStateAuthenticated _: + debugPrint('User is authenticated: ${state.fullPath}'); + if (state.fullPath?.contains(Routes.app.path) ?? + false) { + // Already navigating to app, do nothing + return; + } + debugPrint('Navigating to app route'); + Routes.app.nav(context); + break; + case AuthStateUnauthenticated _: + debugPrint( + 'User is unauthenticated: ${state.fullPath}'); + if (state.fullPath?.contains(Routes.auth.path) ?? + false) { + // Already navigating to auth, do nothing + return; + } + debugPrint('Navigating to auth route'); + Routes.auth.nav(context); + break; + case _: + } + } + }, + child: const SplashPage(), + ); }, routes: [ - GoRoute( - name: Routes.app.name, - path: Routes.app.path, - builder: (context, state) => const HomePage(), + ShellRoute( + builder: (context, state, child) => child, + routes: [ + GoRoute( + name: Routes.auth.name, + path: Routes.auth.path, + redirect: (context, state) { + if (context.read().isLoggedIn()) { + return Routes.app.path; + } + return null; + }, + builder: (context, state) => const LoginPage(), + routes: [ + GoRoute( + name: Routes.signup.name, + path: Routes.signup.subPath, + builder: (context, state) => const SignUpPage(), + ), + ], + ), + ], ), - GoRoute( - name: Routes.placeholder.name, - path: "${Routes.app.path}${Routes.placeholder.path}", - builder: (context, state) => const Placeholder(), + ShellRoute( + builder: (context, state, child) => child, + routes: [ + GoRoute( + name: Routes.app.name, + path: Routes.app.path, + redirect: (context, state) { + if (!context.read().isLoggedIn()) { + return Routes.auth.path; + } + return null; + }, + builder: (context, state) => const HomePage(), + routes: [ + GoRoute( + name: Routes.placeholder.name, + path: Routes.placeholder.subPath, + builder: (context, state) => const Placeholder(), + ), + ], + ), + ], ), ], ), ], - ), - ], - ); + ); } diff --git a/app/lib/presentation/ui/pages/login/login_page.dart b/app/lib/presentation/ui/pages/login/login_page.dart index 6df6f7c..6ad41be 100644 --- a/app/lib/presentation/ui/pages/login/login_page.dart +++ b/app/lib/presentation/ui/pages/login/login_page.dart @@ -33,8 +33,7 @@ class LoginPage extends StatelessWidget { child: ElevatedButton( child: const Text('Login'), onPressed: () { - Routes.signup.nav(); - //_authCubit.login('Rootstrap', '12345678'); + _authCubit.login('Rootstrap', '12345678'); }, ), ), diff --git a/app/linux/flutter/generated_plugin_registrant.cc b/app/linux/flutter/generated_plugin_registrant.cc index e71a16d..1ea3346 100644 --- a/app/linux/flutter/generated_plugin_registrant.cc +++ b/app/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,10 @@ #include "generated_plugin_registrant.h" +#include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) gtk_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin"); + gtk_plugin_register_with_registrar(gtk_registrar); } diff --git a/app/linux/flutter/generated_plugins.cmake b/app/linux/flutter/generated_plugins.cmake index 2e1de87..2ee43a9 100644 --- a/app/linux/flutter/generated_plugins.cmake +++ b/app/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + gtk ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 8888675..5b422a4 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -54,6 +54,7 @@ dependencies: flutter_dotenv: ^5.2.1 flutter_web_plugins: sdk: flutter + app_links: ^6.4.1 dev_dependencies: bloc_test: ^9.0.2 diff --git a/modules/domain/lib/bloc/auth/auth_cubit.dart b/modules/domain/lib/bloc/auth/auth_cubit.dart index 00a1b89..fd83f16 100644 --- a/modules/domain/lib/bloc/auth/auth_cubit.dart +++ b/modules/domain/lib/bloc/auth/auth_cubit.dart @@ -31,8 +31,7 @@ class AuthCubit extends BaseCubit { isLogOut(); } - bool isLoggedIn() => - state is RSuccess && (state as RSuccess).data is AuthStateAuthenticated; + bool isLoggedIn() => _authService.isLoggedIn(); void isLogin() => isSuccess(AuthStateAuthenticated()); diff --git a/pubspec.yaml b/pubspec.yaml index 20ca790..b25738f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,6 +11,7 @@ environment: dependencies: flutter: sdk: flutter + app_links: ^6.4.1 dev_dependencies: flutter_test: From 24a3a958052ce2e6d53adbe2fc0916db5df658b9 Mon Sep 17 00:00:00 2001 From: Amaury Date: Mon, 17 Nov 2025 11:06:41 -0300 Subject: [PATCH 5/5] add deeplink support --- app/lib/presentation/navigation/routers.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/lib/presentation/navigation/routers.dart b/app/lib/presentation/navigation/routers.dart index 028a3fc..cd18b74 100644 --- a/app/lib/presentation/navigation/routers.dart +++ b/app/lib/presentation/navigation/routers.dart @@ -1,3 +1,4 @@ +import 'package:app/main/init.dart'; import 'package:app/presentation/ui/pages/home/home_page.dart'; import 'package:app/presentation/ui/pages/login/login_page.dart'; import 'package:app/presentation/ui/pages/sign_up/sign_up_page.dart'; @@ -42,7 +43,7 @@ class Routers { }) => GoRouter( initialLocation: initialLocation ?? - (context.read().isLoggedIn() + (getIt().isLoggedIn() ? Routes.app.path : Routes.auth.path), routes: [ @@ -56,7 +57,7 @@ class Routers { switch (appState.data) { case AuthStateAuthenticated _: debugPrint('User is authenticated: ${state.fullPath}'); - if (state.fullPath?.contains(Routes.app.path) ?? + if (state.fullPath?.startsWith(Routes.app.path) ?? false) { // Already navigating to app, do nothing return; @@ -67,7 +68,7 @@ class Routers { case AuthStateUnauthenticated _: debugPrint( 'User is unauthenticated: ${state.fullPath}'); - if (state.fullPath?.contains(Routes.auth.path) ?? + if (state.fullPath?.startsWith(Routes.auth.path) ?? false) { // Already navigating to auth, do nothing return; @@ -90,7 +91,7 @@ class Routers { name: Routes.auth.name, path: Routes.auth.path, redirect: (context, state) { - if (context.read().isLoggedIn()) { + if (getIt().isLoggedIn()) { return Routes.app.path; } return null; @@ -113,7 +114,7 @@ class Routers { name: Routes.app.name, path: Routes.app.path, redirect: (context, state) { - if (!context.read().isLoggedIn()) { + if (!getIt().isLoggedIn()) { return Routes.auth.path; } return null;