Add main color
This commit is contained in:
@ -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"
|
||||
}
|
||||
|
||||
@ -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"
|
||||
}
|
||||
|
||||
@ -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<AppLocalizations> {
|
||||
|
||||
@ -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';
|
||||
}
|
||||
|
||||
@ -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';
|
||||
}
|
||||
|
||||
@ -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<MyApp> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer2<LocaleProvider, ThemeProvider>(
|
||||
builder: (context, localeProvider, themeProvider, child) {
|
||||
return Consumer3<LocaleProvider, ThemeProvider, ColorProvider>(
|
||||
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<MyApp> {
|
||||
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<MyApp> {
|
||||
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<MyApp> {
|
||||
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<MyApp> {
|
||||
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<MyApp> {
|
||||
),
|
||||
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<MyApp> {
|
||||
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<MyApp> {
|
||||
onSurface: Colors.white,
|
||||
onBackground: Colors.white,
|
||||
),
|
||||
|
||||
|
||||
|
||||
appBarTheme: AppBarTheme(
|
||||
backgroundColor: Colors.blueGrey[900],
|
||||
foregroundColor: Colors.white,
|
||||
@ -163,7 +179,7 @@ class _MyAppState extends State<MyApp> {
|
||||
),
|
||||
),
|
||||
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<MyApp> {
|
||||
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<MyApp> {
|
||||
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<MyApp> {
|
||||
),
|
||||
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),
|
||||
|
||||
@ -59,29 +59,21 @@ class _BatteryDetailPageState extends State<BatteryDetailPage> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Future<void> _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<BatteryDetailPage> {
|
||||
|
||||
Future<void> _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<BatteryDetailPage> {
|
||||
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<BatteryDetailPage> {
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
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<BatteryDetailPage> {
|
||||
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<BatteryDetailPage> {
|
||||
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<BatteryDetailPage> {
|
||||
? 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<BatteryDetailPage> {
|
||||
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<BatteryDetailPage> {
|
||||
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<BatteryDetailPage> {
|
||||
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<BatteryDetailPage> {
|
||||
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<BatteryDetailPage> {
|
||||
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<BatteryDetailPage> {
|
||||
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<BatteryDetailPage> {
|
||||
? 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<BatteryDetailPage> {
|
||||
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(
|
||||
|
||||
@ -53,7 +53,6 @@ class _DroneDetailPageState extends State<DroneDetailPage> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Future<void> _loadAssociatedFlights() async {
|
||||
setState(() {
|
||||
_isLoadingFlights = true;
|
||||
@ -72,10 +71,6 @@ class _DroneDetailPageState extends State<DroneDetailPage> {
|
||||
});
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
|
||||
|
||||
|
||||
|
||||
setState(() {
|
||||
_isLoadingFlights = false;
|
||||
});
|
||||
@ -119,16 +114,10 @@ class _DroneDetailPageState extends State<DroneDetailPage> {
|
||||
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<DroneDetailPage> {
|
||||
}
|
||||
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<DroneDetailPage> {
|
||||
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<DroneDetailPage> {
|
||||
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<DroneDetailPage> {
|
||||
? 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<DroneDetailPage> {
|
||||
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<DroneDetailPage> {
|
||||
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<DroneDetailPage> {
|
||||
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<DroneDetailPage> {
|
||||
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<DroneDetailPage> {
|
||||
? 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<DroneDetailPage> {
|
||||
'${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(
|
||||
|
||||
@ -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<FlightDetailPage> {
|
||||
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<FlightDetailPage> {
|
||||
Navigator.of(context).pop(true);
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
|
||||
}
|
||||
if (mounted) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -130,6 +127,8 @@ class _FlightDetailPageState extends State<FlightDetailPage> {
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final flight = widget.flight;
|
||||
final colorProvider = Provider.of<ColorProvider>(context);
|
||||
final accentColor = colorProvider.accentColor;
|
||||
|
||||
final DateTime startDate =
|
||||
DateTime.fromMillisecondsSinceEpoch(flight.startTimestamp * 1000);
|
||||
@ -140,13 +139,12 @@ class _FlightDetailPageState extends State<FlightDetailPage> {
|
||||
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<FlightDetailPage> {
|
||||
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<FlightDetailPage> {
|
||||
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<FlightDetailPage> {
|
||||
),
|
||||
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<FlightDetailPage> {
|
||||
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<FlightDetailPage> {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
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<FlightDetailPage> {
|
||||
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<FlightDetailPage> {
|
||||
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<FlightDetailPage> {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@ -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<HomePage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final customAccentColor = Provider.of<ColorProvider>(context).accentColor;
|
||||
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
@ -66,10 +69,10 @@ class _HomePageState extends State<HomePage> {
|
||||
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<HomePage> {
|
||||
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<HomePage> {
|
||||
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<HomePage> {
|
||||
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<HomePage> {
|
||||
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<HomePage> {
|
||||
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<HomePage> {
|
||||
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<HomePage> {
|
||||
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<HomePage> {
|
||||
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<HomePage> {
|
||||
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<HomePage> {
|
||||
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<HomePage> {
|
||||
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<HomePage> {
|
||||
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<HomePage> {
|
||||
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<HomePage> {
|
||||
),
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
onPressed: () {
|
||||
|
||||
Navigator.of(context).push(
|
||||
SlideUpPageRoute(
|
||||
page: const NewFlightPage(),
|
||||
@ -379,9 +371,9 @@ class _HomePageState extends State<HomePage> {
|
||||
},
|
||||
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,
|
||||
);
|
||||
|
||||
@ -28,9 +28,7 @@ class _NewBatteryPageState extends State<NewBatteryPage> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
||||
Future<void> _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<NewBatteryPage> {
|
||||
_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<NewBatteryPage> {
|
||||
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<NewBatteryPage> {
|
||||
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<NewBatteryPage> {
|
||||
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<NewBatteryPage> {
|
||||
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<NewBatteryPage> {
|
||||
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<NewBatteryPage> {
|
||||
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<NewBatteryPage> {
|
||||
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<NewBatteryPage> {
|
||||
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),
|
||||
|
||||
@ -24,9 +24,7 @@ class _NewDronePageState extends State<NewDronePage> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
||||
Future<void> _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<NewDronePage> {
|
||||
_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<NewDronePage> {
|
||||
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<NewDronePage> {
|
||||
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<NewDronePage> {
|
||||
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<NewDronePage> {
|
||||
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<NewDronePage> {
|
||||
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<NewDronePage> {
|
||||
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),
|
||||
|
||||
@ -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<NewFlightPage> {
|
||||
|
||||
late Future<List<Drone>> _dronesFuture;
|
||||
late Future<List<Battery>> _batteriesFuture;
|
||||
|
||||
|
||||
Drone? selectedDrone;
|
||||
Battery? selectedBattery;
|
||||
bool isFlightActive = false;
|
||||
@ -30,15 +30,12 @@ class _NewFlightPageState extends State<NewFlightPage> {
|
||||
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<NewFlightPage> {
|
||||
_loadAvailableItems();
|
||||
}
|
||||
|
||||
|
||||
void _loadAvailableItems() {
|
||||
_dronesFuture = DbHelper.instance.getDrones();
|
||||
_batteriesFuture = DbHelper.instance.getBatteries();
|
||||
@ -59,8 +55,6 @@ class _NewFlightPageState extends State<NewFlightPage> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Future<void> _getCurrentLocation() async {
|
||||
if (!mounted) return;
|
||||
|
||||
@ -75,9 +69,7 @@ class _NewFlightPageState extends State<NewFlightPage> {
|
||||
|
||||
serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
||||
if (!serviceEnabled) {
|
||||
if (mounted) {
|
||||
|
||||
}
|
||||
if (mounted) {}
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
useGpsLocation = false;
|
||||
@ -95,9 +87,7 @@ class _NewFlightPageState extends State<NewFlightPage> {
|
||||
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<NewFlightPage> {
|
||||
}
|
||||
|
||||
if (permission == LocationPermission.deniedForever) {
|
||||
if (mounted) {
|
||||
|
||||
}
|
||||
if (mounted) {}
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
useGpsLocation = false;
|
||||
@ -138,7 +126,6 @@ class _NewFlightPageState extends State<NewFlightPage> {
|
||||
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<NewFlightPage> {
|
||||
}
|
||||
});
|
||||
}
|
||||
if (mounted) {
|
||||
|
||||
}
|
||||
if (mounted) {}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
|
||||
}
|
||||
if (mounted) {}
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
useGpsLocation = false;
|
||||
@ -169,12 +152,10 @@ class _NewFlightPageState extends State<NewFlightPage> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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<NewFlightPage> {
|
||||
});
|
||||
|
||||
_getCurrentLocation().then((_) {
|
||||
|
||||
if (useGpsLocation && currentPosition == null) {
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -201,7 +179,6 @@ class _NewFlightPageState extends State<NewFlightPage> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _proceedToStartFlight() {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
@ -217,26 +194,21 @@ class _NewFlightPageState extends State<NewFlightPage> {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
Future<void> _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<NewFlightPage> {
|
||||
);
|
||||
|
||||
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<NewFlightPage> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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<NewFlightPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final colorProvider = Provider.of<ColorProvider>(context);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
@ -300,7 +266,6 @@ class _NewFlightPageState extends State<NewFlightPage> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
|
||||
Text(
|
||||
l10n.chooseDrone,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
@ -347,7 +312,7 @@ class _NewFlightPageState extends State<NewFlightPage> {
|
||||
items: drones.map<DropdownMenuItem<Drone>>((Drone drone) {
|
||||
return DropdownMenuItem<Drone>(
|
||||
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<NewFlightPage> {
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
Text(
|
||||
l10n.chooseBattery,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
@ -405,7 +368,7 @@ class _NewFlightPageState extends State<NewFlightPage> {
|
||||
items: batteries.map<DropdownMenuItem<Battery>>((Battery battery) {
|
||||
return DropdownMenuItem<Battery>(
|
||||
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<NewFlightPage> {
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
Card(
|
||||
margin: const EdgeInsets.only(bottom: 30),
|
||||
child: ListTile(
|
||||
@ -440,11 +401,9 @@ class _NewFlightPageState extends State<NewFlightPage> {
|
||||
},
|
||||
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<NewFlightPage> {
|
||||
],
|
||||
),
|
||||
child: ClipRRect(
|
||||
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
child: FlutterMap(
|
||||
mapController: _mapController,
|
||||
@ -496,9 +454,9 @@ class _NewFlightPageState extends State<NewFlightPage> {
|
||||
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<NewFlightPage> {
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
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<NewFlightPage> {
|
||||
: (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),
|
||||
|
||||
@ -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<SettingsPage> {
|
||||
// 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<ColorProvider>(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<ThemeProvider>(context);
|
||||
final colorProvider = Provider.of<ColorProvider>(context);
|
||||
|
||||
// REMOVE THIS LINE:
|
||||
// _pickerColor = colorProvider.accentColor;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).colorScheme.background,
|
||||
@ -104,6 +125,71 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||
],
|
||||
),
|
||||
),
|
||||
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: <Widget>[
|
||||
TextButton(
|
||||
child: Text(l10n.cancel),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: Text(l10n.select),
|
||||
onPressed: () {
|
||||
colorProvider.setAccentColor(_pickerColor);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
31
lib/providers/color_provider.dart
Normal file
31
lib/providers/color_provider.dart
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// providers/theme_provider.dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
104
src/rtimelogo.svg
Normal file
104
src/rtimelogo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 10 KiB |
Reference in New Issue
Block a user