feat-add-files-from-qr (#8)

Reviewed-on: http://catelliub.zapto.org:3000/brontomark/flux/pulls/8
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-26 10:15:34 +02:00
committed by brontomark
parent 90bd5ecacf
commit 1c2bcf9df7
46 changed files with 2376 additions and 327 deletions

View File

@@ -12,6 +12,7 @@ import 'package:flux/features/services/models/service_file_model.dart';
import 'package:flux/features/services/models/service_model.dart';
import 'package:get_it/get_it.dart';
import 'package:collection/collection.dart';
import 'package:permission_handler/permission_handler.dart';
part 'services_state.dart';
class ServicesCubit extends Cubit<ServicesState> {
@@ -202,19 +203,31 @@ class ServicesCubit extends Cubit<ServicesState> {
// --- PERSISTENZA ---
Future<void> saveCurrentService({required bool isBozza}) async {
Future<void> saveCurrentService({
required bool isBozza,
bool shouldPop = true,
List<ServiceFileModel>? files,
}) async {
if (state.currentService == null) return;
emit(state.copyWith(status: ServicesStatus.saving, errorMessage: null));
try {
// 1. Aggiorniamo il flag bozza in base a quale pulsante ha premuto l'utente
final serviceToSave = state.currentService!.copyWith(isBozza: isBozza);
final serviceToSave = state.currentService!.copyWith(
isBozza: isBozza,
files: files,
);
// 2. Salvataggio corazzato
await _repository.saveFullService(serviceToSave);
final updatedService = await _repository.saveFullService(serviceToSave);
// 3. Reset e ricaricamento
emit(state.copyWith(status: ServicesStatus.saved, currentService: null));
emit(
state.copyWith(
status: shouldPop ? ServicesStatus.saved : ServicesStatus.savedNoPop,
currentService: shouldPop ? null : updatedService,
),
);
await loadServices(refresh: true);
} catch (e) {
emit(
@@ -235,7 +248,7 @@ class ServicesCubit extends Cubit<ServicesState> {
serviceId: state.currentService?.id ?? '',
name: file.name.fileNameWithoutExtension(),
extension: file.name.fileExtension(),
url: '',
storagePath: '',
fileSize: file.size,
localBytes: file.bytes,
createdAt: DateTime.now(),
@@ -273,49 +286,62 @@ class ServicesCubit extends Cubit<ServicesState> {
);
}
void saveAndCopyFileToCustomer(ServiceFileModel file) async {
void saveAndCopyFileToCustomer(List<ServiceFileModel> selectedFiles) async {
final currentService = state.currentService;
// 1. Check di sicurezza: se non c'è il cliente, non sappiamo dove copiare
if (currentService == null || currentService.customerId == null) {
// Magari mostra un errore: non posso copiare al cliente se non c'è un cliente!
emit(
state.copyWith(
status: ServicesStatus.failure,
errorMessage:
"Impossibile copiare: nessun cliente associato alla pratica.",
),
);
return;
}
emit(state.copyWith(status: ServicesStatus.loading));
try {
// 1. Salviamo la pratica (Bozza o definitiva che sia)
// Questo assicura che il file sia stato caricato su Storage e censito su DB
await saveCurrentService(isBozza: currentService.isBozza);
// 2. SALVATAGGIO CORAZZATO
// Chiamiamo il repo e otteniamo la pratica con TUTTI i file ora dotati di ID e storagePath
final updatedService = await _repository.saveFullService(currentService);
// 2. Recuperiamo il file "aggiornato"
// Dopo il saveCurrentService, il file che prima era "locale" ora ha un URL.
// Lo cerchiamo nella lista aggiornata per nome o estensione.
final savedFile = state.currentService!.files.firstWhere(
(f) => f.name == file.name && f.extension == file.extension,
orElse: () => file,
);
// 3. COPIA RELAZIONALE
// Per ogni file che l'utente ha selezionato nella UI, cerchiamo la sua versione
// "ufficiale" (quella con lo storagePath) nel modello appena tornato dal DB.
for (var selectedFile in selectedFiles) {
// Cerchiamo il match nel modello aggiornato
final persistedFile = updatedService.files.firstWhere(
(f) =>
f.name == selectedFile.name &&
f.extension == selectedFile.extension,
orElse: () => throw Exception(
"File ${selectedFile.name} non trovato dopo il salvataggio.",
),
);
if (savedFile.url.isEmpty) {
throw Exception(
"Errore: URL del file non trovato dopo il salvataggio.",
// Creiamo il link nel database del cliente
await _repository.copyFileToCustomer(
file: persistedFile,
customerId: currentService.customerId!,
);
}
// 3. Chiamiamo il repository per la copia fisica nel database del cliente
// Passiamo l'URL del file e l'ID del cliente
await _repository.copyFileToCustomer(
file: savedFile,
customerId: currentService.customerId!,
// 4. AGGIORNAMENTO STATO
// Aggiorniamo il Cubit con il servizio salvato così la UI mostra i file come "Remoti"
emit(
state.copyWith(
status: ServicesStatus.success,
currentService: updatedService,
),
);
// 4. Feedback all'utente
// Potresti emettere un successo o mostrare un toast
emit(state.copyWith(status: ServicesStatus.success));
} catch (e) {
emit(
state.copyWith(
status: ServicesStatus.failure,
errorMessage: "Errore durante la copia del file: $e",
errorMessage: "Errore durante il salvataggio e copia: $e",
),
);
}