This commit is contained in:
2026-05-27 16:00:50 +02:00
parent f6ecb33729
commit b6e5f9acbe
8 changed files with 232 additions and 134 deletions

View File

@@ -3,19 +3,53 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/features/tasks/blocs/task_form_cubit.dart';
import 'package:go_router/go_router.dart';
class TaskFormScreen extends StatelessWidget {
class TaskFormScreen extends StatefulWidget {
const TaskFormScreen({super.key});
@override
State<TaskFormScreen> createState() => _TaskFormScreenState();
}
class _TaskFormScreenState extends State<TaskFormScreen> {
late final TextEditingController _titleController;
late final TextEditingController _descController;
@override
void initState() {
super.initState();
// Leggiamo lo stato iniziale dal Cubit (che ha già i dati del task esistente)
final initialState = context.read<TaskFormCubit>().state;
_titleController = TextEditingController(text: initialState.title);
_descController = TextEditingController(text: initialState.description);
}
@override
void dispose() {
_titleController.dispose();
_descController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocConsumer<TaskFormCubit, TaskFormState>(
listenWhen: (previous, current) => previous.status != current.status,
listener: (context, state) {
// GESTIONE DEEP LINK: Se eravamo in caricamento e ora siamo pronti, popoliamo i controller!
if (state.status == TaskFormStatus.initial) {
if (_titleController.text != state.title) {
_titleController.text = state.title;
}
if (_descController.text != state.description) {
_descController.text = state.description;
}
}
if (state.status == TaskFormStatus.success) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Task salvato con successo! 🎉')),
);
context.pop(); // Usciamo dalla pagina
context.pop();
} else if (state.status == TaskFormStatus.failure) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
@@ -33,7 +67,6 @@ class TaskFormScreen extends StatelessWidget {
appBar: AppBar(
title: Text(isEditing ? 'Modifica Task' : 'Nuovo Task'),
actions: [
// Tasto Salva (abilitato solo se il form è valido)
if (state.status == TaskFormStatus.submitting)
const Padding(
padding: EdgeInsets.all(16.0),
@@ -46,81 +79,84 @@ class TaskFormScreen extends StatelessWidget {
else
TextButton.icon(
onPressed: state.isFormValid
? () =>
cubit.saveTask(
currentUserId: 'TODO_USER_ID',
) // Passa l'id utente loggato dal SessionCubit
? () => cubit.saveTask(currentUserId: 'TODO_USER_ID')
: null,
icon: const Icon(Icons.save),
label: const Text('Salva'),
style: TextButton.styleFrom(
foregroundColor: Colors.orange, // Il tuo colore primario
foregroundColor: Colors.orange,
disabledForegroundColor: Colors.grey,
),
),
],
),
body: LayoutBuilder(
builder: (context, constraints) {
final isWideScreen = constraints.maxWidth > 800;
body: state.status == TaskFormStatus.loading
// Se sta scaricando i dati dal Deep Link, mostriamo un bel loader centrato
? const Center(child: CircularProgressIndicator())
: LayoutBuilder(
builder: (context, constraints) {
final isWideScreen = constraints.maxWidth > 800;
if (isWideScreen) {
// --- VISTA DESKTOP / TABLET LARGHI (2 Colonne) ---
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 6,
child: SingleChildScrollView(
padding: const EdgeInsets.all(24.0),
child: _buildFormFields(context, state, cubit),
),
),
VerticalDivider(color: Theme.of(context).dividerColor),
Expanded(
flex: 4,
child: _buildStaffSelectorInline(context, state, cubit),
),
],
);
}
if (isWideScreen) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 6,
child: SingleChildScrollView(
padding: const EdgeInsets.all(24.0),
child: _buildFormFields(context, state, cubit),
),
),
VerticalDivider(
color: Theme.of(context).dividerColor,
),
Expanded(
flex: 4,
child: _buildStaffSelectorInline(
context,
state,
cubit,
),
),
],
);
}
// --- VISTA MOBILE (1 Colonna + BottomSheet) ---
return SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildFormFields(context, state, cubit),
const SizedBox(height: 30),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
return SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildFormFields(context, state, cubit),
const SizedBox(height: 30),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
onPressed: () =>
_showStaffBottomSheet(context, cubit),
icon: const Icon(Icons.group_add),
label: Text(
state.selectedStaffIds.isEmpty
? 'Assegna Staff'
: 'Assegnato a ${state.selectedStaffIds.length} persone',
),
),
],
),
onPressed: () => _showStaffBottomSheet(context, cubit),
icon: const Icon(Icons.group_add),
label: Text(
state.selectedStaffIds.isEmpty
? 'Assegna Staff'
: 'Assegnato a ${state.selectedStaffIds.length} persone',
),
),
],
);
},
),
);
},
),
);
},
);
}
// =========================================================================
// 1. I CAMPI DEL FORM PRINCIPALE
// =========================================================================
// --- I CAMPI DEL FORM (Aggiornati con i Controller) ---
Widget _buildFormFields(
BuildContext context,
TaskFormState state,
@@ -129,7 +165,6 @@ class TaskFormScreen extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// --- SCOPE TOGGLE ---
Card(
elevation: 0,
shape: RoundedRectangleBorder(
@@ -153,9 +188,9 @@ class TaskFormScreen extends StatelessWidget {
),
const SizedBox(height: 24),
// --- TITOLO E DESCRIZIONE ---
// Addio initialValue, benvenuto controller!
TextFormField(
initialValue: state.title,
controller: _titleController,
decoration: const InputDecoration(
labelText: 'Titolo del Task*',
border: OutlineInputBorder(),
@@ -165,7 +200,7 @@ class TaskFormScreen extends StatelessWidget {
),
const SizedBox(height: 16),
TextFormField(
initialValue: state.description,
controller: _descController,
maxLines: 4,
decoration: const InputDecoration(
labelText: 'Descrizione (opzionale)',