diff --git a/lib/features/attachments/blocs/attachments_bloc.dart b/lib/features/attachments/blocs/attachments_bloc.dart index d49e099..fa3ea88 100644 --- a/lib/features/attachments/blocs/attachments_bloc.dart +++ b/lib/features/attachments/blocs/attachments_bloc.dart @@ -1,4 +1,6 @@ import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; import 'package:file_picker/file_picker.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:equatable/equatable.dart'; @@ -14,7 +16,6 @@ part 'attachments_state.dart'; class AttachmentsBloc extends Bloc { final _repository = GetIt.I.get(); - final String? companyId = GetIt.I.get().state.company?.id; AttachmentsBloc({String? parentId, required AttachmentParentType parentType}) : super( @@ -36,8 +37,8 @@ class AttachmentsBloc extends Bloc { on(_onSelectAllAttachments); on(_onClearAttachmentSelection); - // Se il BLoC nasce già con un ID, carichiamo i file - if (parentId != null && companyId != null) { + final currentCompanyId = GetIt.I.get().state.company?.id; + if (parentId != null && currentCompanyId != null) { add(LoadAttachmentsEvent(parentId: parentId)); } } @@ -46,6 +47,8 @@ class AttachmentsBloc extends Bloc { ParentEntitySavedEvent event, Emitter emit, ) async { + final companyId = GetIt.I.get().state.company?.id; + emit( state.copyWith( parentId: event.newParentId, @@ -117,14 +120,30 @@ class AttachmentsBloc extends Bloc { Emitter emit, ) async { final currentId = state.parentId; + final currentCompanyId = GetIt.I.get().state.company?.id; - // BIVIO 1: PRATICA NUOVA (Salvataggio locale) + if (currentCompanyId == null) { + emit( + state.copyWith( + status: AttachmentsStatus.failure, + error: "Company ID non trovato nella sessione", + ), + ); + return; + } + + // BIVIO 1: PRATICA NUOVA (Salvataggio locale in memoria) if (currentId == null) { final newLocalFiles = event.files.map((file) { - // Assegniamo i campi dinamicamente in base al parentType! + // FISCHIO SALVAVITA PER DESKTOP: se i bytes sono nulli, li leggiamo dal path fisico! + Uint8List? rawBytes = file.bytes; + if (rawBytes == null && file.path != null) { + rawBytes = File(file.path!).readAsBytesSync(); + } + return AttachmentModel( id: null, - companyId: companyId!, + companyId: currentCompanyId, operationId: state.parentType == AttachmentParentType.operation ? '' : null, @@ -136,7 +155,7 @@ class AttachmentsBloc extends Bloc { extension: file.name.fileExtension(), storagePath: '', fileSize: file.size, - localBytes: file.bytes, + localBytes: rawBytes, // Ora i byte ci sono al 100% anche su Mac! ); }).toList(); @@ -157,7 +176,7 @@ class AttachmentsBloc extends Bloc { parentId: currentId, parentType: state.parentType, pickedFile: file, - companyId: companyId!, + companyId: currentCompanyId, bucket: _getBucketForParentType, ); }).toList(); diff --git a/lib/features/notes/data/notes_repository.dart b/lib/features/notes/data/notes_repository.dart index 87bab1a..6b1ffaf 100644 --- a/lib/features/notes/data/notes_repository.dart +++ b/lib/features/notes/data/notes_repository.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/enums_and_consts/consts.dart'; import 'package:flux/features/notes/models/note_model.dart'; @@ -130,13 +131,26 @@ class NotesRepository { await _supabase.from('note_collaborators').delete().eq('note_id', noteId); // 3. RE-INSERIMENTO DELLA LISTA AGGIORNATA - // Se ci sono collaboratori da inserire, li prepariamo in blocco (Bulk Insert) if (note.collaboratorIds.isNotEmpty) { final collaboratorsToInsert = note.collaboratorIds - .map((staffId) => {'note_id': noteId, 'staff_id': staffId}) + .map( + (staffId) => { + 'note_id': noteId, + 'staff_id': staffId, + 'company_id': note.companyId, // Aggiunto questo! + }, + ) .toList(); - await _supabase.from('note_collaborators').insert(collaboratorsToInsert); + // Consiglio da pro: avvolgi l'insert in un try-catch per stampare l'errore esatto a console + try { + await _supabase + .from(Tables.noteCollaborators) + .insert(collaboratorsToInsert); + } catch (e) { + debugPrint('Errore inserimento collaboratori: $e'); + throw Exception('Impossibile aggiungere i collaboratori alla nota.'); + } } // Restituiamo l'id alla UI (fondamentale per la nostra logica Ninja di creazione) diff --git a/lib/features/notes/ui/notes_form_screen.dart b/lib/features/notes/ui/notes_form_screen.dart index 21746bd..9f86073 100644 --- a/lib/features/notes/ui/notes_form_screen.dart +++ b/lib/features/notes/ui/notes_form_screen.dart @@ -134,73 +134,76 @@ class _NoteFormScreenState extends State { builder: (context) { return StatefulBuilder( builder: (context, setModalState) { - return Column( - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: Text( - 'Seleziona Collaboratori', - style: Theme.of(context).textTheme.titleLarge, + return Material( + color: Colors.transparent, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + 'Seleziona Collaboratori', + style: Theme.of(context).textTheme.titleLarge, + ), ), - ), - Expanded( - child: ListView.builder( - itemCount: allStaff.length, - itemBuilder: (context, index) { - final staff = allStaff[index]; + Expanded( + child: ListView.builder( + itemCount: allStaff.length, + itemBuilder: (context, index) { + final staff = allStaff[index]; - // Capiamo se questo membro dello staff è il creatore - final isCreator = staff.id == creatorId; - // È spuntato se è il creatore OPPURE se è nella lista dei collaboratori - final isSelected = - isCreator || _selectedStaffIds.contains(staff.id); + // Capiamo se questo membro dello staff è il creatore + final isCreator = staff.id == creatorId; + // È spuntato se è il creatore OPPURE se è nella lista dei collaboratori + final isSelected = + isCreator || _selectedStaffIds.contains(staff.id); - return CheckboxListTile( - title: RichText( - text: TextSpan( - style: Theme.of(context).textTheme.bodyLarge, - children: [ - TextSpan(text: staff.name), - if (isCreator) - const TextSpan( - text: ' (Proprietario)', - style: TextStyle( - color: Colors.grey, - fontStyle: FontStyle.italic, - fontSize: 12, + return CheckboxListTile( + title: RichText( + text: TextSpan( + style: Theme.of(context).textTheme.bodyLarge, + children: [ + TextSpan(text: staff.name), + if (isCreator) + const TextSpan( + text: ' (Proprietario)', + style: TextStyle( + color: Colors.grey, + fontStyle: FontStyle.italic, + fontSize: 12, + ), ), - ), - ], + ], + ), ), - ), - value: isSelected, - activeColor: Theme.of(context).colorScheme.primary, - // IL TRUCCO NINJA: se è il creatore, passiamo null per disabilitare la spunta! - onChanged: isCreator - ? null - : (bool? value) { - setModalState(() { - if (value == true) { - _selectedStaffIds.add(staff.id!); - } else { - _selectedStaffIds.remove(staff.id!); - } - }); - setState(() {}); - _triggerAutoSave(); - }, - ); - }, + value: isSelected, + activeColor: Theme.of(context).colorScheme.primary, + // IL TRUCCO NINJA: se è il creatore, passiamo null per disabilitare la spunta! + onChanged: isCreator + ? null + : (bool? value) { + setModalState(() { + if (value == true) { + _selectedStaffIds.add(staff.id!); + } else { + _selectedStaffIds.remove(staff.id!); + } + }); + setState(() {}); + _triggerAutoSave(); + }, + ); + }, + ), ), - ), - Padding( - padding: const EdgeInsets.all(16.0), - child: FilledButton( - onPressed: () => Navigator.pop(context), - child: const Text('Fatto'), + Padding( + padding: const EdgeInsets.all(16.0), + child: FilledButton( + onPressed: () => Navigator.pop(context), + child: const Text('Fatto'), + ), ), - ), - ], + ], + ), ); }, ); @@ -403,24 +406,27 @@ class _NoteFormScreenState extends State { const SizedBox(height: 12), // --- CONDIVISIONE --- - SwitchListTile( - title: const Text( - 'Condividi con tutti', - style: TextStyle( - color: Colors.black87, - fontWeight: FontWeight.w500, + Material( + color: Colors.transparent, + child: SwitchListTile( + title: const Text( + 'Condividi con tutti', + style: TextStyle( + color: Colors.black87, + fontWeight: FontWeight.w500, + ), ), + value: _isSharedAll, + activeThumbColor: Colors.black87, + contentPadding: EdgeInsets.zero, + onChanged: (val) { + setState(() { + _isSharedAll = val; + if (val) _selectedStaffIds.clear(); + }); + _triggerAutoSave(); + }, ), - value: _isSharedAll, - activeThumbColor: Colors.black87, - contentPadding: EdgeInsets.zero, - onChanged: (val) { - setState(() { - _isSharedAll = val; - if (val) _selectedStaffIds.clear(); - }); - _triggerAutoSave(); - }, ), if (!_isSharedAll) ...[ diff --git a/macos/Runner/DebugProfile.entitlements b/macos/Runner/DebugProfile.entitlements index dea5605..b2ed8a5 100644 --- a/macos/Runner/DebugProfile.entitlements +++ b/macos/Runner/DebugProfile.entitlements @@ -2,30 +2,23 @@ - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - - com.apple.security.network.client - - com.apple.security.files.user-selected.read-write + com.apple.security.app-sandbox - - com.apple.security.files.downloads.read-write + com.apple.security.cs.allow-jit + + com.apple.security.network.server - com.apple.security.network.client - com.apple.security.device.camera - - - com.apple.security.device.audio-input - - com.apple.security.print - com.apple.security.files.downloads.read-write + com.apple.security.device.camera + + com.apple.security.device.audio-input + + com.apple.security.print + + com.apple.security.files.user-selected.read-write + + com.apple.security.files.downloads.read-write - - + \ No newline at end of file diff --git a/macos/Runner/Release.entitlements b/macos/Runner/Release.entitlements index bcc66f7..118fc00 100644 --- a/macos/Runner/Release.entitlements +++ b/macos/Runner/Release.entitlements @@ -2,27 +2,19 @@ - com.apple.security.app-sandbox - - com.apple.security.network.client - + com.apple.security.app-sandbox + com.apple.security.cs.allow-jit - - com.apple.security.files.downloads.read-write + com.apple.security.network.client com.apple.security.device.camera - com.apple.security.device.audio-input - com.apple.security.files.user-selected.read-write com.apple.security.print - com.apple.security.files.downloads.read-write - - - + \ No newline at end of file