reworked operation (#12)
Reviewed-on: #12 Co-authored-by: Mark M2 Macbook <marco@catelli.it> Co-committed-by: Mark M2 Macbook <marco@catelli.it>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flux/features/operations/data/operations_repository.dart';
|
||||
import 'package:flux/features/operations/models/operation_model.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
|
||||
part '../../latest_store_operations/bloc/latest_store_operations_events.dart';
|
||||
part '../../latest_store_operations/bloc/latest_store_operations_state.dart';
|
||||
|
||||
class LatestStoreOperationsBloc
|
||||
extends Bloc<LatestStoreOperationsEvent, LatestStoreOperationsState> {
|
||||
final _repository = GetIt.I.get<OperationsRepository>();
|
||||
|
||||
LatestStoreOperationsBloc()
|
||||
: super(
|
||||
const LatestStoreOperationsState(
|
||||
status: LatestStoreOperationsStatus.initial,
|
||||
),
|
||||
) {
|
||||
on<InitLastStoreOperationsEvent>((event, emit) async {
|
||||
emit(state.copyWith(status: LatestStoreOperationsStatus.loading));
|
||||
try {
|
||||
// 1. Creiamo uno stream "intermedio" che idrata i dati
|
||||
final hydratedStream = _repository
|
||||
.getLastStoreOperationsStream(storeId: event.storeId, limit: 5)
|
||||
.asyncMap((List<OperationModel> rawOperations) async {
|
||||
// Questo gira ad ogni "scatto" dello stream di Supabase
|
||||
List<OperationModel> fullyHydratedOperations = [];
|
||||
|
||||
for (OperationModel operation in rawOperations) {
|
||||
// Peschiamo i dati completi (incluso il cliente)
|
||||
OperationModel fullOperation = await _repository
|
||||
.fetchOperationById(operation.id!);
|
||||
fullyHydratedOperations.add(fullOperation);
|
||||
}
|
||||
|
||||
// Passiamo la lista completa allo step successivo
|
||||
return fullyHydratedOperations;
|
||||
});
|
||||
|
||||
// 2. Ora passiamo lo stream idratato all'emit.forEach
|
||||
await emit.forEach(
|
||||
hydratedStream, // Usiamo lo stream modificato!
|
||||
onData: (List<OperationModel> fullyHydratedOperations) {
|
||||
// Qui ora è tutto sincrono e bellissimo
|
||||
return state.copyWith(
|
||||
operations: fullyHydratedOperations,
|
||||
status: LatestStoreOperationsStatus.success,
|
||||
);
|
||||
},
|
||||
onError: (error, stackTrace) => state.copyWith(
|
||||
status: LatestStoreOperationsStatus.failure,
|
||||
error: error.toString(),
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: LatestStoreOperationsStatus.failure,
|
||||
error: e.toString(),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
part of 'latest_store_operations_bloc.dart';
|
||||
|
||||
sealed class LatestStoreOperationsEvent extends Equatable {
|
||||
const LatestStoreOperationsEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class InitLastStoreOperationsEvent extends LatestStoreOperationsEvent {
|
||||
final String storeId;
|
||||
|
||||
const InitLastStoreOperationsEvent(this.storeId);
|
||||
|
||||
@override
|
||||
List<Object> get props => [storeId];
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
part of 'latest_store_operations_bloc.dart';
|
||||
|
||||
enum LatestStoreOperationsStatus { initial, loading, success, failure }
|
||||
|
||||
class LatestStoreOperationsState extends Equatable {
|
||||
final LatestStoreOperationsStatus status;
|
||||
final String? error;
|
||||
final List<OperationModel> operations;
|
||||
|
||||
const LatestStoreOperationsState({
|
||||
required this.status,
|
||||
this.error,
|
||||
this.operations = const [],
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [status, error, operations];
|
||||
|
||||
LatestStoreOperationsState copyWith({
|
||||
LatestStoreOperationsStatus? status,
|
||||
String? error,
|
||||
List<OperationModel>? operations,
|
||||
}) {
|
||||
return LatestStoreOperationsState(
|
||||
status: status ?? this.status,
|
||||
error: error,
|
||||
operations: operations ?? this.operations,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flux/core/blocs/session/session_cubit.dart';
|
||||
import 'package:flux/core/theme/theme.dart';
|
||||
import 'package:flux/core/utils/extensions.dart';
|
||||
import 'package:flux/features/home/latest_store_operations/bloc/latest_store_operations_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class LatestStoreOperationsCard extends StatelessWidget {
|
||||
const LatestStoreOperationsCard({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final currentStoreId = context.read<SessionCubit>().state.currentStore?.id;
|
||||
|
||||
return BlocProvider(
|
||||
// 1. Creiamo il Bloc e facciamo partire subito la query
|
||||
create: (context) =>
|
||||
LatestStoreOperationsBloc()
|
||||
..add(InitLastStoreOperationsEvent(currentStoreId ?? '')),
|
||||
child: BlocListener<SessionCubit, SessionState>(
|
||||
// 2. MAGIA: Se l'utente cambia negozio dalla barra in alto, riavviamo lo stream!
|
||||
listenWhen: (previous, current) =>
|
||||
previous.currentStore?.id != current.currentStore?.id,
|
||||
listener: (context, state) {
|
||||
if (state.currentStore?.id != null) {
|
||||
context.read<LatestStoreOperationsBloc>().add(
|
||||
InitLastStoreOperationsEvent(state.currentStore!.id!),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: _LatestOperationsCardContent(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _LatestOperationsCardContent extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
const color = Colors.blue;
|
||||
|
||||
return Card(
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
side: BorderSide(color: theme.dividerColor.withValues(alpha: 0.5)),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// --- HEADER DELLA CARD ---
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.design_services_outlined,
|
||||
color: color,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: TextButton(
|
||||
onPressed: () => context.push('/operations'),
|
||||
child: Text(
|
||||
context.l10n.homeLatestOperations,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
color: context.primaryText,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// --- CORPO DELLA CARD (LA LISTA REAL-TIME) ---
|
||||
Expanded(
|
||||
child:
|
||||
BlocBuilder<
|
||||
LatestStoreOperationsBloc,
|
||||
LatestStoreOperationsState
|
||||
>(
|
||||
builder: (context, state) {
|
||||
if (state.status == LatestStoreOperationsStatus.loading ||
|
||||
state.status == LatestStoreOperationsStatus.initial) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (state.status == LatestStoreOperationsStatus.failure) {
|
||||
return Center(
|
||||
child: Text(
|
||||
"Errore di caricamento",
|
||||
style: TextStyle(color: theme.colorScheme.error),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (state.operations.isEmpty) {
|
||||
return Center(
|
||||
child: Text(
|
||||
"Nessun servizio recente.",
|
||||
style: TextStyle(
|
||||
color: context.secondaryText,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.separated(
|
||||
itemCount: state.operations.length,
|
||||
separatorBuilder: (context, index) => Divider(
|
||||
height: 1,
|
||||
color: theme.dividerColor.withValues(alpha: 0.3),
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
final operation = state.operations[index];
|
||||
return InkWell(
|
||||
onTap: () => context.push(
|
||||
'/operation-form',
|
||||
extra: operation,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 8.0,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 5,
|
||||
child: Text(
|
||||
operation.customerDisplayName ??
|
||||
'Cliente sconosciuto',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w700,
|
||||
color: context.primaryText,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 5,
|
||||
child: Text(
|
||||
operation.reference,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: context.primaryText,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"${operation.createdAt?.day}/${operation.createdAt?.month}",
|
||||
style: TextStyle(
|
||||
color: context.secondaryText,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flux/core/theme/theme.dart';
|
||||
|
||||
class DashboardActionCard extends StatelessWidget {
|
||||
final String label;
|
||||
final IconData icon;
|
||||
final Color color;
|
||||
final VoidCallback onTap;
|
||||
|
||||
const DashboardActionCard({
|
||||
super.key,
|
||||
required this.label,
|
||||
required this.icon,
|
||||
required this.color,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
// CAMBIA QUI: da Border.all a BorderSide
|
||||
side: BorderSide(
|
||||
color: context.accent.withValues(alpha: 0.1),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(icon, color: color, size: 32),
|
||||
const SizedBox(height: 8),
|
||||
Text(label, style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flux/core/theme/theme.dart';
|
||||
import 'package:flux/features/home/ui/dashboard_action_card.dart';
|
||||
import 'package:flux/features/services/utils/service_actions.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class DashboardAdaptiveGrid extends StatelessWidget {
|
||||
final bool isLargeScreen;
|
||||
final Function(int)? onTabRequested;
|
||||
const DashboardAdaptiveGrid({
|
||||
super.key,
|
||||
this.isLargeScreen = false,
|
||||
this.onTabRequested,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
// Logica Colonne: Mobile 2, Tablet 3, Desktop 4+
|
||||
int crossAxisCount = 2;
|
||||
if (constraints.maxWidth > 1000) {
|
||||
crossAxisCount = 5;
|
||||
} else if (constraints.maxWidth > 700) {
|
||||
crossAxisCount = 3;
|
||||
}
|
||||
|
||||
return GridView.count(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
crossAxisCount: crossAxisCount,
|
||||
mainAxisSpacing: 16,
|
||||
crossAxisSpacing: 16,
|
||||
childAspectRatio: isLargeScreen ? 1.3 : 1.5,
|
||||
children: [
|
||||
DashboardActionCard(
|
||||
label: 'Nuova Op',
|
||||
icon: Icons.add_task,
|
||||
color: context.accent,
|
||||
onTap: () => startNewService(context),
|
||||
),
|
||||
DashboardActionCard(
|
||||
label: 'Clienti',
|
||||
icon: Icons.people,
|
||||
color: Colors.orange,
|
||||
onTap: () => onTabRequested?.call(1),
|
||||
),
|
||||
DashboardActionCard(
|
||||
label: 'Prodotti',
|
||||
icon: Icons
|
||||
.phone_android_outlined, // Icona "comoda" e professionale
|
||||
color: context
|
||||
.accent, // O un colore a tua scelta, magari Indigo o Blue
|
||||
onTap: () => context.push(
|
||||
'/products',
|
||||
), // Apre la schermata sopra la Dashboard
|
||||
),
|
||||
DashboardActionCard(
|
||||
label: 'Campagne',
|
||||
icon: Icons.campaign,
|
||||
color: Colors.purple,
|
||||
onTap: () {},
|
||||
),
|
||||
DashboardActionCard(
|
||||
label: 'Report',
|
||||
icon: Icons.analytics,
|
||||
color: Colors.teal,
|
||||
onTap: () {},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flux/core/blocs/session/session_cubit.dart';
|
||||
import 'package:flux/core/theme/theme.dart';
|
||||
import 'package:flux/features/home/ui/dashboard_adaptive_grid.dart';
|
||||
|
||||
class DashboardContent extends StatelessWidget {
|
||||
final bool isLargeScreen;
|
||||
final Function(int)? onTabRequested;
|
||||
|
||||
const DashboardContent({
|
||||
super.key,
|
||||
this.isLargeScreen = false,
|
||||
this.onTabRequested,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<SessionCubit, SessionState>(
|
||||
builder: (context, state) {
|
||||
final store = state.currentStore;
|
||||
final company = state.company;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: context.background,
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
SliverAppBar(
|
||||
expandedHeight: 100.0,
|
||||
floating: false,
|
||||
pinned: true,
|
||||
elevation: 0,
|
||||
backgroundColor: context.background,
|
||||
flexibleSpace: FlexibleSpaceBar(
|
||||
titlePadding: const EdgeInsets.only(left: 24, bottom: 16),
|
||||
title: Text(
|
||||
store?.nome ?? 'Dashboard',
|
||||
style: TextStyle(
|
||||
color: context.primaryText,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Center(
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxWidth: 1200),
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildWelcome(context, company?.ragioneSociale),
|
||||
const SizedBox(height: 32),
|
||||
const _SectionTitle(title: 'AZIONI RAPIDE'),
|
||||
const SizedBox(height: 16),
|
||||
DashboardAdaptiveGrid(
|
||||
isLargeScreen: isLargeScreen,
|
||||
onTabRequested: onTabRequested,
|
||||
),
|
||||
const SizedBox(height: 40),
|
||||
const _SectionTitle(title: 'INFO PUNTO VENDITA'),
|
||||
const SizedBox(height: 16),
|
||||
_buildStoreCard(context, store),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildWelcome(BuildContext context, String? name) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Benvenuto in',
|
||||
style: TextStyle(color: context.secondaryText, fontSize: 16),
|
||||
),
|
||||
Text(
|
||||
name ?? 'Azienda',
|
||||
style: const TextStyle(fontSize: 28, fontWeight: FontWeight.w900),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStoreCard(BuildContext context, dynamic store) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: context.accent.withValues(alpha: 0.05),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: context.accent.withValues(alpha: 0.1)),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.location_on, color: context.accent),
|
||||
const SizedBox(width: 16),
|
||||
Text('${store?.indirizzo}, ${store?.comune} (${store?.provincia})'),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SectionTitle extends StatelessWidget {
|
||||
final String title;
|
||||
const _SectionTitle({required this.title});
|
||||
@override
|
||||
Widget build(BuildContext context) => Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: context.accent,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 12,
|
||||
letterSpacing: 1.2,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flux/core/blocs/session/session_cubit.dart';
|
||||
import 'package:flux/core/theme/theme.dart';
|
||||
import 'package:flux/core/utils/extensions.dart';
|
||||
import 'package:flux/features/home/latest_store_operations/ui/latest_store_operations_card.dart';
|
||||
import 'package:flux/features/home/ui/quick_actions_widget.dart';
|
||||
import 'package:flux/features/master_data/staff/blocs/staff_cubit.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
@@ -57,31 +59,27 @@ class HomeScreen extends StatelessWidget {
|
||||
),
|
||||
delegate: SliverChildListDelegate([
|
||||
_buildDashboardWidget(
|
||||
title: 'Contratti in Scadenza',
|
||||
title: context.l10n.homeExpiringContracts,
|
||||
icon: Icons.assignment_late_outlined,
|
||||
color: Colors.orange,
|
||||
context: context,
|
||||
),
|
||||
_buildDashboardWidget(
|
||||
title: 'Sticky Notes',
|
||||
title: context.l10n.commonStickyNotes,
|
||||
icon: Icons.sticky_note_2_outlined,
|
||||
color: Colors.yellow.shade700,
|
||||
context: context,
|
||||
),
|
||||
_buildDashboardWidget(
|
||||
title: 'I miei Task',
|
||||
title: context.l10n.homeMyTasks,
|
||||
icon: Icons.check_box_outlined,
|
||||
color: Colors.green,
|
||||
context: context,
|
||||
),
|
||||
LatestStoreOperationsCard(),
|
||||
|
||||
_buildDashboardWidget(
|
||||
title: 'Ultimi Servizi',
|
||||
icon: Icons.design_services_outlined,
|
||||
color: Colors.blue,
|
||||
context: context,
|
||||
),
|
||||
_buildDashboardWidget(
|
||||
title: 'Ultime Assistenze',
|
||||
title: context.l10n.homeLatestOperationTickets,
|
||||
icon: Icons.support_agent_outlined,
|
||||
color: Colors.purple,
|
||||
context: context,
|
||||
@@ -117,7 +115,7 @@ class HomeScreen extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Bentornato, ${user!.name}! 👋",
|
||||
context.l10n.homeWelcomeBack(user?.name ?? "Utente"),
|
||||
style: theme.textTheme.headlineMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: -0.5,
|
||||
@@ -151,7 +149,7 @@ class HomeScreen extends StatelessWidget {
|
||||
Icon(Icons.storefront, size: 16, color: context.primary),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
currentStore?.nome ?? "Nessun negozio",
|
||||
currentStore?.name ?? context.l10n.homeNoStoreFound,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: context.primary,
|
||||
@@ -183,17 +181,17 @@ class HomeScreen extends StatelessWidget {
|
||||
children: [
|
||||
QuickActionButton(
|
||||
icon: Icons.add,
|
||||
label: "Servizio",
|
||||
label: context.l10n.commonOperation,
|
||||
color: Colors.blue,
|
||||
onTap: () {
|
||||
// Entriamo nel form! Nessun parametro extra = Nuovo Servizio
|
||||
context.push('/service-form');
|
||||
context.push('/operation-form');
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
QuickActionButton(
|
||||
icon: Icons.handyman,
|
||||
label: "Assistenza",
|
||||
label: context.l10n.homeNewOperationTicket,
|
||||
color: Colors.redAccent,
|
||||
onTap: () {
|
||||
// TODO: Quando avrai la rotta per la nuova assistenza
|
||||
@@ -203,7 +201,7 @@ class HomeScreen extends StatelessWidget {
|
||||
const SizedBox(width: 12),
|
||||
QuickActionButton(
|
||||
icon: Icons.note_add,
|
||||
label: "Nota",
|
||||
label: context.l10n.commonNote,
|
||||
color: Colors.amber,
|
||||
onTap: () {
|
||||
// TODO: Quando faremo il modale/pagina delle note
|
||||
@@ -212,7 +210,7 @@ class HomeScreen extends StatelessWidget {
|
||||
const SizedBox(width: 12),
|
||||
QuickActionButton(
|
||||
icon: Icons.task_alt,
|
||||
label: "Task",
|
||||
label: context.l10n.commonTask,
|
||||
color: Colors.teal,
|
||||
onTap: () {
|
||||
// TODO: Quando faremo i task
|
||||
@@ -280,7 +278,7 @@ class HomeScreen extends StatelessWidget {
|
||||
const Spacer(),
|
||||
Center(
|
||||
child: Text(
|
||||
"(Coming Soon)",
|
||||
context.l10n.commonComingSoon,
|
||||
style: TextStyle(
|
||||
color: context.secondaryText.withValues(alpha: 0.7),
|
||||
fontStyle: FontStyle.italic,
|
||||
@@ -354,7 +352,7 @@ class HomeScreen extends StatelessWidget {
|
||||
: theme.iconTheme.color,
|
||||
),
|
||||
title: Text(
|
||||
store.nome,
|
||||
store.name,
|
||||
style: TextStyle(
|
||||
fontWeight: isSelected
|
||||
? FontWeight.bold
|
||||
|
||||
Reference in New Issue
Block a user