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';
|
|
|
|
|
import 'package:flux/core/blocs/session/session_cubit.dart';
|
|
|
|
|
import 'package:flux/core/data/core_repository.dart';
|
2026-04-29 11:40:17 +02:00
|
|
|
import 'package:flux/core/layout/app_shell.dart';
|
2026-04-30 10:25:52 +02:00
|
|
|
import 'package:flux/core/utils/extensions.dart';
|
2026-04-28 10:12:15 +02:00
|
|
|
import 'package:flux/core/widgets/set_password_screen.dart';
|
2026-04-09 18:17:48 +02:00
|
|
|
import 'package:flux/features/auth/ui/auth_screen.dart';
|
2026-04-26 10:15: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-29 11:40:17 +02:00
|
|
|
import 'package:flux/features/customers/ui/customer_mobile_upload_screen.dart';
|
|
|
|
|
import 'package:flux/features/customers/ui/customers_content.dart';
|
2026-04-13 10:00:07 +02:00
|
|
|
import 'package:flux/features/home/ui/home_screen.dart';
|
2026-04-29 11:40:17 +02:00
|
|
|
import 'package:flux/features/master_data/master_data_hub_content.dart';
|
2026-04-14 11:29:49 +02:00
|
|
|
import 'package:flux/features/master_data/products/ui/products_screen.dart';
|
2026-04-30 10:25:52 +02:00
|
|
|
import 'package:flux/features/master_data/providers/ui/providers_master_data_screen.dart';
|
|
|
|
|
import 'package:flux/features/master_data/staff/ui/staff_screen.dart';
|
|
|
|
|
import 'package:flux/features/master_data/store/ui/stores_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-05-01 10:11:44 +02:00
|
|
|
import 'package:flux/features/operations/blocs/operation_files_bloc.dart';
|
|
|
|
|
import 'package:flux/features/operations/models/operation_model.dart';
|
2026-05-02 12:19:04 +02:00
|
|
|
import 'package:flux/features/operations/ui/operation_form_screen.dart';
|
|
|
|
|
import 'package:flux/features/operations/ui/operation_mobile_upload_screen.dart';
|
2026-05-01 10:11:44 +02:00
|
|
|
import 'package:flux/features/operations/ui/operations_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';
|
|
|
|
|
|
2026-04-29 11:40:17 +02:00
|
|
|
// Nota: Dovrai creare questi placeholder o file per non avere errori di compilazione
|
|
|
|
|
// import 'package:flux/features/master_data/master_data_hub_screen.dart';
|
|
|
|
|
// import 'package:flux/features/master_data/staff/ui/staff_screen.dart';
|
|
|
|
|
// import 'package:flux/features/master_data/store/ui/stores_screen.dart';
|
|
|
|
|
|
2026-04-09 18:17:48 +02:00
|
|
|
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
|
|
|
refreshListenable: GoRouterRefreshStream(sessionCubit.stream),
|
|
|
|
|
redirect: (context, state) {
|
|
|
|
|
final sessionState = sessionCubit.state;
|
|
|
|
|
final isGoingToLogin = state.matchedLocation == '/login';
|
|
|
|
|
final isGoingToOnboarding = state.matchedLocation == '/onboarding';
|
2026-04-28 10:12:15 +02:00
|
|
|
final isGoingToSetPassword = state.matchedLocation == '/set-password';
|
2026-04-09 18:17:48 +02:00
|
|
|
|
2026-04-29 11:40:17 +02:00
|
|
|
if (sessionState.status == SessionStatus.initial) return null;
|
2026-04-09 18:17:48 +02:00
|
|
|
|
2026-04-22 11:06:02 +02:00
|
|
|
if (sessionState.status == SessionStatus.unauthenticated) {
|
2026-04-28 10:12:15 +02:00
|
|
|
if (isGoingToLogin || isGoingToSetPassword) return null;
|
|
|
|
|
return '/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
|
|
|
if (sessionState.status == SessionStatus.onboardingRequired) {
|
|
|
|
|
return isGoingToOnboarding ? null : '/onboarding';
|
|
|
|
|
}
|
2026-04-09 18:17:48 +02:00
|
|
|
|
2026-04-22 11:06:02 +02:00
|
|
|
if (sessionState.status == SessionStatus.authenticated) {
|
2026-04-29 11:40:17 +02:00
|
|
|
if (isGoingToLogin || isGoingToOnboarding) return '/';
|
|
|
|
|
return null;
|
2026-04-22 11:06:02 +02:00
|
|
|
}
|
2026-04-09 18:17:48 +02:00
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
},
|
|
|
|
|
routes: [
|
2026-04-29 11:40:17 +02:00
|
|
|
// --- ROTTE DI SERVIZIO (FUORI DALLA SHELL) ---
|
2026-04-09 18:17:48 +02:00
|
|
|
GoRoute(
|
|
|
|
|
path: '/login',
|
|
|
|
|
builder: (context, state) => const AuthScreen(),
|
|
|
|
|
),
|
2026-04-28 10:12:15 +02:00
|
|
|
GoRoute(
|
|
|
|
|
path: '/set-password',
|
|
|
|
|
builder: (context, state) => const SetPasswordScreen(),
|
|
|
|
|
),
|
2026-04-09 18:17:48 +02:00
|
|
|
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(),
|
|
|
|
|
),
|
2026-04-09 18:17:48 +02:00
|
|
|
),
|
2026-04-29 11:40:17 +02:00
|
|
|
|
|
|
|
|
// --- CORE APP (DENTRO LA SHELL CON NAVIGATION BAR/RAIL) ---
|
|
|
|
|
ShellRoute(
|
|
|
|
|
builder: (context, state, child) => AppShell(child: child),
|
|
|
|
|
routes: [
|
|
|
|
|
// 1. DASHBOARD
|
|
|
|
|
GoRoute(path: '/', builder: (context, state) => const HomeScreen()),
|
|
|
|
|
|
|
|
|
|
// 2. HUB ANAGRAFICHE E SOTTO-ROTTE
|
|
|
|
|
GoRoute(
|
|
|
|
|
path: '/master-data',
|
|
|
|
|
builder: (context, state) => const MasterDataHubScreen(),
|
|
|
|
|
routes: [
|
|
|
|
|
GoRoute(
|
|
|
|
|
path: 'products', // Diventa /master-data/products
|
|
|
|
|
builder: (context, state) => const ProductsScreen(),
|
|
|
|
|
),
|
|
|
|
|
GoRoute(
|
|
|
|
|
path: 'staff', // Diventa /master-data/staff
|
2026-04-30 10:25:52 +02:00
|
|
|
builder: (context, state) => const StaffScreen(),
|
2026-04-29 11:40:17 +02:00
|
|
|
),
|
|
|
|
|
GoRoute(
|
|
|
|
|
path: 'stores', // Diventa /master-data/stores
|
2026-04-30 10:25:52 +02:00
|
|
|
builder: (context, state) => const StoresScreen(),
|
2026-04-29 11:40:17 +02:00
|
|
|
),
|
|
|
|
|
GoRoute(
|
|
|
|
|
path: 'providers', // Diventa /master-data/providers
|
2026-04-30 10:25:52 +02:00
|
|
|
builder: (context, state) =>
|
|
|
|
|
const ProvidersMasterDataScreen(),
|
2026-04-29 11:40:17 +02:00
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
// 3. IMPOSTAZIONI
|
|
|
|
|
GoRoute(
|
|
|
|
|
path: '/settings',
|
|
|
|
|
builder: (context, state) => Scaffold(
|
2026-04-30 10:25:52 +02:00
|
|
|
appBar: AppBar(title: Text(context.l10n.commonSettings)),
|
2026-04-29 11:40:17 +02:00
|
|
|
body: Center(
|
|
|
|
|
child: ElevatedButton.icon(
|
|
|
|
|
onPressed: () => context.read<SessionCubit>().signOut(),
|
|
|
|
|
icon: const Icon(Icons.logout),
|
|
|
|
|
label: const Text("Esci da FLUX"),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2026-04-30 12:39:25 +02:00
|
|
|
GoRoute(
|
2026-05-01 09:51:42 +02:00
|
|
|
path: '/operations',
|
2026-05-01 10:11:44 +02:00
|
|
|
builder: (context, state) => const OperationsScreen(),
|
2026-04-30 12:39:25 +02:00
|
|
|
),
|
|
|
|
|
GoRoute(
|
|
|
|
|
path: '/customers',
|
|
|
|
|
builder: (context, state) =>
|
|
|
|
|
const CustomersContent(), // O come si chiama il tuo widget della lista!
|
|
|
|
|
),
|
2026-04-29 11:40:17 +02:00
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
// --- DETTAGLI E OPERATIVITÀ (FUORI DALLA SHELL - TUTTO SCHERMO) ---
|
2026-04-11 12:40:03 +02:00
|
|
|
GoRoute(
|
|
|
|
|
path: '/customer/:id',
|
|
|
|
|
builder: (context, state) {
|
|
|
|
|
final customer = state.extra as CustomerModel;
|
2026-04-26 10:15:34 +02:00
|
|
|
return BlocProvider(
|
|
|
|
|
create: (context) => CustomerFilesBloc(customer.id!),
|
|
|
|
|
child: CustomerDetailScreen(customer: customer),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
GoRoute(
|
|
|
|
|
path: '/customer/:id/upload',
|
|
|
|
|
builder: (context, state) {
|
|
|
|
|
final customerId = state.pathParameters['id']!;
|
|
|
|
|
final customerName = state.uri.queryParameters['name'] ?? 'Cliente';
|
|
|
|
|
return BlocProvider(
|
|
|
|
|
create: (context) => CustomerFilesBloc(customerId),
|
|
|
|
|
child: CustomerMobileUploadScreen(
|
|
|
|
|
customerId: customerId,
|
|
|
|
|
customerName: customerName,
|
|
|
|
|
),
|
|
|
|
|
);
|
2026-04-11 12:40:03 +02:00
|
|
|
},
|
|
|
|
|
),
|
2026-04-16 11:50:29 +02:00
|
|
|
GoRoute(
|
2026-05-01 09:51:42 +02:00
|
|
|
path: '/operation-form',
|
|
|
|
|
name: 'operation-form',
|
2026-04-16 11:50:29 +02:00
|
|
|
builder: (context, state) {
|
2026-05-01 10:11:44 +02:00
|
|
|
final existingOperation = state.extra as OperationModel?;
|
|
|
|
|
final operationId = state.uri.queryParameters['operationId'];
|
2026-04-26 10:15:34 +02:00
|
|
|
return BlocProvider(
|
2026-05-01 10:11:44 +02:00
|
|
|
create: (context) => OperationFilesBloc(
|
|
|
|
|
operationId: operationId ?? existingOperation?.id,
|
|
|
|
|
),
|
|
|
|
|
child: OperationFormScreen(
|
|
|
|
|
operationId: operationId ?? existingOperation?.id,
|
|
|
|
|
existingOperation: existingOperation,
|
2026-04-26 10:15:34 +02:00
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
GoRoute(
|
2026-05-01 09:51:42 +02:00
|
|
|
path: '/operation/:id/upload',
|
2026-04-26 10:15:34 +02:00
|
|
|
builder: (context, state) {
|
2026-05-01 10:11:44 +02:00
|
|
|
final operationId = state.pathParameters['id']!;
|
|
|
|
|
final operationName =
|
|
|
|
|
state.uri.queryParameters['name'] ?? 'Pratica';
|
2026-04-26 10:15:34 +02:00
|
|
|
return BlocProvider(
|
2026-05-01 10:11:44 +02:00
|
|
|
create: (context) => OperationFilesBloc(operationId: operationId),
|
|
|
|
|
child: OperationMobileUploadScreen(
|
|
|
|
|
operationId: operationId,
|
|
|
|
|
operationName: operationName,
|
2026-04-26 10:15:34 +02:00
|
|
|
),
|
2026-04-20 16:52:20 +02:00
|
|
|
);
|
2026-04-16 11:50:29 +02:00
|
|
|
},
|
|
|
|
|
),
|
2026-04-09 18:17:48 +02:00
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-22 11:06:02 +02:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|