From e1684285a2fafbc0c9c6346a4f296c5d3d0588fb Mon Sep 17 00:00:00 2001 From: zeefaad Date: Wed, 9 Jul 2025 20:16:04 +0200 Subject: [PATCH] Add main color --- lib/l10n/app_en.arb | 6 +- lib/l10n/app_fr.arb | 6 +- lib/l10n/app_localizations.dart | 24 +++++ lib/l10n/app_localizations_en.dart | 12 +++ lib/l10n/app_localizations_fr.dart | 12 +++ lib/main.dart | 96 +++++++++++------ lib/pages/battery_detail_page.dart | 95 ++++++----------- lib/pages/drone_detail_page.dart | 65 +++++------- lib/pages/flight_detail_page.dart | 161 +++++++++++++---------------- lib/pages/home_page.dart | 44 ++++---- lib/pages/new_battery_page.dart | 112 ++++++++------------ lib/pages/new_drone_page.dart | 96 +++++++---------- lib/pages/new_flight_page.dart | 101 +++++------------- lib/pages/settings_page.dart | 86 +++++++++++++++ lib/providers/color_provider.dart | 31 ++++++ lib/providers/local_provider.dart | 6 +- lib/providers/theme_provider.dart | 1 + pubspec.lock | 8 ++ pubspec.yaml | 2 +- src/rtimelogo.svg | 104 +++++++++++++++++++ 20 files changed, 608 insertions(+), 460 deletions(-) create mode 100644 lib/providers/color_provider.dart create mode 100644 src/rtimelogo.svg diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index b27a751..3ca3b50 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -206,5 +206,9 @@ } }, "flightDeletedSuccessfully": "Flight deleted successfully!", - "failedToDeleteFlight": "Failed to delete flight" + "failedToDeleteFlight": "Failed to delete flight", + "customColorSetting": "Button Color", + "selectButtonColor": "Select Button Primary Color", + "pickColor": "Pick a color", + "select": "Select" } diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index c34c281..c6c4792 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -206,5 +206,9 @@ } }, "flightDeletedSuccessfully": "Vol supprimé avec succès !", - "failedToDeleteFlight": "Échec de la suppression du vol" + "failedToDeleteFlight": "Échec de la suppression du vol", + "customColorSetting": "Couleur des Boutons", + "selectButtonColor": "Sélectionner la couleur principale des boutons", + "pickColor": "Choisir une couleur", + "select": "Sélectionner" } diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 053ae1c..d74d381 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -712,6 +712,30 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Failed to delete flight'** String get failedToDeleteFlight; + + /// No description provided for @customColorSetting. + /// + /// In en, this message translates to: + /// **'Button Color'** + String get customColorSetting; + + /// No description provided for @selectButtonColor. + /// + /// In en, this message translates to: + /// **'Select Button Primary Color'** + String get selectButtonColor; + + /// No description provided for @pickColor. + /// + /// In en, this message translates to: + /// **'Pick a color'** + String get pickColor; + + /// No description provided for @select. + /// + /// In en, this message translates to: + /// **'Select'** + String get select; } class _AppLocalizationsDelegate extends LocalizationsDelegate { diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 808734b..678c58e 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -342,4 +342,16 @@ class AppLocalizationsEn extends AppLocalizations { @override String get failedToDeleteFlight => 'Failed to delete flight'; + + @override + String get customColorSetting => 'Button Color'; + + @override + String get selectButtonColor => 'Select Button Primary Color'; + + @override + String get pickColor => 'Pick a color'; + + @override + String get select => 'Select'; } diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index a1b042f..a0b2081 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -342,4 +342,16 @@ class AppLocalizationsFr extends AppLocalizations { @override String get failedToDeleteFlight => 'Échec de la suppression du vol'; + + @override + String get customColorSetting => 'Couleur des Boutons'; + + @override + String get selectButtonColor => 'Sélectionner la couleur principale des boutons'; + + @override + String get pickColor => 'Choisir une couleur'; + + @override + String get select => 'Sélectionner'; } diff --git a/lib/main.dart b/lib/main.dart index 2b24d59..9998230 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,6 +5,7 @@ import 'package:rtime/l10n/app_localizations.dart'; import 'package:rtime/pages/home_page.dart'; import 'package:rtime/providers/local_provider.dart'; import 'package:rtime/providers/theme_provider.dart'; +import 'package:rtime/providers/color_provider.dart'; void main() { runApp( @@ -16,6 +17,9 @@ void main() { ChangeNotifierProvider( create: (context) => ThemeProvider(), ), + ChangeNotifierProvider( + create: (context) => ColorProvider(), + ), ], child: const MyApp(), ), @@ -32,8 +36,11 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { @override Widget build(BuildContext context) { - return Consumer2( - builder: (context, localeProvider, themeProvider, child) { + return Consumer3( + builder: (context, localeProvider, themeProvider, colorProvider, child) { + // customAccentColor est toujours là si tu veux l'utiliser pour d'autres éléments + final customAccentColor = colorProvider.accentColor; + return MaterialApp( title: 'Rtime', locale: localeProvider.locale, @@ -47,11 +54,10 @@ class _MyAppState extends State { Locale('en', ''), Locale('fr', ''), ], - theme: ThemeData( primaryColor: Colors.white, colorScheme: ColorScheme.light( - primary: Colors.blue.shade600, + primary: Colors.blue, // Couleur primaire fixe pour le mode clair secondary: Colors.teal.shade400, surface: Colors.white, background: Colors.white, @@ -62,20 +68,19 @@ class _MyAppState extends State { onBackground: Colors.black87, ), scaffoldBackgroundColor: Colors.white, - - appBarTheme: AppBarTheme( - backgroundColor: Colors.white, + appBarTheme: const AppBarTheme( + backgroundColor: Color(0xFFF5F5F5), foregroundColor: Colors.black87, elevation: 0.5, - iconTheme: const IconThemeData(color: Colors.black87), - titleTextStyle: const TextStyle( - color: Colors.black87, + iconTheme: IconThemeData(color: Colors.black87), + titleTextStyle: TextStyle( + color: Colors.black, fontSize: 20, fontWeight: FontWeight.bold, ), ), floatingActionButtonTheme: FloatingActionButtonThemeData( - backgroundColor: Colors.blue.shade600, + backgroundColor: customAccentColor, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30.0), @@ -99,7 +104,7 @@ class _MyAppState extends State { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), - selectedTileColor: Colors.blue.shade50, + selectedTileColor: customAccentColor.withOpacity(0.1), ), textTheme: const TextTheme( headlineSmall: TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.black87), @@ -110,11 +115,27 @@ class _MyAppState extends State { bodySmall: TextStyle(fontSize: 12, color: Colors.black45), ), visualDensity: VisualDensity.adaptivePlatformDensity, - buttonTheme: ButtonThemeData( - buttonColor: Colors.blue.shade600, - textTheme: ButtonTextTheme.primary, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + backgroundColor: customAccentColor, + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + ), + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + foregroundColor: customAccentColor, + ), + ), + outlinedButtonTheme: OutlinedButtonThemeData( + style: OutlinedButton.styleFrom( + side: BorderSide(color: customAccentColor), + foregroundColor: customAccentColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), ), ), inputDecorationTheme: InputDecorationTheme( @@ -124,7 +145,7 @@ class _MyAppState extends State { ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), - borderSide: BorderSide(color: Colors.blue.shade600, width: 2), + borderSide: BorderSide(color: customAccentColor, width: 2), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -134,12 +155,10 @@ class _MyAppState extends State { hintStyle: TextStyle(color: Colors.grey.shade500), ), ), - - darkTheme: ThemeData.dark().copyWith( primaryColor: Colors.blueGrey[900], colorScheme: ColorScheme.dark( - primary: Colors.lightBlueAccent, + primary: Colors.blueGrey[600]!, secondary: Colors.tealAccent, surface: Colors.blueGrey.shade800, background: Colors.blueGrey.shade900, @@ -148,9 +167,6 @@ class _MyAppState extends State { onSurface: Colors.white, onBackground: Colors.white, ), - - - appBarTheme: AppBarTheme( backgroundColor: Colors.blueGrey[900], foregroundColor: Colors.white, @@ -163,7 +179,7 @@ class _MyAppState extends State { ), ), floatingActionButtonTheme: FloatingActionButtonThemeData( - backgroundColor: Colors.lightBlueAccent, + backgroundColor: customAccentColor, foregroundColor: Colors.black, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30.0), @@ -185,7 +201,7 @@ class _MyAppState extends State { contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), tileColor: Colors.blueGrey[800], shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - selectedTileColor: Colors.blueGrey[700], + selectedTileColor: customAccentColor.withOpacity(0.3), ), textTheme: const TextTheme( headlineSmall: TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.white), @@ -196,11 +212,27 @@ class _MyAppState extends State { bodySmall: TextStyle(fontSize: 12, color: Colors.white70), ), visualDensity: VisualDensity.adaptivePlatformDensity, - buttonTheme: ButtonThemeData( - buttonColor: Colors.lightBlueAccent, - textTheme: ButtonTextTheme.primary, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + backgroundColor: customAccentColor, + foregroundColor: Colors.black, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + ), + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + foregroundColor: customAccentColor, + ), + ), + outlinedButtonTheme: OutlinedButtonThemeData( + style: OutlinedButton.styleFrom( + side: BorderSide(color: customAccentColor), + foregroundColor: customAccentColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), ), ), inputDecorationTheme: InputDecorationTheme( @@ -210,7 +242,7 @@ class _MyAppState extends State { ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), - borderSide: BorderSide(color: Colors.lightBlueAccent, width: 2), + borderSide: BorderSide(color: customAccentColor, width: 2), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), diff --git a/lib/pages/battery_detail_page.dart b/lib/pages/battery_detail_page.dart index cad1354..2821214 100644 --- a/lib/pages/battery_detail_page.dart +++ b/lib/pages/battery_detail_page.dart @@ -59,29 +59,21 @@ class _BatteryDetailPageState extends State { } } - Future _loadAssociatedFlights() async { setState(() { _isLoadingFlights = true; }); try { final allFlights = await DbHelper.instance.getBatteryFlights(widget.battery.id!); - _associatedFlights = allFlights .where((flight) => flight.batteryId == widget.battery.id) .toList(); - _associatedFlights.sort((a, b) => b.startTimestamp.compareTo(a.startTimestamp)); - setState(() { _isLoadingFlights = false; }); } catch (e) { if (mounted) { - - - - setState(() { _isLoadingFlights = false; }); @@ -91,9 +83,7 @@ class _BatteryDetailPageState extends State { Future _pickImage(ImageSource source) async { final uuid = await ImagesManager.instance.createImage(source); - if (uuid != null) { - if (_currentImageUuid != null && _currentImageUuid != uuid) { await ImagesManager.instance.deleteImage(_currentImageUuid!); } @@ -124,20 +114,13 @@ class _BatteryDetailPageState extends State { voltage: double.parse(_voltageController.text.trim()), imageUuid: _currentImageUuid, ); - try { await DbHelper.instance.updateBattery(updatedBattery); if (mounted) { - - - Navigator.of(context).pop(true); } } catch (e) { if (mounted) { - - - } } } @@ -162,25 +145,17 @@ class _BatteryDetailPageState extends State { ], ), ); - if (confirm == true) { try { - if (_currentImageUuid != null && _currentImageUuid!.isNotEmpty) { await ImagesManager.instance.deleteImage(_currentImageUuid!); } await DbHelper.instance.deleteBattery(widget.battery.id!); if (mounted) { - - - Navigator.of(context).pop(true); } } catch (e) { if (mounted) { - - - } } } @@ -195,8 +170,8 @@ class _BatteryDetailPageState extends State { appBar: AppBar( title: Text(_isEditing ? l10n.editBattery : l10n.batteryDetails), backgroundColor: Theme.of(context).primaryColor, - foregroundColor: Colors.white, - iconTheme: const IconThemeData(color: Colors.white), + foregroundColor: Theme.of(context).appBarTheme.foregroundColor, + iconTheme: Theme.of(context).appBarTheme.iconTheme, actions: [ IconButton( icon: Icon(_isEditing ? Icons.save : Icons.edit), @@ -227,9 +202,10 @@ class _BatteryDetailPageState extends State { width: 180, height: 180, decoration: BoxDecoration( - color: Colors.blueGrey[800], + color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(15), - border: Border.all(color: Colors.tealAccent, width: 2), + border: Border.all( + color: Theme.of(context).colorScheme.primary, width: 2), image: _displayImage != null ? DecorationImage( image: _displayImage!.image, @@ -241,7 +217,7 @@ class _BatteryDetailPageState extends State { ? Icon( Icons.camera_alt, size: 80, - color: Colors.blueGrey[400], + color: Theme.of(context).colorScheme.onSurface.withOpacity(0.4), ) : null, ), @@ -257,7 +233,7 @@ class _BatteryDetailPageState extends State { label: Text(l10n.takePhoto), style: ElevatedButton.styleFrom( backgroundColor: Colors.blueGrey[700], - foregroundColor: Colors.white, + foregroundColor: Colors.white, // Texte en blanc ), ), const SizedBox(width: 10), @@ -267,7 +243,7 @@ class _BatteryDetailPageState extends State { label: Text(l10n.chooseFromGallery), style: ElevatedButton.styleFrom( backgroundColor: Colors.blueGrey[700], - foregroundColor: Colors.white, + foregroundColor: Colors.white, // Texte en blanc ), ), ], @@ -285,15 +261,13 @@ class _BatteryDetailPageState extends State { readOnly: !_isEditing, decoration: InputDecoration( labelText: l10n.batteryName, - labelStyle: const TextStyle(color: Colors.white70), - enabledBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.white30), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: _isEditing ? Colors.blueGrey[600]! : Colors.white30), ), - focusedBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.tealAccent), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.blueGrey[600]!), ), ), - style: const TextStyle(color: Colors.white), validator: (value) { if (value == null || value.isEmpty) { return l10n.pleaseEnterBatteryName; @@ -307,15 +281,13 @@ class _BatteryDetailPageState extends State { readOnly: !_isEditing, decoration: InputDecoration( labelText: l10n.batteryType, - labelStyle: const TextStyle(color: Colors.white70), - enabledBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.white30), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: _isEditing ? Colors.blueGrey[600]! : Colors.white30), ), - focusedBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.tealAccent), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.blueGrey[600]!), ), ), - style: const TextStyle(color: Colors.white), validator: (value) { if (value == null || value.isEmpty) { return l10n.pleaseEnterBatteryType; @@ -330,15 +302,13 @@ class _BatteryDetailPageState extends State { readOnly: !_isEditing, decoration: InputDecoration( labelText: l10n.batteryVoltage, - labelStyle: const TextStyle(color: Colors.white70), - enabledBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.white30), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: _isEditing ? Colors.blueGrey[600]! : Colors.white30), ), - focusedBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.tealAccent), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.blueGrey[600]!), ), ), - style: const TextStyle(color: Colors.white), validator: (value) { if (value == null || value.isEmpty) { return l10n.pleaseEnterBatteryVoltage; @@ -354,25 +324,24 @@ class _BatteryDetailPageState extends State { Center( child: ElevatedButton( onPressed: _saveBattery, - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.secondary, - foregroundColor: Colors.black, - padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 15), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), + style: Theme.of(context).elevatedButtonTheme.style?.copyWith( + padding: MaterialStateProperty.all( + const EdgeInsets.symmetric(horizontal: 40, vertical: 15)), + shape: MaterialStateProperty.all(RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + )), + foregroundColor: MaterialStateProperty.all(Colors.white), // Texte en blanc pour le bouton Save Changes ), - ), child: Text( l10n.saveChanges, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), ), - const SizedBox(height: 30), Text( l10n.latestFlights, - style: Theme.of(context).textTheme.headlineSmall!.copyWith(color: Colors.white), + style: Theme.of(context).textTheme.headlineSmall, ), const SizedBox(height: 15), _isLoadingFlights @@ -381,7 +350,7 @@ class _BatteryDetailPageState extends State { ? Center( child: Text( l10n.noFlightsYet, - style: Theme.of(context).textTheme.titleMedium!.copyWith(color: Colors.white70), + style: Theme.of(context).textTheme.titleMedium, ), ) : ListView.builder( @@ -397,14 +366,14 @@ class _BatteryDetailPageState extends State { child: ListTile( contentPadding: const EdgeInsets.symmetric( horizontal: 20, vertical: 12), - leading: const Icon(Icons.flight_takeoff, + leading: Icon(Icons.flight_takeoff, color: Colors.orangeAccent, size: 32), title: Text( '${flight.name} - ${flightDate.toLocal().toString().split(' ')[0]}', style: Theme.of(context).textTheme.titleMedium, ), - trailing: const Icon(Icons.arrow_forward_ios, - size: 20, color: Colors.white54), + trailing: Icon(Icons.arrow_forward_ios, + size: 20, color: Theme.of(context).colorScheme.onSurface), onTap: () { Navigator.of(context).push( MaterialPageRoute( diff --git a/lib/pages/drone_detail_page.dart b/lib/pages/drone_detail_page.dart index 9ab016d..86711a5 100644 --- a/lib/pages/drone_detail_page.dart +++ b/lib/pages/drone_detail_page.dart @@ -53,7 +53,6 @@ class _DroneDetailPageState extends State { } } - Future _loadAssociatedFlights() async { setState(() { _isLoadingFlights = true; @@ -72,10 +71,6 @@ class _DroneDetailPageState extends State { }); } catch (e) { if (mounted) { - - - - setState(() { _isLoadingFlights = false; }); @@ -119,16 +114,10 @@ class _DroneDetailPageState extends State { try { await DbHelper.instance.updateDrone(updatedDrone); if (mounted) { - - - Navigator.of(context).pop(true); } } catch (e) { if (mounted) { - - - } } } @@ -161,16 +150,10 @@ class _DroneDetailPageState extends State { } await DbHelper.instance.deleteDrone(widget.drone.id!); if (mounted) { - - - Navigator.of(context).pop(true); } } catch (e) { if (mounted) { - - - } } } @@ -185,8 +168,8 @@ class _DroneDetailPageState extends State { appBar: AppBar( title: Text(_isEditing ? l10n.editDrone : l10n.droneDetails), backgroundColor: Theme.of(context).primaryColor, - foregroundColor: Colors.white, - iconTheme: const IconThemeData(color: Colors.white), + foregroundColor: Theme.of(context).appBarTheme.foregroundColor, + iconTheme: Theme.of(context).appBarTheme.iconTheme, actions: [ IconButton( icon: Icon(_isEditing ? Icons.save : Icons.edit), @@ -217,9 +200,10 @@ class _DroneDetailPageState extends State { width: 180, height: 180, decoration: BoxDecoration( - color: Colors.blueGrey[800], + color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(15), - border: Border.all(color: Colors.lightBlueAccent, width: 2), + border: Border.all( + color: Theme.of(context).colorScheme.primary, width: 2), image: _displayImage != null ? DecorationImage( image: _displayImage!.image, @@ -231,7 +215,7 @@ class _DroneDetailPageState extends State { ? Icon( Icons.camera_alt, size: 80, - color: Colors.blueGrey[400], + color: Theme.of(context).colorScheme.onSurface.withOpacity(0.4), ) : null, ), @@ -247,7 +231,7 @@ class _DroneDetailPageState extends State { label: Text(l10n.takePhoto), style: ElevatedButton.styleFrom( backgroundColor: Colors.blueGrey[700], - foregroundColor: Colors.white, + foregroundColor: Colors.white, // Texte en blanc ), ), const SizedBox(width: 10), @@ -257,7 +241,7 @@ class _DroneDetailPageState extends State { label: Text(l10n.chooseFromGallery), style: ElevatedButton.styleFrom( backgroundColor: Colors.blueGrey[700], - foregroundColor: Colors.white, + foregroundColor: Colors.white, // Texte en blanc ), ), ], @@ -275,15 +259,13 @@ class _DroneDetailPageState extends State { readOnly: !_isEditing, decoration: InputDecoration( labelText: l10n.droneName, - labelStyle: const TextStyle(color: Colors.white70), - enabledBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.white30), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: _isEditing ? Colors.blueGrey[600]! : Colors.white30), ), - focusedBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.lightBlueAccent), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.blueGrey[600]!), ), ), - style: const TextStyle(color: Colors.white), validator: (value) { if (value == null || value.isEmpty) { return l10n.pleaseEnterDroneName; @@ -296,25 +278,24 @@ class _DroneDetailPageState extends State { Center( child: ElevatedButton( onPressed: _saveDrone, - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.secondary, - foregroundColor: Colors.black, - padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 15), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), + style: Theme.of(context).elevatedButtonTheme.style?.copyWith( + padding: MaterialStateProperty.all( + const EdgeInsets.symmetric(horizontal: 40, vertical: 15)), + shape: MaterialStateProperty.all(RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + )), + foregroundColor: MaterialStateProperty.all(Colors.white), // Texte en blanc pour le bouton Save Changes ), - ), child: Text( l10n.saveChanges, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), ), - const SizedBox(height: 30), Text( l10n.latestFlights, - style: Theme.of(context).textTheme.headlineSmall!.copyWith(color: Colors.white), + style: Theme.of(context).textTheme.headlineSmall, ), const SizedBox(height: 15), _isLoadingFlights @@ -323,7 +304,7 @@ class _DroneDetailPageState extends State { ? Center( child: Text( l10n.noFlightsYet, - style: Theme.of(context).textTheme.titleMedium!.copyWith(color: Colors.white70), + style: Theme.of(context).textTheme.titleMedium, ), ) : ListView.builder( @@ -345,8 +326,8 @@ class _DroneDetailPageState extends State { '${flight.name} - ${flightDate.toLocal().toString().split(' ')[0]}', style: Theme.of(context).textTheme.titleMedium, ), - trailing: const Icon(Icons.arrow_forward_ios, - size: 20, color: Colors.white54), + trailing: Icon(Icons.arrow_forward_ios, + size: 20, color: Theme.of(context).colorScheme.onSurface), onTap: () { Navigator.of(context).push( MaterialPageRoute( diff --git a/lib/pages/flight_detail_page.dart b/lib/pages/flight_detail_page.dart index 31a87b5..795727d 100644 --- a/lib/pages/flight_detail_page.dart +++ b/lib/pages/flight_detail_page.dart @@ -7,6 +7,9 @@ import 'package:rtime/db/db_helper.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; import 'package:rtime/images_manager.dart'; +import 'package:provider/provider.dart'; +import 'package:rtime/providers/color_provider.dart'; + class FlightDetailPage extends StatefulWidget { final Flight flight; @@ -48,15 +51,11 @@ class _FlightDetailPageState extends State { final droneList = await DbHelper.instance.getDrones(); final batteryList = await DbHelper.instance.getBatteries(); - final drone = droneList.firstWhere( - (d) => d.id == widget.flight.droneId, + final drone = droneList.firstWhere((d) => d.id == widget.flight.droneId, orElse: () => Drone(name: 'Unknown Drone')); - final battery = batteryList.firstWhere( - (b) => b.id == widget.flight.batteryId, - orElse: () => Battery( - name: 'Unknown Battery', type: '', voltage: 0.0)); - + final battery = batteryList.firstWhere((b) => b.id == widget.flight.batteryId, + orElse: () => Battery(name: 'Unknown Battery', type: '', voltage: 0.0)); await _loadImage(drone.imageUuid, (image) { setState(() { @@ -119,9 +118,7 @@ class _FlightDetailPageState extends State { Navigator.of(context).pop(true); } } catch (e) { - if (mounted) { - - } + if (mounted) {} } } } @@ -130,6 +127,8 @@ class _FlightDetailPageState extends State { Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; final flight = widget.flight; + final colorProvider = Provider.of(context); + final accentColor = colorProvider.accentColor; final DateTime startDate = DateTime.fromMillisecondsSinceEpoch(flight.startTimestamp * 1000); @@ -140,13 +139,12 @@ class _FlightDetailPageState extends State { backgroundColor: Theme.of(context).primaryColor, appBar: AppBar( title: Text(l10n.flightDetails), - backgroundColor: Theme.of(context).primaryColor, - foregroundColor: Colors.white, - iconTheme: const IconThemeData(color: Colors.white), - elevation: 0, + backgroundColor: Theme.of(context).appBarTheme.backgroundColor, + foregroundColor: Theme.of(context).appBarTheme.foregroundColor, + iconTheme: Theme.of(context).iconTheme, actions: [ IconButton( - icon: const Icon(Icons.delete_forever, color: Colors.redAccent), + icon: Icon(Icons.delete_forever, color: Theme.of(context).colorScheme.error), onPressed: _deleteFlight, ), ], @@ -161,8 +159,7 @@ class _FlightDetailPageState extends State { Card( elevation: 4, margin: const EdgeInsets.only(bottom: 20), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(15)), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)), child: Padding( padding: const EdgeInsets.all(20.0), child: Column( @@ -170,63 +167,61 @@ class _FlightDetailPageState extends State { children: [ Text( flight.name, - style: Theme.of(context).textTheme.headlineMedium!.copyWith( - color: Theme.of(context).colorScheme.onSurface, + style: Theme.of(context).textTheme.headlineSmall!.copyWith( + color: Theme.of(context).textTheme.headlineSmall!.color, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 10), - Divider(color: Colors.grey[300]), - + Divider(color: Theme.of(context).dividerColor), _buildImageAndDetailRow( context, l10n.drone, _associatedDrone?.name ?? l10n.unknown, _droneDisplayImage, Icons.flight_takeoff, + accentColor, ), - _buildImageAndDetailRow( context, l10n.battery, _associatedBattery?.name ?? l10n.unknown, _batteryDisplayImage, Icons.battery_std, + accentColor, ), _buildDetailRow( l10n.startTime, - '${startDate.toLocal().toString().split(' ')[0]} ${startDate.toLocal().toString().split(' ')[1].substring(0, 5)}'), + '${startDate.toLocal().toString().split(' ')[0]} ${startDate.toLocal().toString().split(' ')[1].substring(0, 5)}', + accentColor), _buildDetailRow( l10n.endTime, - '${endDate.toLocal().toString().split(' ')[0]} ${endDate.toLocal().toString().split(' ')[1].substring(0, 5)}'), - _buildDetailRow( - l10n.duration, - _formatDuration( - flight.startTimestamp, flight.endTimestamp)), + '${endDate.toLocal().toString().split(' ')[0]} ${endDate.toLocal().toString().split(' ')[1].substring(0, 5)}', + accentColor), + _buildDetailRow(l10n.duration, + _formatDuration(flight.startTimestamp, flight.endTimestamp), + accentColor), ], ), ), ), - - if (flight.locationLat != null && flight.locationLong != null) ...[ Text( l10n.flightLocation, - style: Theme.of(context).textTheme.headlineSmall!.copyWith(color: Colors.white), + style: Theme.of(context).textTheme.headlineSmall, ), const SizedBox(height: 15), Container( height: 300, decoration: BoxDecoration( - color: Colors.grey[300], + color: Theme.of(context).cardTheme.color, borderRadius: BorderRadius.circular(15), ), child: ClipRRect( borderRadius: BorderRadius.circular(15), child: FlutterMap( options: MapOptions( - initialCenter: LatLng( - flight.locationLat!, flight.locationLong!), + initialCenter: LatLng(flight.locationLat!, flight.locationLong!), initialZoom: 15.0, interactionOptions: const InteractionOptions( flags: InteractiveFlag.all & ~InteractiveFlag.rotate, @@ -234,20 +229,18 @@ class _FlightDetailPageState extends State { ), children: [ TileLayer( - urlTemplate: - "https://tile.openstreetmap.org/{z}/{x}/{y}.png", + urlTemplate: "https://tile.openstreetmap.org/{z}/{x}/{y}.png", userAgentPackageName: 'com.example.rtime', ), MarkerLayer( markers: [ Marker( - point: LatLng( - flight.locationLat!, flight.locationLong!), + point: LatLng(flight.locationLat!, flight.locationLong!), width: 80, height: 80, - child: const Icon( + child: Icon( Icons.location_on, - color: Colors.red, + color: accentColor, size: 40.0, ), ), @@ -262,10 +255,7 @@ class _FlightDetailPageState extends State { Center( child: Text( l10n.noLocationData, - style: Theme.of(context) - .textTheme - .titleMedium! - .copyWith(color: Colors.white70), + style: Theme.of(context).textTheme.titleMedium, ), ), ], @@ -276,8 +266,7 @@ class _FlightDetailPageState extends State { ); } - - Widget _buildDetailRow(String label, String value) { + Widget _buildDetailRow(String label, String value, Color labelColor) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Row( @@ -288,7 +277,7 @@ class _FlightDetailPageState extends State { child: Text( '$label:', style: Theme.of(context).textTheme.titleSmall!.copyWith( - color: Theme.of(context).colorScheme.secondary, + color: labelColor, fontWeight: FontWeight.bold, ), ), @@ -298,7 +287,7 @@ class _FlightDetailPageState extends State { child: Text( value, style: Theme.of(context).textTheme.titleMedium!.copyWith( - color: Theme.of(context).colorScheme.onSurface, + color: Theme.of(context).textTheme.bodyLarge!.color, ), ), ), @@ -307,62 +296,58 @@ class _FlightDetailPageState extends State { ); } - Widget _buildImageAndDetailRow( - BuildContext context, String label, String value, Image? displayImage, IconData defaultIcon) { + BuildContext context, String label, String value, Image? displayImage, IconData defaultIcon, Color labelColor) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - - Container( - width: 40, - height: 40, - margin: const EdgeInsets.only(right: 12), - decoration: BoxDecoration( - color: Colors.blueGrey[800], - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Colors.blueGrey[600]!, width: 1), - image: displayImage != null - ? DecorationImage( - image: displayImage.image, - fit: BoxFit.cover, - ) - : null, - ), - child: displayImage == null - ? Icon( - defaultIcon, - size: 24, - color: Colors.blueGrey[400], - ) - : null, - ), - Expanded( + flex: 2, + child: Text( + '$label:', + style: Theme.of(context).textTheme.titleSmall!.copyWith( + color: labelColor, + fontWeight: FontWeight.bold, + ), + ), + ), + Expanded( + flex: 3, child: Row( - crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( - flex: 2, - child: Text( - '$label:', - style: Theme.of(context).textTheme.titleSmall!.copyWith( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), - ), - ), - Expanded( - flex: 3, child: Text( value, style: Theme.of(context).textTheme.titleMedium!.copyWith( - color: Theme.of(context).colorScheme.onSurface, + color: Theme.of(context).textTheme.bodyLarge!.color, ), ), ), + Container( + width: 40, + height: 40, + margin: const EdgeInsets.only(left: 12), + decoration: BoxDecoration( + color: Theme.of(context).cardColor, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Theme.of(context).dividerColor, width: 1), + image: displayImage != null + ? DecorationImage( + image: displayImage.image, + fit: BoxFit.cover, + ) + : null, + ), + child: displayImage == null + ? Icon( + defaultIcon, + size: 24, + color: Theme.of(context).iconTheme.color, + ) + : null, + ), ], ), ), diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 2469dac..1368a55 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -1,4 +1,3 @@ - import 'package:flutter/material.dart'; import 'package:rtime/models/drone.dart'; import 'package:rtime/models/battery.dart'; @@ -14,6 +13,8 @@ import 'package:rtime/pages/drone_detail_page.dart'; import 'package:rtime/pages/battery_detail_page.dart'; import 'package:rtime/db/db_helper.dart'; import 'package:rtime/pages/flight_detail_page.dart'; +import 'package:provider/provider.dart'; +import 'package:rtime/providers/color_provider.dart'; import 'package:rtime/widgets/page_transition_animations.dart'; @@ -47,6 +48,8 @@ class _HomePageState extends State { @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; + final customAccentColor = Provider.of(context).accentColor; + return Scaffold( backgroundColor: Theme.of(context).primaryColor, @@ -66,10 +69,10 @@ class _HomePageState extends State { children: [ Text( l10n.appTitle, - style: const TextStyle( + style: TextStyle( fontSize: 48, fontWeight: FontWeight.bold, - color: Colors.lightBlueAccent, + color: customAccentColor, fontFamily: 'Montserrat', ), ), @@ -77,7 +80,6 @@ class _HomePageState extends State { icon: const Icon(Icons.settings, size: 30, color: Colors.white70), onPressed: () { - Navigator.of(context).push( SlideRightPageRoute( page: const SettingsPage(), @@ -111,7 +113,6 @@ class _HomePageState extends State { margin: const EdgeInsets.only(right: 16), child: InkWell( onTap: () { - Navigator.of(context).push( SlideUpPageRoute( page: const NewDronePage(), @@ -129,7 +130,7 @@ class _HomePageState extends State { const SizedBox(height: 10), Text(l10n.addDrone, textAlign: TextAlign.center, - style: Theme.of(context).textTheme.titleSmall), + style: Theme.of(context).textTheme.titleSmall!.copyWith(color: Colors.white)), // Texte blanc ], ), ), @@ -146,7 +147,6 @@ class _HomePageState extends State { margin: const EdgeInsets.only(right: 16), child: InkWell( onTap: () { - Navigator.of(context).push( SlideUpPageRoute( page: const NewDronePage(), @@ -164,7 +164,7 @@ class _HomePageState extends State { const SizedBox(height: 10), Text(l10n.addDrone, textAlign: TextAlign.center, - style: Theme.of(context).textTheme.titleSmall), + style: Theme.of(context).textTheme.titleSmall!.copyWith(color: Colors.white)), // Texte blanc ], ), ), @@ -174,13 +174,11 @@ class _HomePageState extends State { return DroneCard( drone: drones[index], onTap: () { - Navigator.of(context).push( SlideRightPageRoute( page: DroneDetailPage(drone: drones[index]), ), ).then((result) { - if (result == true) { _loadData(); } @@ -218,7 +216,6 @@ class _HomePageState extends State { margin: const EdgeInsets.only(right: 16), child: InkWell( onTap: () { - Navigator.of(context).push( SlideUpPageRoute( page: const NewBatteryPage(), @@ -236,12 +233,12 @@ class _HomePageState extends State { const SizedBox(height: 10), Text(l10n.addBattery, textAlign: TextAlign.center, - style: Theme.of(context).textTheme.titleSmall), + style: Theme.of(context).textTheme.titleSmall!.copyWith(color: Colors.white)), // Texte blanc ], ), - ), ), - ); + ), + ); } else { final batteries = snapshot.data!; return ListView.builder( @@ -253,7 +250,6 @@ class _HomePageState extends State { margin: const EdgeInsets.only(right: 16), child: InkWell( onTap: () { - Navigator.of(context).push( SlideUpPageRoute( page: const NewBatteryPage(), @@ -271,7 +267,7 @@ class _HomePageState extends State { const SizedBox(height: 10), Text(l10n.addBattery, textAlign: TextAlign.center, - style: Theme.of(context).textTheme.titleSmall), + style: Theme.of(context).textTheme.titleSmall!.copyWith(color: Colors.white)), // Texte blanc ], ), ), @@ -281,13 +277,11 @@ class _HomePageState extends State { return BatteryCard( battery: batteries[index], onTap: () { - Navigator.of(context).push( SlideRightPageRoute( page: BatteryDetailPage(battery: batteries[index]), ), ).then((result) { - if (result == true) { _loadData(); } @@ -325,7 +319,7 @@ class _HomePageState extends State { style: Theme.of(context) .textTheme .titleMedium! - .copyWith(color: Colors.white70), + .copyWith(color: Theme.of(context).colorScheme.onBackground), ), ); } else { @@ -341,16 +335,15 @@ class _HomePageState extends State { child: ListTile( contentPadding: const EdgeInsets.symmetric( horizontal: 20, vertical: 12), - leading: const Icon(Icons.flight_takeoff, + leading: Icon(Icons.flight_takeoff, color: Colors.orangeAccent, size: 32), title: Text( '${flight.name} - ${DateTime.fromMillisecondsSinceEpoch(flight.startTimestamp * 1000).toLocal().toString().split(' ')[0]}', style: Theme.of(context).textTheme.titleMedium, ), - trailing: const Icon(Icons.arrow_forward_ios, - size: 20, color: Colors.white54), + trailing: Icon(Icons.arrow_forward_ios, + size: 20, color: Theme.of(context).colorScheme.onSurface), onTap: () { - Navigator.of(context).push( SlideRightPageRoute( page: FlightDetailPage(flight: flight), @@ -370,7 +363,6 @@ class _HomePageState extends State { ), floatingActionButton: FloatingActionButton.extended( onPressed: () { - Navigator.of(context).push( SlideUpPageRoute( page: const NewFlightPage(), @@ -379,9 +371,9 @@ class _HomePageState extends State { }, label: Text( l10n.newFlight, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white), // Texte blanc ), - icon: const Icon(Icons.add_to_photos, size: 28), + icon: const Icon(Icons.add_to_photos, size: 28, color: Colors.white), // Icône blanche ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, ); diff --git a/lib/pages/new_battery_page.dart b/lib/pages/new_battery_page.dart index 1663d76..96c1513 100644 --- a/lib/pages/new_battery_page.dart +++ b/lib/pages/new_battery_page.dart @@ -28,9 +28,7 @@ class _NewBatteryPageState extends State { super.dispose(); } - Future _pickImage(ImageSource source) async { - final l10n = AppLocalizations.of(context)!; final uuid = await ImagesManager.instance.createImage(source); if (uuid != null) { final loadedImage = await ImagesManager.instance.loadImage(uuid); @@ -38,23 +36,11 @@ class _NewBatteryPageState extends State { _selectedImageUuid = uuid; _displayImage = loadedImage; }); - if (mounted) { - - - - } - } else { - if (mounted) { - - - - } } } void _saveBattery() async { if (_formKey.currentState!.validate()) { - final l10n = AppLocalizations.of(context)!; final newBattery = Battery( name: _nameController.text.trim(), type: _typeController.text.trim(), @@ -65,18 +51,9 @@ class _NewBatteryPageState extends State { try { await DbHelper.instance.insertBattery(newBattery); if (mounted) { - - - Navigator.of(context).pop(); } - } catch (e) { - if (mounted) { - - - - } - } + } catch (e) {} } } @@ -98,33 +75,33 @@ class _NewBatteryPageState extends State { key: _formKey, child: ListView( children: [ - Center( child: Column( children: [ - Container( - width: 150, - height: 150, - decoration: BoxDecoration( - color: Colors.blueGrey[800], - borderRadius: BorderRadius.circular(15), - border: Border.all(color: Colors.lightBlueAccent, width: 2), - - image: _displayImage != null - ? DecorationImage( - image: _displayImage!.image, - fit: BoxFit.cover, + GestureDetector( + onTap: () => _pickImage(ImageSource.camera), + child: Container( + width: 150, + height: 150, + decoration: BoxDecoration( + color: Colors.blueGrey[800], + borderRadius: BorderRadius.circular(15), + border: Border.all(color: Colors.blueGrey[600]!, width: 2), + image: _displayImage != null + ? DecorationImage( + image: _displayImage!.image, + fit: BoxFit.cover, + ) + : null, + ), + child: _displayImage == null + ? Icon( + Icons.camera_alt, + size: 60, + color: Colors.blueGrey[400], ) : null, ), - - child: _displayImage == null - ? Icon( - Icons.camera_alt, - size: 60, - color: Colors.blueGrey[400], - ) - : null, ), const SizedBox(height: 10), Text(l10n.batteryImage, @@ -139,7 +116,7 @@ class _NewBatteryPageState extends State { label: Text(l10n.takePhoto), style: ElevatedButton.styleFrom( backgroundColor: Colors.blueGrey[700], - foregroundColor: Colors.white, + foregroundColor: Colors.white, // Set text color to white ), ), const SizedBox(width: 10), @@ -149,7 +126,7 @@ class _NewBatteryPageState extends State { label: Text(l10n.chooseFromGallery), style: ElevatedButton.styleFrom( backgroundColor: Colors.blueGrey[700], - foregroundColor: Colors.white, + foregroundColor: Colors.white, // Set text color to white ), ), ], @@ -163,11 +140,11 @@ class _NewBatteryPageState extends State { decoration: InputDecoration( labelText: l10n.batteryName, labelStyle: const TextStyle(color: Colors.white70), - enabledBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.white30), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.blueGrey[600]!), ), - focusedBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.lightBlueAccent), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.blueGrey[600]!), ), ), style: const TextStyle(color: Colors.white), @@ -184,11 +161,11 @@ class _NewBatteryPageState extends State { decoration: InputDecoration( labelText: l10n.batteryType, labelStyle: const TextStyle(color: Colors.white70), - enabledBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.white30), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.blueGrey[600]!), ), - focusedBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.lightBlueAccent), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.blueGrey[600]!), ), ), style: const TextStyle(color: Colors.white), @@ -206,11 +183,11 @@ class _NewBatteryPageState extends State { decoration: InputDecoration( labelText: l10n.batteryVoltage, labelStyle: const TextStyle(color: Colors.white70), - enabledBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.white30), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.blueGrey[600]!), ), - focusedBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.lightBlueAccent), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.blueGrey[600]!), ), ), style: const TextStyle(color: Colors.white), @@ -228,15 +205,14 @@ class _NewBatteryPageState extends State { Center( child: ElevatedButton( onPressed: _saveBattery, - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.secondary, - foregroundColor: Colors.black, - padding: - const EdgeInsets.symmetric(horizontal: 40, vertical: 15), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - ), + style: Theme.of(context).elevatedButtonTheme.style?.copyWith( + padding: MaterialStateProperty.all( + const EdgeInsets.symmetric(horizontal: 40, vertical: 15)), + shape: MaterialStateProperty.all(RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + )), + foregroundColor: MaterialStateProperty.all(Colors.white), // Set text color to white + ), child: Text( l10n.saveBattery, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), diff --git a/lib/pages/new_drone_page.dart b/lib/pages/new_drone_page.dart index 948ce73..72552fc 100644 --- a/lib/pages/new_drone_page.dart +++ b/lib/pages/new_drone_page.dart @@ -24,9 +24,7 @@ class _NewDronePageState extends State { super.dispose(); } - Future _pickImage(ImageSource source) async { - final l10n = AppLocalizations.of(context)!; final uuid = await ImagesManager.instance.createImage(source); if (uuid != null) { final loadedImage = await ImagesManager.instance.loadImage(uuid); @@ -34,23 +32,11 @@ class _NewDronePageState extends State { _selectedImageUuid = uuid; _displayImage = loadedImage; }); - if (mounted) { - - - - } - } else { - if (mounted) { - - - - } } } void _saveDrone() async { if (_formKey.currentState!.validate()) { - final l10n = AppLocalizations.of(context)!; final newDrone = Drone( name: _nameController.text.trim(), imageUuid: _selectedImageUuid, @@ -59,18 +45,9 @@ class _NewDronePageState extends State { try { await DbHelper.instance.insertDrone(newDrone); if (mounted) { - - - Navigator.of(context).pop(); } - } catch (e) { - if (mounted) { - - - - } - } + } catch (e) {} } } @@ -92,33 +69,33 @@ class _NewDronePageState extends State { key: _formKey, child: ListView( children: [ - Center( child: Column( children: [ - Container( - width: 150, - height: 150, - decoration: BoxDecoration( - color: Colors.blueGrey[800], - borderRadius: BorderRadius.circular(15), - border: Border.all(color: Colors.lightBlueAccent, width: 2), - - image: _displayImage != null - ? DecorationImage( - image: _displayImage!.image, - fit: BoxFit.cover, + GestureDetector( + onTap: () => _pickImage(ImageSource.camera), + child: Container( + width: 150, + height: 150, + decoration: BoxDecoration( + color: Colors.blueGrey[800], + borderRadius: BorderRadius.circular(15), + border: Border.all(color: Colors.blueGrey[600]!, width: 2), + image: _displayImage != null + ? DecorationImage( + image: _displayImage!.image, + fit: BoxFit.cover, + ) + : null, + ), + child: _displayImage == null + ? Icon( + Icons.camera_alt, + size: 60, + color: Colors.blueGrey[400], ) : null, ), - - child: _displayImage == null - ? Icon( - Icons.camera_alt, - size: 60, - color: Colors.blueGrey[400], - ) - : null, ), const SizedBox(height: 10), Text(l10n.droneImage, @@ -133,7 +110,7 @@ class _NewDronePageState extends State { label: Text(l10n.takePhoto), style: ElevatedButton.styleFrom( backgroundColor: Colors.blueGrey[700], - foregroundColor: Colors.white, + foregroundColor: Colors.white, // Set text color to white ), ), const SizedBox(width: 10), @@ -143,7 +120,7 @@ class _NewDronePageState extends State { label: Text(l10n.chooseFromGallery), style: ElevatedButton.styleFrom( backgroundColor: Colors.blueGrey[700], - foregroundColor: Colors.white, + foregroundColor: Colors.white, // Set text color to white ), ), ], @@ -157,11 +134,11 @@ class _NewDronePageState extends State { decoration: InputDecoration( labelText: l10n.droneName, labelStyle: const TextStyle(color: Colors.white70), - enabledBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.white30), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.blueGrey[600]!), ), - focusedBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.lightBlueAccent), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.blueGrey[600]!), ), ), style: const TextStyle(color: Colors.white), @@ -176,15 +153,14 @@ class _NewDronePageState extends State { Center( child: ElevatedButton( onPressed: _saveDrone, - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.secondary, - foregroundColor: Colors.black, - padding: - const EdgeInsets.symmetric(horizontal: 40, vertical: 15), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - ), + style: Theme.of(context).elevatedButtonTheme.style?.copyWith( + padding: MaterialStateProperty.all( + const EdgeInsets.symmetric(horizontal: 40, vertical: 15)), + shape: MaterialStateProperty.all(RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + )), + foregroundColor: MaterialStateProperty.all(Colors.white), // Set text color to white + ), child: Text( l10n.saveDrone, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), diff --git a/lib/pages/new_flight_page.dart b/lib/pages/new_flight_page.dart index 5508b06..6f05d74 100644 --- a/lib/pages/new_flight_page.dart +++ b/lib/pages/new_flight_page.dart @@ -8,6 +8,8 @@ import 'dart:async'; import 'package:geolocator/geolocator.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; +import 'package:provider/provider.dart'; +import 'package:rtime/providers/color_provider.dart'; class NewFlightPage extends StatefulWidget { const NewFlightPage({super.key}); @@ -17,11 +19,9 @@ class NewFlightPage extends StatefulWidget { } class _NewFlightPageState extends State { - late Future> _dronesFuture; late Future> _batteriesFuture; - Drone? selectedDrone; Battery? selectedBattery; bool isFlightActive = false; @@ -30,15 +30,12 @@ class _NewFlightPageState extends State { String formattedTime = '00:00:00'; int? flightStartTime; - bool useGpsLocation = false; Position? currentPosition; bool isGettingLocation = false; - final MapController _mapController = MapController(); - bool _initialMapCentered = false; @override @@ -47,7 +44,6 @@ class _NewFlightPageState extends State { _loadAvailableItems(); } - void _loadAvailableItems() { _dronesFuture = DbHelper.instance.getDrones(); _batteriesFuture = DbHelper.instance.getBatteries(); @@ -59,8 +55,6 @@ class _NewFlightPageState extends State { super.dispose(); } - - Future _getCurrentLocation() async { if (!mounted) return; @@ -75,9 +69,7 @@ class _NewFlightPageState extends State { serviceEnabled = await Geolocator.isLocationServiceEnabled(); if (!serviceEnabled) { - if (mounted) { - - } + if (mounted) {} if (mounted) { setState(() { useGpsLocation = false; @@ -95,9 +87,7 @@ class _NewFlightPageState extends State { if (permission == LocationPermission.denied) { permission = await Geolocator.requestPermission(); if (permission == LocationPermission.denied) { - if (mounted) { - - } + if (mounted) {} if (mounted) { setState(() { useGpsLocation = false; @@ -113,9 +103,7 @@ class _NewFlightPageState extends State { } if (permission == LocationPermission.deniedForever) { - if (mounted) { - - } + if (mounted) {} if (mounted) { setState(() { useGpsLocation = false; @@ -138,7 +126,6 @@ class _NewFlightPageState extends State { setState(() { currentPosition = position; - if (_initialMapCentered && _mapController.camera.center != LatLng(position.latitude, position.longitude)) { _mapController.move( LatLng(currentPosition!.latitude, currentPosition!.longitude), @@ -147,13 +134,9 @@ class _NewFlightPageState extends State { } }); } - if (mounted) { - - } + if (mounted) {} } catch (e) { - if (mounted) { - - } + if (mounted) {} if (mounted) { setState(() { useGpsLocation = false; @@ -169,12 +152,10 @@ class _NewFlightPageState extends State { } } - void _startFlight() { final l10n = AppLocalizations.of(context)!; if (selectedDrone == null || selectedBattery == null) { - ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(l10n.selectDroneBattery)), ); @@ -187,10 +168,7 @@ class _NewFlightPageState extends State { }); _getCurrentLocation().then((_) { - if (useGpsLocation && currentPosition == null) { - - return; } @@ -201,7 +179,6 @@ class _NewFlightPageState extends State { } } - void _proceedToStartFlight() { final l10n = AppLocalizations.of(context)!; @@ -217,26 +194,21 @@ class _NewFlightPageState extends State { } }); }); - } - Future _stopFlight() async { final l10n = AppLocalizations.of(context)!; - stopwatch.stop(); timer?.cancel(); - final int flightEndTime = DateTime.now().millisecondsSinceEpoch ~/ 1000; - final Duration flightDuration = stopwatch.elapsed; - final Flight newFlight = Flight( - name: '${selectedDrone!.name} - ${DateTime.fromMillisecondsSinceEpoch(flightStartTime! * 1000).toLocal().toString().split(' ')[0]}', + name: + '${selectedDrone!.name} - ${DateTime.fromMillisecondsSinceEpoch(flightStartTime! * 1000).toLocal().toString().split(' ')[0]}', startTimestamp: flightStartTime!, endTimestamp: flightEndTime, droneId: selectedDrone!.id!, @@ -246,17 +218,11 @@ class _NewFlightPageState extends State { ); try { - await DbHelper.instance.insertFlight(newFlight); - if (mounted) { - - } + if (mounted) {} } catch (e) { - if (mounted) { - - } + if (mounted) {} } finally { - setState(() { isFlightActive = false; stopwatch.reset(); @@ -275,7 +241,6 @@ class _NewFlightPageState extends State { } } - String _formatDuration(Duration duration) { String twoDigits(int n) => n.toString().padLeft(2, '0'); String hours = twoDigits(duration.inHours); @@ -287,6 +252,7 @@ class _NewFlightPageState extends State { @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; + final colorProvider = Provider.of(context); return Scaffold( backgroundColor: Theme.of(context).primaryColor, @@ -300,7 +266,6 @@ class _NewFlightPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( l10n.chooseDrone, style: Theme.of(context).textTheme.headlineSmall, @@ -347,7 +312,7 @@ class _NewFlightPageState extends State { items: drones.map>((Drone drone) { return DropdownMenuItem( value: drone, - child: Text(drone.name), + child: Text(drone.name, style: Theme.of(context).textTheme.titleMedium!.copyWith(color: Colors.white)), // Texte blanc ); }).toList(), ), @@ -357,8 +322,6 @@ class _NewFlightPageState extends State { ), ), ), - - Text( l10n.chooseBattery, style: Theme.of(context).textTheme.headlineSmall, @@ -405,7 +368,7 @@ class _NewFlightPageState extends State { items: batteries.map>((Battery battery) { return DropdownMenuItem( value: battery, - child: Text('${battery.name} (${battery.voltage}V)'), + child: Text('${battery.name} (${battery.voltage}V)', style: Theme.of(context).textTheme.titleMedium!.copyWith(color: Colors.white)), // Texte blanc ); }).toList(), ), @@ -415,8 +378,6 @@ class _NewFlightPageState extends State { ), ), ), - - Card( margin: const EdgeInsets.only(bottom: 30), child: ListTile( @@ -440,11 +401,9 @@ class _NewFlightPageState extends State { }, activeColor: Theme.of(context).colorScheme.primary, ), - leading: Icon(Icons.location_on, color: Theme.of(context).colorScheme.secondary), + leading: Icon(Icons.location_on, color: colorProvider.accentColor), ), ), - - if (currentPosition != null && useGpsLocation) Container( margin: const EdgeInsets.only(bottom: 20), @@ -461,7 +420,6 @@ class _NewFlightPageState extends State { ], ), child: ClipRRect( - borderRadius: BorderRadius.circular(15), child: FlutterMap( mapController: _mapController, @@ -496,9 +454,9 @@ class _NewFlightPageState extends State { point: LatLng(currentPosition!.latitude, currentPosition!.longitude), width: 80, height: 80, - child: const Icon( + child: Icon( Icons.location_on, - color: Colors.red, + color: colorProvider.accentColor, size: 40, ), ), @@ -508,30 +466,26 @@ class _NewFlightPageState extends State { ), ), ), - - Center( child: Text( formattedTime, - style: const TextStyle( + style: TextStyle( fontSize: 72, fontWeight: FontWeight.bold, - color: Colors.lightBlueAccent, + color: colorProvider.accentColor, fontFamily: 'RobotoMono', ), ), ), const SizedBox(height: 40), - - Center( child: isFlightActive ? ElevatedButton.icon( onPressed: _stopFlight, - icon: const Icon(Icons.stop, size: 30), + icon: const Icon(Icons.stop, size: 30, color: Colors.white), // Icône blanche label: Text( l10n.stopFlight, - style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold), + style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.white), // Texte blanc ), style: ElevatedButton.styleFrom( backgroundColor: Colors.redAccent, @@ -546,21 +500,22 @@ class _NewFlightPageState extends State { : (isGettingLocation ? Column( children: [ - const CircularProgressIndicator(color: Colors.tealAccent), + CircularProgressIndicator(color: colorProvider.accentColor), const SizedBox(height: 10), - Text(l10n.obtainingLocation, style: Theme.of(context).textTheme.titleSmall), + Text(l10n.obtainingLocation, + style: Theme.of(context).textTheme.titleSmall), ], ) : ElevatedButton.icon( onPressed: _startFlight, - icon: const Icon(Icons.flight_takeoff, size: 30), + icon: const Icon(Icons.flight_takeoff, size: 30, color: Colors.white), // Icône blanche label: Text( l10n.startFlight, - style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold), + style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.white), // Texte blanc ), style: ElevatedButton.styleFrom( - backgroundColor: Colors.tealAccent, - foregroundColor: Colors.black, + backgroundColor: colorProvider.accentColor, + foregroundColor: Theme.of(context).colorScheme.onPrimary, padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 20), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30), diff --git a/lib/pages/settings_page.dart b/lib/pages/settings_page.dart index 7eef3fa..7d948d0 100644 --- a/lib/pages/settings_page.dart +++ b/lib/pages/settings_page.dart @@ -1,8 +1,11 @@ +// pages/settings_page.dart import 'package:flutter/material.dart'; import 'package:rtime/l10n/app_localizations.dart'; import 'package:provider/provider.dart'; import 'package:rtime/providers/local_provider.dart'; import 'package:rtime/providers/theme_provider.dart'; +import 'package:rtime/providers/color_provider.dart'; +import 'package:flutter_colorpicker/flutter_colorpicker.dart'; class SettingsPage extends StatefulWidget { const SettingsPage({super.key}); @@ -12,11 +15,29 @@ class SettingsPage extends StatefulWidget { } class _SettingsPageState extends State { + // Initialize with a default color or the current accent color + late Color _pickerColor; // Use late to initialize in initState + + @override + void initState() { + super.initState(); + // Initialize _pickerColor with the current accent color from the ColorProvider + _pickerColor = Provider.of(context, listen: false).accentColor; + } + + void _onColorChanged(Color color) { + setState(() => _pickerColor = color); + } + @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; final currentLocale = Localizations.localeOf(context); final themeProvider = Provider.of(context); + final colorProvider = Provider.of(context); + + // REMOVE THIS LINE: + // _pickerColor = colorProvider.accentColor; return Scaffold( backgroundColor: Theme.of(context).colorScheme.background, @@ -104,6 +125,71 @@ class _SettingsPageState extends State { ], ), ), + const SizedBox(height: 30), + Text( + l10n.customColorSetting, + style: Theme.of(context).textTheme.headlineSmall, + ), + const SizedBox(height: 10), + Card( + color: Theme.of(context).cardTheme.color, + child: ListTile( + title: Text( + l10n.selectButtonColor, + style: Theme.of(context).textTheme.titleMedium, + ), + trailing: Container( + width: 30, + height: 30, + decoration: BoxDecoration( + // This should always reflect the current accent color from the provider + color: colorProvider.accentColor, + shape: BoxShape.circle, + border: Border.all(color: Theme.of(context).dividerColor), + ), + ), + onTap: () { + // When the dialog is opened, ensure _pickerColor reflects the *current* accent color + // so that the color picker starts with the color currently in use. + setState(() { + _pickerColor = colorProvider.accentColor; + }); + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text(l10n.pickColor), + content: SingleChildScrollView( + child: ColorPicker( + pickerColor: _pickerColor, + onColorChanged: _onColorChanged, + pickerAreaHeightPercent: 0.8, + enableAlpha: false, + displayThumbColor: true, + paletteType: PaletteType.hsv, + ), + ), + actions: [ + TextButton( + child: Text(l10n.cancel), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + TextButton( + child: Text(l10n.select), + onPressed: () { + colorProvider.setAccentColor(_pickerColor); + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); + }, + ), + ), ], ), ), diff --git a/lib/providers/color_provider.dart b/lib/providers/color_provider.dart new file mode 100644 index 0000000..b319e66 --- /dev/null +++ b/lib/providers/color_provider.dart @@ -0,0 +1,31 @@ +// providers/color_provider.dart +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class ColorProvider extends ChangeNotifier { + Color _accentColor = Colors.blue.shade600; + + Color get accentColor => _accentColor; + + ColorProvider() { + _loadAccentColor(); + } + + void _loadAccentColor() async { + final prefs = await SharedPreferences.getInstance(); + final int? colorValue = prefs.getInt('customAccentColor'); + if (colorValue != null) { + _accentColor = Color(colorValue); + } + notifyListeners(); + } + + void setAccentColor(Color color) async { + if (_accentColor != color) { + _accentColor = color; + notifyListeners(); + final prefs = await SharedPreferences.getInstance(); + await prefs.setInt('customAccentColor', color.value); + } + } +} diff --git a/lib/providers/local_provider.dart b/lib/providers/local_provider.dart index c47d349..8446135 100644 --- a/lib/providers/local_provider.dart +++ b/lib/providers/local_provider.dart @@ -1,3 +1,4 @@ +// providers/local_provider.dart import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -6,12 +7,10 @@ class LocaleProvider extends ChangeNotifier { Locale? get locale => _locale; - LocaleProvider() { _loadLocale(); } - void _loadLocale() async { final prefs = await SharedPreferences.getInstance(); final languageCode = prefs.getString('languageCode'); @@ -25,14 +24,12 @@ class LocaleProvider extends ChangeNotifier { notifyListeners(); } - void setLocale(Locale newLocale) async { if (_locale == newLocale) return; _locale = newLocale; notifyListeners(); - final prefs = await SharedPreferences.getInstance(); await prefs.setString('languageCode', newLocale.languageCode); if (newLocale.countryCode != null) { @@ -42,7 +39,6 @@ class LocaleProvider extends ChangeNotifier { } } - void clearLocale() async { _locale = null; notifyListeners(); diff --git a/lib/providers/theme_provider.dart b/lib/providers/theme_provider.dart index 01de855..ed65cae 100644 --- a/lib/providers/theme_provider.dart +++ b/lib/providers/theme_provider.dart @@ -1,3 +1,4 @@ +// providers/theme_provider.dart import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; diff --git a/pubspec.lock b/pubspec.lock index f7d6533..b48a5d2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -270,6 +270,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_colorpicker: + dependency: "direct main" + description: + name: flutter_colorpicker + sha256: "969de5f6f9e2a570ac660fb7b501551451ea2a1ab9e2097e89475f60e07816ea" + url: "https://pub.dev" + source: hosted + version: "1.1.0" flutter_lints: dependency: "direct dev" description: diff --git a/pubspec.yaml b/pubspec.yaml index f5712b0..9b7f08e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,7 +30,7 @@ environment: dependencies: flutter: sdk: flutter - + flutter_colorpicker: ^1.0.0 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.8 diff --git a/src/rtimelogo.svg b/src/rtimelogo.svg new file mode 100644 index 0000000..776fc9b --- /dev/null +++ b/src/rtimelogo.svg @@ -0,0 +1,104 @@ + + + +