diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 9f6f798..7903ec6 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -211,6 +211,31 @@ "description": "Block command action button label" }, + "unblock": "Unblock", + "@unblock": { + "description": "Unblock command action button label" + }, + + "unblockCommandConfirmTitle": "Unblock vehicle?", + "@unblockCommandConfirmTitle": { + "description": "Title for unblock command confirmation dialog" + }, + + "unblockCommandConfirmMessage": "This will resume the engine remotely. Are you sure?", + "@unblockCommandConfirmMessage": { + "description": "Body text for unblock command confirmation dialog" + }, + + "unblockCommandSent": "Unblock command sent", + "@unblockCommandSent": { + "description": "Snackbar message when unblock command is sent" + }, + + "unblockCommandFailed": "Failed to send unblock command", + "@unblockCommandFailed": { + "description": "Snackbar message when unblock command fails" + }, + "locationCopied": "Location copied to clipboard", "@locationCopied": { "description": "Snackbar message when location is copied" diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index cec27c2..5cf82b9 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -77,6 +77,16 @@ "block": "Bloquer", + "unblock": "Débloquer", + + "unblockCommandConfirmTitle": "Débloquer le véhicule ?", + + "unblockCommandConfirmMessage": "Cela relancera le moteur à distance. Êtes-vous sûr ?", + + "unblockCommandSent": "Commande de déblocage envoyée", + + "unblockCommandFailed": "Échec de l'envoi de la commande de déblocage", + "locationCopied": "Emplacement copié dans le presse-papiers", "blockCommandConfirmTitle": "Bloquer le véhicule ?", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 3e286dc..2cff4a3 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -77,6 +77,16 @@ "block": "Bloquear", + "unblock": "Desbloquear", + + "unblockCommandConfirmTitle": "Desbloquear veículo?", + + "unblockCommandConfirmMessage": "Isto irá retomar o motor remotamente. Tem a certeza?", + + "unblockCommandSent": "Comando de desbloqueio enviado", + + "unblockCommandFailed": "Falha ao enviar comando de desbloqueio", + "locationCopied": "Localização copiada para a área de transferência", "blockCommandConfirmTitle": "Bloquear veículo?", diff --git a/lib/map/styles.dart b/lib/map/styles.dart index 42d3688..bd67c46 100644 --- a/lib/map/styles.dart +++ b/lib/map/styles.dart @@ -5,27 +5,27 @@ class MapStyles { static const List configs = [ MapStyleConfig( nameKey: 'roads', - urlTemplate: 'https://mt{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}&scale=2&gl=MA&hl={lang}', + urlTemplate: 'https://mt{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}&gl=MA&hl={lang}', subdomains: ['0', '1', '2', '3'], attribution: '© Google Maps', ), MapStyleConfig( nameKey: 'satellite', - urlTemplate: 'https://mt{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}&scale=2&gl=MA&hl={lang}', + urlTemplate: 'https://mt{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}&gl=MA&hl={lang}', subdomains: ['0', '1', '2', '3'], attribution: '© Google Maps', isDark: true, ), MapStyleConfig( nameKey: 'hybrid', - urlTemplate: 'https://mt{s}.google.com/vt/lyrs=y&x={x}&y={y}&z={z}&scale=2&gl=MA&hl={lang}', + urlTemplate: 'https://mt{s}.google.com/vt/lyrs=y&x={x}&y={y}&z={z}&gl=MA&hl={lang}', subdomains: ['0', '1', '2', '3'], attribution: '© Google Maps', isDark: true, ), MapStyleConfig( nameKey: 'traffic', - urlTemplate: 'https://mt{s}.google.com/vt/lyrs=m,traffic&x={x}&y={y}&z={z}&scale=2&gl=MA&hl={lang}', + urlTemplate: 'https://mt{s}.google.com/vt/lyrs=m,traffic&x={x}&y={y}&z={z}&gl=MA&hl={lang}', subdomains: ['0', '1', '2', '3'], attribution: '© Google Maps', ), diff --git a/lib/widgets/device_detail.dart b/lib/widgets/device_detail.dart index 442600f..ef289a1 100644 --- a/lib/widgets/device_detail.dart +++ b/lib/widgets/device_detail.dart @@ -206,14 +206,17 @@ class DeviceDetail extends StatelessWidget { } } + bool get _isBlocked => position?.attributes?['blocked'] == true; + Future _sendBlockCommand(BuildContext context) async { final l10n = AppLocalizations.of(context)!; + final isBlocked = _isBlocked; final confirmed = await showDialog( context: context, builder: (ctx) => AlertDialog( - title: Text(l10n.blockCommandConfirmTitle), - content: Text(l10n.blockCommandConfirmMessage), + title: Text(isBlocked ? l10n.unblockCommandConfirmTitle : l10n.blockCommandConfirmTitle), + content: Text(isBlocked ? l10n.unblockCommandConfirmMessage : l10n.blockCommandConfirmMessage), actions: [ TextButton( onPressed: () => Navigator.of(ctx).pop(false), @@ -221,7 +224,7 @@ class DeviceDetail extends StatelessWidget { ), TextButton( onPressed: () => Navigator.of(ctx).pop(true), - child: Text(l10n.block), + child: Text(isBlocked ? l10n.unblock : l10n.block), ), ], ), @@ -232,7 +235,7 @@ class DeviceDetail extends StatelessWidget { final canCheck = await auth.canCheckBiometrics || await auth.isDeviceSupported(); if (canCheck) { final authenticated = await auth.authenticate( - localizedReason: 'Authenticate to send the block command', + localizedReason: 'Authenticate to send the ${isBlocked ? 'unblock' : 'block'} command', options: const AuthenticationOptions(biometricOnly: false), ); if (!authenticated) return; @@ -241,22 +244,27 @@ class DeviceDetail extends StatelessWidget { final apiService = ApiService(); try { - final success = await apiService.sendCommand(device.id, 'engineStop'); + final success = await apiService.sendCommand( + device.id, + isBlocked ? 'engineResume' : 'engineStop', + ); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(success ? l10n.blockCommandSent : l10n.blockCommandFailed), + content: Text(isBlocked + ? (success ? l10n.unblockCommandSent : l10n.unblockCommandFailed) + : (success ? l10n.blockCommandSent : l10n.blockCommandFailed)), duration: const Duration(seconds: 2), ), ); } } catch (e) { - dev.log('Error sending block command: $e'); + dev.log('Error sending ${isBlocked ? 'unblock' : 'block'} command: $e'); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(l10n.blockCommandFailed), + content: Text(isBlocked ? l10n.unblockCommandFailed : l10n.blockCommandFailed), duration: const Duration(seconds: 2), ), ); @@ -428,8 +436,8 @@ class DeviceDetail extends StatelessWidget { const SizedBox(width: 12), Expanded( child: _ActionButton( - icon: Icons.lock, - label: l10n.block, + icon: _isBlocked ? Icons.lock_open : Icons.lock, + label: _isBlocked ? l10n.unblock : l10n.block, onPressed: () => _sendBlockCommand(context), ), ), diff --git a/pubspec.yaml b/pubspec.yaml index 666ced3..f01049b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: manager description: "Track Fleet" publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 3.18.8+1 +version: 3.18.9+1 environment: sdk: ^3.9.2 diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index a9ed2a8..0000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:manager/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -}