2026-04-22 11:06:02 +02:00
|
|
|
import 'dart:async';
|
|
|
|
|
|
2026-04-09 18:17:48 +02:00
|
|
|
import 'package:flutter/material.dart';
|
2026-04-22 11:06:02 +02:00
|
|
|
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';
|
2026-04-26 10:13:58 +02:00
|
|
|
import 'package:flux/features/customers/ui/customer_mobile_upload_screen.dart';
|
2026-04-09 18:17:48 +02:00
|
|
|
import 'package:flux/features/auth/ui/auth_screen.dart';
|
2026-04-23 11:20:34 +02:00
|
|
|
import 'package:flux/features/customers/blocs/customer_files_bloc.dart';
|
2026-04-11 12:40:03 +02:00
|
|
|
import 'package:flux/features/customers/models/customer_model.dart';
|
|
|
|
|
import 'package:flux/features/customers/ui/customer_detail_screen.dart';
|
2026-04-13 10:00:07 +02:00
|
|
|
import 'package:flux/features/home/ui/home_screen.dart';
|
2026-04-14 11:29:49 +02:00
|
|
|
import 'package:flux/features/master_data/products/ui/products_screen.dart';
|
2026-04-22 11:06:02 +02:00
|
|
|
import 'package:flux/features/onboarding/blocs/onboarding_cubit.dart';
|
|
|
|
|
import 'package:flux/features/onboarding/ui/onboarding_screen.dart';
|
2026-04-24 12:39:22 +02:00
|
|
|
import 'package:flux/features/services/blocs/service_files_bloc.dart';
|
2026-04-16 11:50:29 +02:00
|
|
|
import 'package:flux/features/services/models/service_model.dart';
|
2026-04-20 16:52:20 +02:00
|
|
|
import 'package:flux/features/services/ui/service_form_screen/service_form_screen.dart';
|
2026-04-24 12:39:22 +02:00
|
|
|
import 'package:flux/features/services/ui/service_form_screen/service_mobile_upload_screen.dart';
|
2026-04-22 11:06:02 +02:00
|
|
|
import 'package:get_it/get_it.dart';
|
2026-04-09 18:17:48 +02:00
|
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
|
|
|
|
|
|
class AppRouter {
|
2026-04-22 11:06:02 +02:00
|
|
|
static GoRouter createRouter(SessionCubit sessionCubit) {
|
2026-04-09 18:17:48 +02:00
|
|
|
return GoRouter(
|
|
|
|
|
initialLocation: '/',
|
2026-04-22 11:06:02 +02:00
|
|
|
// MAGIA 1: Il router "ascolta" ogni singolo respiro del SessionCubit
|
|
|
|
|
refreshListenable: GoRouterRefreshStream(sessionCubit.stream),
|
2026-04-09 18:17:48 +02:00
|
|
|
|
2026-04-22 11:06:02 +02:00
|
|
|
// MAGIA 2: Il Buttafuori Supremo
|
|
|
|
|
redirect: (context, state) {
|
|
|
|
|
final sessionState = sessionCubit.state;
|
|
|
|
|
final isGoingToLogin = state.matchedLocation == '/login';
|
|
|
|
|
final isGoingToOnboarding = state.matchedLocation == '/onboarding';
|
2026-04-09 18:17:48 +02:00
|
|
|
|
2026-04-22 11:06:02 +02:00
|
|
|
// 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;
|
|
|
|
|
}
|
2026-04-09 18:17:48 +02:00
|
|
|
|
2026-04-22 11:06:02 +02:00
|
|
|
// 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';
|
2026-04-09 19:25:32 +02:00
|
|
|
}
|
2026-04-09 18:17:48 +02:00
|
|
|
|
2026-04-22 11:06:02 +02:00
|
|
|
// 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';
|
|
|
|
|
}
|
2026-04-09 18:17:48 +02:00
|
|
|
|
2026-04-22 11:06:02 +02:00
|
|
|
// 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;
|
|
|
|
|
}
|
2026-04-09 18:17:48 +02:00
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
},
|
|
|
|
|
routes: [
|
|
|
|
|
GoRoute(
|
|
|
|
|
path: '/login',
|
2026-04-22 11:06:02 +02:00
|
|
|
//builder: (context, state) => const LoginScreen(),
|
2026-04-09 18:17:48 +02:00
|
|
|
builder: (context, state) => const AuthScreen(),
|
|
|
|
|
),
|
|
|
|
|
GoRoute(
|
2026-04-22 11:06:02 +02:00
|
|
|
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!
|
2026-04-09 18:17:48 +02:00
|
|
|
),
|
|
|
|
|
GoRoute(
|
2026-04-22 11:06:02 +02:00
|
|
|
path: '/',
|
|
|
|
|
builder: (context, state) => const HomeScreen(), // La tua home
|
2026-04-09 18:17:48 +02:00
|
|
|
),
|
2026-04-11 12:40:03 +02:00
|
|
|
GoRoute(
|
|
|
|
|
path: '/customer/:id',
|
|
|
|
|
builder: (context, state) {
|
|
|
|
|
// Recuperiamo l'oggetto customer passato tramite extra
|
|
|
|
|
final customer = state.extra as CustomerModel;
|
2026-04-23 11:20:34 +02:00
|
|
|
return BlocProvider(
|
|
|
|
|
create: (context) => CustomerFilesBloc(customer.id!),
|
|
|
|
|
child: CustomerDetailScreen(customer: customer),
|
|
|
|
|
);
|
2026-04-11 12:40:03 +02:00
|
|
|
},
|
|
|
|
|
),
|
2026-04-24 12:39:22 +02:00
|
|
|
GoRoute(
|
|
|
|
|
path: '/customer/:id/upload',
|
|
|
|
|
builder: (context, state) {
|
|
|
|
|
final customerId = state.pathParameters['id']!;
|
|
|
|
|
// Recuperiamo il nome dalle query se vogliamo mostrarlo nel titolo,
|
|
|
|
|
// oppure lo caricherà il bloc.
|
|
|
|
|
final customerName = state.uri.queryParameters['name'] ?? 'Cliente';
|
2026-04-23 11:20:34 +02:00
|
|
|
|
2026-04-24 12:39:22 +02:00
|
|
|
return BlocProvider(
|
|
|
|
|
create: (context) => CustomerFilesBloc(customerId),
|
2026-04-26 10:13:58 +02:00
|
|
|
child: CustomerMobileUploadScreen(
|
2026-04-24 12:39:22 +02:00
|
|
|
customerId: customerId,
|
|
|
|
|
customerName: customerName,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
2026-04-12 21:32:20 +02:00
|
|
|
GoRoute(
|
|
|
|
|
path: '/products',
|
|
|
|
|
name: 'products',
|
|
|
|
|
builder: (context, state) => const ProductsScreen(),
|
|
|
|
|
),
|
2026-04-16 11:50:29 +02:00
|
|
|
GoRoute(
|
|
|
|
|
path: '/service-form',
|
|
|
|
|
name: 'service-form',
|
|
|
|
|
builder: (context, state) {
|
2026-04-20 16:52:20 +02:00
|
|
|
// Recuperiamo l'oggetto se passato tramite 'extra'
|
|
|
|
|
final existingService = state.extra as ServiceModel?;
|
|
|
|
|
// Recuperiamo l'ID se presente nell'URL
|
|
|
|
|
final serviceId = state.uri.queryParameters['serviceId'];
|
|
|
|
|
|
2026-04-24 14:20:31 +02:00
|
|
|
return BlocProvider(
|
|
|
|
|
create: (context) =>
|
|
|
|
|
ServiceFilesBloc(serviceId: serviceId ?? existingService?.id),
|
|
|
|
|
child: ServiceFormScreen(
|
|
|
|
|
serviceId: serviceId ?? existingService?.id,
|
|
|
|
|
existingService: existingService,
|
|
|
|
|
),
|
2026-04-20 16:52:20 +02:00
|
|
|
);
|
2026-04-16 11:50:29 +02:00
|
|
|
},
|
|
|
|
|
),
|
2026-04-24 12:39:22 +02:00
|
|
|
GoRoute(
|
|
|
|
|
path: '/service/:id/upload',
|
|
|
|
|
builder: (context, state) {
|
|
|
|
|
final serviceId = state.pathParameters['id']!;
|
|
|
|
|
final serviceName = state.uri.queryParameters['name'] ?? 'Pratica';
|
|
|
|
|
|
|
|
|
|
return BlocProvider(
|
|
|
|
|
// Inizializziamo il bloc col serviceId corretto!
|
|
|
|
|
create: (context) => ServiceFilesBloc(serviceId: serviceId),
|
|
|
|
|
child: ServiceMobileUploadScreen(
|
|
|
|
|
serviceId: serviceId,
|
|
|
|
|
serviceName: serviceName,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
2026-04-09 18:17:48 +02:00
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-22 11:06:02 +02:00
|
|
|
/// 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) {
|
2026-04-09 18:17:48 +02:00
|
|
|
notifyListeners();
|
2026-04-22 11:06:02 +02:00
|
|
|
_subscription = stream.asBroadcastStream().listen(
|
|
|
|
|
(dynamic _) => notifyListeners(),
|
|
|
|
|
);
|
2026-04-09 18:17:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
late final StreamSubscription<dynamic> _subscription;
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
void dispose() {
|
|
|
|
|
_subscription.cancel();
|
|
|
|
|
super.dispose();
|
|
|
|
|
}
|
|
|
|
|
}
|