feat-ultimi_servizi-contratti_in_scadenza #12

Merged
brontomark merged 18 commits from feat-ultimi_servizi-contratti_in_scadenza into main 2026-05-04 15:36:42 +02:00
20 changed files with 361 additions and 20 deletions
Showing only changes of commit 8d3ca62304 - Show all commits

View File

@@ -1 +1,16 @@
include: package:flutter_lints/flutter.yaml include: package:flutter_lints/flutter.yaml
analyzer:
exclude:
# Escludiamo i file generati per le lingue, così il linter non ci entra proprio
- "lib/generated/**"
- "lib/l10n/*.dart"
- "**/*.g.dart" # Già che ci siamo escludiamo tutti i file generati (tipo quelli di JsonSerializable)
- "**/*.freezed.dart"
linter:
rules:
diagnostic_describe_all_properties: false
public_member_api_docs: false
# Ti consiglio di aggiungere anche questa se usi molto i file generati
avoid_relative_lib_imports: true

3
l10n.yaml Normal file
View File

@@ -0,0 +1,3 @@
arb-dir: lib/l10n
template-arb-file: app_it.arb
output-localization-file: app_localizations.dart

View File

@@ -1,3 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flux/l10n/app_localizations.dart';
extension MyStringExtensions on String? { extension MyStringExtensions on String? {
// Gestiamo anche il nullable per sicurezza // Gestiamo anche il nullable per sicurezza
String myFormat() { String myFormat() {
@@ -40,3 +43,7 @@ extension MyStringExtensions on String? {
.join('.'); // Ritorna tutto tranne l'ultima parte .join('.'); // Ritorna tutto tranne l'ultima parte
} }
} }
extension LocalizationExtension on BuildContext {
AppLocalizations get l10n => AppLocalizations.of(this)!;
}

View File

@@ -1,7 +1,7 @@
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/utils/string_extensions.dart'; import 'package:flux/core/utils/extensions.dart';
import 'package:flux/features/customers/models/customer_file_model.dart'; import 'package:flux/features/customers/models/customer_file_model.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:supabase_flutter/supabase_flutter.dart';

View File

@@ -1,5 +1,5 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flux/core/utils/string_extensions.dart'; import 'package:flux/core/utils/extensions.dart';
import 'package:flux/features/customers/models/customer_file_model.dart'; import 'package:flux/features/customers/models/customer_file_model.dart';
class CustomerModel extends Equatable { class CustomerModel extends Equatable {

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/theme/theme.dart'; import 'package:flux/core/theme/theme.dart';
import 'package:flux/core/utils/extensions.dart';
import 'package:flux/features/home/ui/quick_actions_widget.dart'; import 'package:flux/features/home/ui/quick_actions_widget.dart';
import 'package:flux/features/master_data/staff/blocs/staff_cubit.dart'; import 'package:flux/features/master_data/staff/blocs/staff_cubit.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
@@ -57,25 +58,25 @@ class HomeScreen extends StatelessWidget {
), ),
delegate: SliverChildListDelegate([ delegate: SliverChildListDelegate([
_buildDashboardWidget( _buildDashboardWidget(
title: 'Contratti in Scadenza', title: context.l10n.expiring_contracts,
icon: Icons.assignment_late_outlined, icon: Icons.assignment_late_outlined,
color: Colors.orange, color: Colors.orange,
context: context, context: context,
), ),
_buildDashboardWidget( _buildDashboardWidget(
title: 'Sticky Notes', title: context.l10n.sticky_notes,
icon: Icons.sticky_note_2_outlined, icon: Icons.sticky_note_2_outlined,
color: Colors.yellow.shade700, color: Colors.yellow.shade700,
context: context, context: context,
), ),
_buildDashboardWidget( _buildDashboardWidget(
title: 'I miei Task', title: context.l10n.my_tasks,
icon: Icons.check_box_outlined, icon: Icons.check_box_outlined,
color: Colors.green, color: Colors.green,
context: context, context: context,
), ),
_buildDashboardWidget( _buildDashboardWidget(
title: 'Ultimi Servizi', title: context.l10n.latestServices,
icon: Icons.design_services_outlined, icon: Icons.design_services_outlined,
color: Colors.blue, color: Colors.blue,
context: context, context: context,

View File

@@ -1,5 +1,5 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flux/core/utils/string_extensions.dart'; import 'package:flux/core/utils/extensions.dart';
class BrandModel extends Equatable { class BrandModel extends Equatable {
final String? id; final String? id;

View File

@@ -1,5 +1,5 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flux/core/utils/string_extensions.dart'; import 'package:flux/core/utils/extensions.dart';
class ModelModel extends Equatable { class ModelModel extends Equatable {
final String? id; final String? id;

View File

@@ -4,7 +4,7 @@ import 'dart:io';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flux/core/utils/string_extensions.dart'; import 'package:flux/core/utils/extensions.dart';
import 'package:flux/features/services/data/services_repository.dart'; import 'package:flux/features/services/data/services_repository.dart';
import 'package:flux/features/services/models/service_file_model.dart'; import 'package:flux/features/services/models/service_file_model.dart';
import 'package:flux/features/services/models/service_model.dart'; import 'package:flux/features/services/models/service_model.dart';

View File

@@ -3,7 +3,7 @@ import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/utils/string_extensions.dart'; import 'package:flux/core/utils/extensions.dart';
import 'package:flux/features/services/data/services_repository.dart'; import 'package:flux/features/services/data/services_repository.dart';
import 'package:flux/features/services/models/energy_service_model.dart'; import 'package:flux/features/services/models/energy_service_model.dart';
import 'package:flux/features/services/models/entertainment_service_model.dart'; import 'package:flux/features/services/models/entertainment_service_model.dart';

View File

@@ -1,7 +1,7 @@
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/utils/string_extensions.dart'; import 'package:flux/core/utils/extensions.dart';
import 'package:flux/features/customers/data/customer_repository.dart'; import 'package:flux/features/customers/data/customer_repository.dart';
import 'package:flux/features/customers/models/customer_file_model.dart'; import 'package:flux/features/customers/models/customer_file_model.dart';
import 'package:flux/features/services/models/service_file_model.dart'; import 'package:flux/features/services/models/service_file_model.dart';

View File

@@ -1,5 +1,5 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flux/core/utils/string_extensions.dart'; import 'package:flux/core/utils/extensions.dart';
import 'package:flux/features/services/models/energy_service_model.dart'; import 'package:flux/features/services/models/energy_service_model.dart';
import 'package:flux/features/services/models/entertainment_service_model.dart'; import 'package:flux/features/services/models/entertainment_service_model.dart';
import 'package:flux/features/services/models/fin_service_model.dart'; import 'package:flux/features/services/models/fin_service_model.dart';

13
lib/l10n/app_en.arb Normal file
View File

@@ -0,0 +1,13 @@
{
"@@locale": "en",
"welcomeBack": "Welcome back, {name}! 👋",
"latestServices": "Latest Services",
"masterData": "Master Data",
"settings": "Settings",
"newService": "Service",
"expiring_contracts": "Expiring Contracts",
"sticky_notes": "Sticky Notes",
"my_tasks": "My Tasks",
"latest_service_tickets": "Latest service tickets"
}

20
lib/l10n/app_it.arb Normal file
View File

@@ -0,0 +1,20 @@
{
"@@locale": "it",
"welcomeBack": "Bentornato, {name}! 👋",
"@welcomeBack": {
"placeholders": {
"name": {
"type": "String"
}
}
},
"latestServices": "Ultimi Servizi",
"masterData": "Anagrafiche",
"settings": "Impostazioni",
"newService": "Servizio",
"expiring_contracts": "Contratti in scadenza",
"sticky_notes": "Sticky Notes",
"my_tasks": "Mie Attività",
"latest_service_tickets": "Ultime assistenze"
}

View File

@@ -0,0 +1,188 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:intl/intl.dart' as intl;
import 'app_localizations_en.dart';
import 'app_localizations_it.dart';
// ignore_for_file: type=lint
/// Callers can lookup localized strings with an instance of AppLocalizations
/// returned by `AppLocalizations.of(context)`.
///
/// Applications need to include `AppLocalizations.delegate()` in their app's
/// `localizationDelegates` list, and the locales they support in the app's
/// `supportedLocales` list. For example:
///
/// ```dart
/// import 'l10n/app_localizations.dart';
///
/// return MaterialApp(
/// localizationsDelegates: AppLocalizations.localizationsDelegates,
/// supportedLocales: AppLocalizations.supportedLocales,
/// home: MyApplicationHome(),
/// );
/// ```
///
/// ## Update pubspec.yaml
///
/// Please make sure to update your pubspec.yaml to include the following
/// packages:
///
/// ```yaml
/// dependencies:
/// # Internationalization support.
/// flutter_localizations:
/// sdk: flutter
/// intl: any # Use the pinned version from flutter_localizations
///
/// # Rest of dependencies
/// ```
///
/// ## iOS Applications
///
/// iOS applications define key application metadata, including supported
/// locales, in an Info.plist file that is built into the application bundle.
/// To configure the locales supported by your app, youll need to edit this
/// file.
///
/// First, open your projects ios/Runner.xcworkspace Xcode workspace file.
/// Then, in the Project Navigator, open the Info.plist file under the Runner
/// projects Runner folder.
///
/// Next, select the Information Property List item, select Add Item from the
/// Editor menu, then select Localizations from the pop-up menu.
///
/// Select and expand the newly-created Localizations item then, for each
/// locale your application supports, add a new item and select the locale
/// you wish to add from the pop-up menu in the Value field. This list should
/// be consistent with the languages listed in the AppLocalizations.supportedLocales
/// property.
abstract class AppLocalizations {
AppLocalizations(String locale)
: localeName = intl.Intl.canonicalizedLocale(locale.toString());
final String localeName;
static AppLocalizations? of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
/// A list of this localizations delegate along with the default localizations
/// delegates.
///
/// Returns a list of localizations delegates containing this delegate along with
/// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
/// and GlobalWidgetsLocalizations.delegate.
///
/// Additional delegates can be added by appending to this list in
/// MaterialApp. This list does not have to be used at all if a custom list
/// of delegates is preferred or required.
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates =
<LocalizationsDelegate<dynamic>>[
delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
];
/// A list of this localizations delegate's supported locales.
static const List<Locale> supportedLocales = <Locale>[
Locale('en'),
Locale('it'),
];
/// No description provided for @welcomeBack.
///
/// In it, this message translates to:
/// **'Bentornato, {name}! 👋'**
String welcomeBack(String name);
/// No description provided for @latestServices.
///
/// In it, this message translates to:
/// **'Ultimi Servizi'**
String get latestServices;
/// No description provided for @masterData.
///
/// In it, this message translates to:
/// **'Anagrafiche'**
String get masterData;
/// No description provided for @settings.
///
/// In it, this message translates to:
/// **'Impostazioni'**
String get settings;
/// No description provided for @newService.
///
/// In it, this message translates to:
/// **'Servizio'**
String get newService;
/// No description provided for @expiring_contracts.
///
/// In it, this message translates to:
/// **'Contratti in scadenza'**
String get expiring_contracts;
/// No description provided for @sticky_notes.
///
/// In it, this message translates to:
/// **'Sticky Notes'**
String get sticky_notes;
/// No description provided for @my_tasks.
///
/// In it, this message translates to:
/// **'Mie Attività'**
String get my_tasks;
/// No description provided for @latest_service_tickets.
///
/// In it, this message translates to:
/// **'Ultime assistenze'**
String get latest_service_tickets;
}
class _AppLocalizationsDelegate
extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
@override
Future<AppLocalizations> load(Locale locale) {
return SynchronousFuture<AppLocalizations>(lookupAppLocalizations(locale));
}
@override
bool isSupported(Locale locale) =>
<String>['en', 'it'].contains(locale.languageCode);
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
AppLocalizations lookupAppLocalizations(Locale locale) {
// Lookup logic when only language code is specified.
switch (locale.languageCode) {
case 'en':
return AppLocalizationsEn();
case 'it':
return AppLocalizationsIt();
}
throw FlutterError(
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
'an issue with the localizations generation tool. Please file an issue '
'on GitHub with a reproducible sample app and the gen-l10n configuration '
'that was used.',
);
}

View File

@@ -0,0 +1,39 @@
// ignore: unused_import
import 'package:intl/intl.dart' as intl;
import 'app_localizations.dart';
// ignore_for_file: type=lint
/// The translations for English (`en`).
class AppLocalizationsEn extends AppLocalizations {
AppLocalizationsEn([String locale = 'en']) : super(locale);
@override
String welcomeBack(String name) {
return 'Welcome back, $name! 👋';
}
@override
String get latestServices => 'Latest Services';
@override
String get masterData => 'Master Data';
@override
String get settings => 'Settings';
@override
String get newService => 'Service';
@override
String get expiring_contracts => 'Expiring Contracts';
@override
String get sticky_notes => 'Sticky Notes';
@override
String get my_tasks => 'My Tasks';
@override
String get latest_service_tickets => 'Latest service tickets';
}

View File

@@ -0,0 +1,39 @@
// ignore: unused_import
import 'package:intl/intl.dart' as intl;
import 'app_localizations.dart';
// ignore_for_file: type=lint
/// The translations for Italian (`it`).
class AppLocalizationsIt extends AppLocalizations {
AppLocalizationsIt([String locale = 'it']) : super(locale);
@override
String welcomeBack(String name) {
return 'Bentornato, $name! 👋';
}
@override
String get latestServices => 'Ultimi Servizi';
@override
String get masterData => 'Anagrafiche';
@override
String get settings => 'Impostazioni';
@override
String get newService => 'Servizio';
@override
String get expiring_contracts => 'Contratti in scadenza';
@override
String get sticky_notes => 'Sticky Notes';
@override
String get my_tasks => 'Mie Attività';
@override
String get latest_service_tickets => 'Ultime assistenze';
}

View File

@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flux/features/auth/bloc/auth_cubit.dart'; import 'package:flux/features/auth/bloc/auth_cubit.dart';
import 'package:flux/l10n/app_localizations.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@@ -152,6 +153,11 @@ class _FluxAppState extends State<FluxApp> {
darkTheme: fluxDarkTheme, darkTheme: fluxDarkTheme,
themeMode: themeState.currentTheme.themeMode, themeMode: themeState.currentTheme.themeMode,
routerConfig: _router, routerConfig: _router,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
locale: const Locale(
'it',
), // Per ora forziamo l'italiano, poi lo renderemo dinamico!
); );
}, },
); );

View File

@@ -254,6 +254,11 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.0" version: "6.0.0"
flutter_localizations:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_plugin_android_lifecycle: flutter_plugin_android_lifecycle:
dependency: transitive dependency: transitive
description: description:
@@ -316,10 +321,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: google_fonts name: google_fonts
sha256: db9df7a5898d894eeda4c78143f35c30a243558be439518972366880b80bf88e sha256: "4e9391085e524954a51e3625b7c9c7e9851dc3f376603208bb45c24b9a66255d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.0.2" version: "8.1.0"
gotrue: gotrue:
dependency: transitive dependency: transitive
description: description:
@@ -364,10 +369,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: image_picker name: image_picker
sha256: "784210112be18ea55f69d7076e2c656a4e24949fa9e76429fe53af0c0f4fa320" sha256: "91c025426c2881c551100bce834e201c835a170151545f58d17da5180ca7d9ac"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "1.2.2"
image_picker_android: image_picker_android:
dependency: transitive dependency: transitive
description: description:
@@ -1041,10 +1046,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vector_graphics name: vector_graphics
sha256: "81da85e9ca8885ade47f9685b953cb098970d11be4821ac765580a6607ea4373" sha256: "6409a25046024f0f8c5d8a59fec314081e81f9d436b66ca4015a8b49772bf445"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.21" version: "1.2.0"
vector_graphics_codec: vector_graphics_codec:
dependency: transitive dependency: transitive
description: description:
@@ -1073,10 +1078,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: "046d3928e16fa4dc46e8350415661755ab759d9fc97fc21b5ab295f71e4f0499" sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "15.1.0" version: "15.2.0"
web: web:
dependency: transitive dependency: transitive
description: description:

View File

@@ -12,6 +12,8 @@ dependencies:
file_picker: ^11.0.2 file_picker: ^11.0.2
flutter: flutter:
sdk: flutter sdk: flutter
flutter_localizations:
sdk: flutter
flutter_bloc: ^9.1.1 flutter_bloc: ^9.1.1
flutter_dotenv: ^6.0.0 flutter_dotenv: ^6.0.0
flutter_svg: ^2.2.4 flutter_svg: ^2.2.4
@@ -27,6 +29,8 @@ dependencies:
shared_preferences: ^2.5.5 shared_preferences: ^2.5.5
supabase_flutter: ^2.12.2 supabase_flutter: ^2.12.2
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
@@ -34,6 +38,7 @@ dev_dependencies:
flutter: flutter:
uses-material-design: true uses-material-design: true
generate: true
assets: assets:
- assets/images/ - assets/images/