rework-onboarding (#7)

Onboarding completato, ora super rapido e top

Reviewed-on: http://catelliub.zapto.org:3000/brontomark/flux/pulls/7
Co-authored-by: Mark M2 Macbook <marco@catelli.it>
Co-committed-by: Mark M2 Macbook <marco@catelli.it>
This commit is contained in:
2026-04-22 11:06:02 +02:00
committed by brontomark
parent c5b5b76bd6
commit 90bd5ecacf
47 changed files with 1742 additions and 516 deletions

View File

@@ -1,67 +1,89 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flux/core/blocs/session/session_bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
// Importa il tuo SessionCubit e lo State
import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/data/core_repository.dart';
import 'package:flux/features/auth/ui/auth_screen.dart';
import 'package:flux/features/company/ui/create_company_screen.dart';
import 'package:flux/features/customers/models/customer_model.dart';
import 'package:flux/features/customers/ui/customer_detail_screen.dart';
import 'package:flux/features/home/ui/home_screen.dart';
import 'package:flux/features/master_data/products/ui/products_screen.dart';
import 'package:flux/features/master_data/store/ui/create_store_screen.dart';
import 'package:flux/features/onboarding/blocs/onboarding_cubit.dart';
import 'package:flux/features/onboarding/ui/onboarding_screen.dart';
import 'package:flux/features/services/models/service_model.dart';
import 'package:flux/features/services/ui/service_form_screen/service_form_screen.dart';
import 'package:get_it/get_it.dart';
import 'package:go_router/go_router.dart';
import 'dart:async';
class AppRouter {
// Funzione statica per creare il router
static GoRouter createRouter(SessionBloc sessionBloc) {
static GoRouter createRouter(SessionCubit sessionCubit) {
return GoRouter(
initialLocation: '/',
// Ascolta i cambiamenti del Bloc per scatenare il redirect
refreshListenable: _GoRouterRefreshStream(sessionBloc.stream),
// MAGIA 1: Il router "ascolta" ogni singolo respiro del SessionCubit
refreshListenable: GoRouterRefreshStream(sessionCubit.stream),
// MAGIA 2: Il Buttafuori Supremo
redirect: (context, state) {
final sessionState = sessionBloc.state;
final sessionState = sessionCubit.state;
final isGoingToLogin = state.matchedLocation == '/login';
final isGoingToOnboarding = state.matchedLocation == '/onboarding';
// Logica di redirezione basata sugli stati del SessionBloc
final bool isUnknown = sessionState.status == SessionStatus.unknown;
final bool isUnauthenticated =
sessionState.status == SessionStatus.unauthenticated;
final bool isNoCompany =
sessionState.status == SessionStatus.authenticatedNoCompany;
final bool isNoStore =
sessionState.status == SessionStatus.authenticatedNoStore;
final bool isReady = sessionState.status == SessionStatus.ready;
final String location = state.matchedLocation;
if (isUnknown) return null; // Aspetta che l'app si svegli
if (isUnauthenticated && location != '/login') return '/login';
if (isNoCompany && location != '/create-company') {
return '/create-company';
// Caso 1: L'app si sta ancora avviando.
// Restituiamo null per farlo rimanere sulla SplashScreen del main.dart
if (sessionState.status == SessionStatus.initial) {
return null;
}
if (isNoStore && location != '/create-store') return '/create-store';
// Caso 2: Utente NON loggato.
if (sessionState.status == SessionStatus.unauthenticated) {
// Se sta già andando al login, lascialo andare. Altrimenti, forzalo al login.
return isGoingToLogin ? null : '/login';
}
// Se sono loggato e sto cercando di andare alla login, vai in dashboard
if (isReady && location == '/login') return '/';
// Caso 3: Utente loggato MA manca un pezzo dell'azienda (Flusso Canalizzatore)
if (sessionState.status == SessionStatus.onboardingRequired) {
// Se sta già andando all'onboarding, ok. Altrimenti forzalo lì.
// Non può "scappare" digitando l'URL della dashboard!
return isGoingToOnboarding ? null : '/onboarding';
}
// Caso 4: Utente loggato e configurato (Tutto OK!)
if (sessionState.status == SessionStatus.authenticated) {
// Se per sbaglio cerca di tornare al login o all'onboarding,
// lo rimbalziamo alla home.
if (isGoingToLogin || isGoingToOnboarding) {
return '/';
}
// Per tutte le altre rotte (dashboard, clienti, anagrafiche), lascialo passare.
return null;
}
return null;
},
routes: [
GoRoute(path: '/', builder: (context, state) => const HomeScreen()),
GoRoute(
path: '/login',
//builder: (context, state) => const LoginScreen(),
builder: (context, state) => const AuthScreen(),
),
GoRoute(
path: '/create-company',
builder: (context, state) => const CreateCompanyScreen(),
path: '/onboarding',
builder: (context, state) => BlocProvider(
create: (context) => OnboardingCubit(
GetIt.I.get<SessionCubit>(),
GetIt.I.get<CoreRepository>(),
),
child: const OnboardingScreen(),
),
// Nota: All'interno di questa schermata useremo il PageView pilotato
// dall'OnboardingStep. Al router non interessa quale step è attivo,
// gli basta sapere che deve stare rinchiuso qui dentro!
),
GoRoute(
path: '/create-store',
builder: (context, state) => const CreateStoreScreen(),
path: '/',
builder: (context, state) => const HomeScreen(), // La tua home
),
GoRoute(
path: '/customer/:id',
@@ -96,11 +118,14 @@ class AppRouter {
}
}
// Classe di supporto per convertire lo Stream del Bloc in un Listenable per GoRouter
class _GoRouterRefreshStream extends ChangeNotifier {
_GoRouterRefreshStream(Stream<dynamic> stream) {
/// Utility fondamentale per GoRouter: trasforma lo Stream del Cubit
/// in un Listenable che GoRouter può ascoltare per forzare i redirect.
class GoRouterRefreshStream extends ChangeNotifier {
GoRouterRefreshStream(Stream<dynamic> stream) {
notifyListeners();
_subscription = stream.asBroadcastStream().listen((_) => notifyListeners());
_subscription = stream.asBroadcastStream().listen(
(dynamic _) => notifyListeners(),
);
}
late final StreamSubscription<dynamic> _subscription;