From 0069dba953d18c5326ac5201258aa496fef79615 Mon Sep 17 00:00:00 2001 From: 240403 <240403@epvc.pt> Date: Thu, 5 Mar 2026 16:39:10 +0000 Subject: [PATCH] correcao de erros no codigo do mapa --- lib/constants/app_strings.dart | 46 ++++++++++++++++++++ lib/main.dart | 25 ++++++----- lib/screens/bluetooth_connection_screen.dart | 27 ++++++------ lib/screens/google_map_screen.dart | 28 ++++++------ 4 files changed, 87 insertions(+), 39 deletions(-) create mode 100644 lib/constants/app_strings.dart diff --git a/lib/constants/app_strings.dart b/lib/constants/app_strings.dart new file mode 100644 index 0000000..7efae11 --- /dev/null +++ b/lib/constants/app_strings.dart @@ -0,0 +1,46 @@ +class AppStrings { + // Main Screen + static const String complete = "COMPLETO"; + static const String steps = "PASSOS"; + static const String bpm = "BPM"; + static const String kcal = "K/CAL"; + static const String mapPreview = "MAPA"; + static const String settings = "Configurações"; + static const String groups = "Grupos"; + static const String history = "Histórico"; + static const String notifications = "Notificações"; + static const String profile = "Perfil"; + + // Bluetooth Screen + static const String bluetoothTitle = "DISPOSITIVOS"; + static const String bluetoothConnect = "CONECTAR BLUETOOTH"; + static const String statusSearching = "STATUS: BUSCANDO..."; + static const String statusReady = "STATUS: PRONTO"; + static const String statusConnected = "STATUS: CONECTADO"; + static const String foundDevices = "Encontrados"; + static const String oneDevice = "1 Dispositivo"; + static const String permissionDenied = "Permissões de Bluetooth negadas."; + static const String turnOnBluetooth = "Ligue o Bluetooth para buscar dispositivos."; + static const String scanError = "Erro ao iniciar scan: "; + static const String stopScanError = "Erro ao parar scan: "; + static const String connectingTo = "Conectando a "; + static const String connectionSuccess = "Conectado com sucesso!"; + static const String connectionError = "Erro ao conectar: "; + static const String unknownDevice = "Dispositivo Desconhecido"; + + // Map Screen + static const String mapTitleTracking = "TRACKING ATIVO"; + static const String mapTitlePlanning = "PLANEJAR TRAJETO"; + static const String mapTitleRunning = "TOUHOU VIVA"; + static const String mapPace = "RITMO"; + static const String mapRoute = "TRAJETO"; + static const String kmhUnit = "KM/H"; + static const String kmUnit = "KM"; + static const String planningInstruction = "Toque para definir Início e Fim"; + static const String btnStop = "PARAR"; + static const String btnSimulate = "SIMULAR"; + static const String btnStartRun = "INICIAR CORRIDA"; + static const String btnStopRun = "PARAR CORRIDA"; + static const String startPoint = "Partida"; + static const String finishPoint = "Chegada"; +} diff --git a/lib/main.dart b/lib/main.dart index 275b9a8..22b5734 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; import 'constants/app_colors.dart'; +import 'constants/app_strings.dart'; import 'screens/google_map_screen.dart'; -import 'screens/bluetooth_connection_screen.dart'; // Importando a nova tela +import 'screens/bluetooth_connection_screen.dart'; void main() { // Ponto de entrada do aplicativo. @@ -99,7 +100,7 @@ class _RunningScreenState extends State ), ), Text( - "COMPLETO", + AppStrings.complete, style: TextStyle( color: Colors.white.withOpacity(0.5), fontSize: 11, @@ -144,7 +145,7 @@ class _RunningScreenState extends State border: Border.all(color: Colors.white.withOpacity(0.1)), ), child: Text( - "${currentDistance.toStringAsFixed(1)} KM | ${targetDistance.toStringAsFixed(1)} KM", + "${currentDistance.toStringAsFixed(1)} ${AppStrings.kmUnit} | ${targetDistance.toStringAsFixed(1)} ${AppStrings.kmUnit}", style: const TextStyle( color: AppColors.white, fontSize: 15, @@ -184,11 +185,11 @@ class _RunningScreenState extends State child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - _buildStatItem(Icons.directions_run_rounded, "3219", "PASSOS"), + _buildStatItem(Icons.directions_run_rounded, "3219", AppStrings.steps), Divider(color: Colors.white.withOpacity(0.1), height: 1), - _buildStatItem(Icons.favorite_rounded, "98", "BPM"), + _buildStatItem(Icons.favorite_rounded, "98", AppStrings.bpm), Divider(color: Colors.white.withOpacity(0.1), height: 1), - _buildStatItem(Icons.local_fire_department_rounded, "480", "K/CAL"), + _buildStatItem(Icons.local_fire_department_rounded, "480", AppStrings.kcal), ], ), ), @@ -243,7 +244,7 @@ class _RunningScreenState extends State top: 12, left: 12, child: Text( - "MAPA", + AppStrings.mapPreview, style: TextStyle( color: Colors.white, fontSize: 10, @@ -287,11 +288,11 @@ class _RunningScreenState extends State child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - _buildMenuButton(Icons.settings_outlined, 'Configurações'), - _buildMenuButton(Icons.group_outlined, 'Grupos'), - _buildMenuButton(Icons.history_rounded, 'Histórico'), - _buildMenuButton(Icons.notifications_none_rounded, 'Notificações', showBadge: true), - _buildMenuButton(Icons.person_outline_rounded, 'Perfil', isAvatar: true), + _buildMenuButton(Icons.settings_outlined, AppStrings.settings), + _buildMenuButton(Icons.group_outlined, AppStrings.groups), + _buildMenuButton(Icons.history_rounded, AppStrings.history), + _buildMenuButton(Icons.notifications_none_rounded, AppStrings.notifications, showBadge: true), + _buildMenuButton(Icons.person_outline_rounded, AppStrings.profile, isAvatar: true), ], ), ), diff --git a/lib/screens/bluetooth_connection_screen.dart b/lib/screens/bluetooth_connection_screen.dart index 92be200..406e3d3 100644 --- a/lib/screens/bluetooth_connection_screen.dart +++ b/lib/screens/bluetooth_connection_screen.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import '../constants/app_colors.dart'; +import '../constants/app_strings.dart'; class BluetoothConnectionScreen extends StatefulWidget { const BluetoothConnectionScreen({super.key}); @@ -63,7 +64,7 @@ class _BluetoothConnectionScreenState extends State { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( - content: Text('Permissões de Bluetooth negadas.'), + content: Text(AppStrings.permissionDenied), behavior: SnackBarBehavior.floating, ), ); @@ -80,7 +81,7 @@ class _BluetoothConnectionScreenState extends State { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( - content: Text('Ligue o Bluetooth para buscar dispositivos.'), + content: Text(AppStrings.turnOnBluetooth), behavior: SnackBarBehavior.floating, ), ); @@ -93,7 +94,7 @@ class _BluetoothConnectionScreenState extends State { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Erro ao iniciar scan: $e'), + content: Text('${AppStrings.scanError}$e'), behavior: SnackBarBehavior.floating, ), ); @@ -108,7 +109,7 @@ class _BluetoothConnectionScreenState extends State { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Erro ao parar scan: $e'), + content: Text('${AppStrings.stopScanError}$e'), behavior: SnackBarBehavior.floating, ), ); @@ -120,7 +121,7 @@ class _BluetoothConnectionScreenState extends State { try { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Conectando a ${device.platformName}...'), + content: Text('${AppStrings.connectingTo}${device.platformName.isEmpty ? AppStrings.unknownDevice : device.platformName}...'), duration: const Duration(seconds: 2), behavior: SnackBarBehavior.floating, ), @@ -135,7 +136,7 @@ class _BluetoothConnectionScreenState extends State { FlutterBluePlus.stopScan(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( - content: Text('Conectado com sucesso!'), + content: Text(AppStrings.connectionSuccess), backgroundColor: Colors.green, behavior: SnackBarBehavior.floating, ), @@ -145,7 +146,7 @@ class _BluetoothConnectionScreenState extends State { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Erro ao conectar: $e'), + content: Text('${AppStrings.connectionError}$e'), backgroundColor: Colors.red, behavior: SnackBarBehavior.floating, ), @@ -169,7 +170,7 @@ class _BluetoothConnectionScreenState extends State { backgroundColor: AppColors.background, appBar: AppBar( title: const Text( - 'DISPOSITIVOS', + AppStrings.bluetoothTitle, style: TextStyle( fontWeight: FontWeight.w900, letterSpacing: 2, @@ -214,8 +215,8 @@ class _BluetoothConnectionScreenState extends State { children: [ Text( _connectedDevice != null - ? 'STATUS: CONECTADO' - : (_isScanning ? 'STATUS: BUSCANDO...' : 'STATUS: PRONTO'), + ? AppStrings.statusConnected + : (_isScanning ? AppStrings.statusSearching : AppStrings.statusReady), style: TextStyle( color: _connectedDevice != null ? Colors.greenAccent : (_isScanning ? AppColors.coral : Colors.white54), fontSize: 10, @@ -226,8 +227,8 @@ class _BluetoothConnectionScreenState extends State { const SizedBox(height: 8), Text( _connectedDevice != null - ? '1 Dispositivo' - : '${_scanResults.length} Encontrados', + ? AppStrings.oneDevice + : '${_scanResults.length} ${AppStrings.foundDevices}', style: const TextStyle( color: Colors.white, fontSize: 22, @@ -289,7 +290,7 @@ class _BluetoothConnectionScreenState extends State { physics: const BouncingScrollPhysics(), itemBuilder: (context, index) { final BluetoothDevice device = _connectedDevice ?? _scanResults[index].device; - final name = device.platformName; + final name = device.platformName.isEmpty ? AppStrings.unknownDevice : device.platformName; return Padding( padding: const EdgeInsets.only(bottom: 18), diff --git a/lib/screens/google_map_screen.dart b/lib/screens/google_map_screen.dart index 506adc5..8e1eb17 100644 --- a/lib/screens/google_map_screen.dart +++ b/lib/screens/google_map_screen.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:geolocator/geolocator.dart'; import '../constants/app_colors.dart'; +import '../constants/app_strings.dart'; class GoogleMapScreen extends StatefulWidget { const GoogleMapScreen({super.key}); @@ -18,17 +19,18 @@ class _GoogleMapScreenState extends State { GoogleMapController? _mapController; StreamSubscription? _positionStreamSubscription; Timer? _simulationTimer; - + // Controle de frequência de atualização para evitar sobrecarga e crashes DateTime? _lastUpdate; - + final List _routePoints = []; final Set _polylines = {}; final Set _markers = {}; - + LatLng? _plannedStart; LatLng? _plannedEnd; bool _isPlanningMode = false; + bool _isRunning = false; double _currentSpeed = 0.0; double _totalDistance = 0.0; @@ -124,7 +126,7 @@ class _GoogleMapScreenState extends State { } } }, onError: (error) { - debugPrint("Erro no GPS: $error"); + debugPrint("${AppStrings.unknownDevice}: $error"); }); } @@ -137,7 +139,7 @@ class _GoogleMapScreenState extends State { _currentSpeed = speed >= 0 ? speed : 0; _routePoints.add(newPoint); _currentPosition = newPoint; - _updateMarkers(); // Agora só atualiza a seta seguidora + _updateMarkers(); if (_routePoints.length > 1) { _polylines.removeWhere((p) => p.polylineId.value == 'route' || p.polylineId.value == 'route_glow'); @@ -166,9 +168,7 @@ class _GoogleMapScreenState extends State { } void _updateMarkers() { - // Remove APENAS o marcador da seta seguidora para evitar duplicidade com o ponto de partida fixo _markers.removeWhere((m) => m.markerId.value == 'follower'); - _markers.add(Marker( markerId: const MarkerId('follower'), position: _currentPosition, @@ -192,17 +192,17 @@ class _GoogleMapScreenState extends State { setState(() { if (_plannedStart == null) { _plannedStart = point; - _markers.add(Marker(markerId: const MarkerId('planned_start'), position: point, icon: _startIcon ?? BitmapDescriptor.defaultMarker, zIndex: 5)); + _markers.add(Marker(markerId: const MarkerId('planned_start'), position: point, icon: _startIcon ?? BitmapDescriptor.defaultMarker, zIndex: 5, infoWindow: const InfoWindow(title: AppStrings.startPoint))); } else if (_plannedEnd == null) { _plannedEnd = point; - _markers.add(Marker(markerId: const MarkerId('planned_end'), position: point, icon: _finishIcon ?? BitmapDescriptor.defaultMarker, zIndex: 5)); + _markers.add(Marker(markerId: const MarkerId('planned_end'), position: point, icon: _finishIcon ?? BitmapDescriptor.defaultMarker, zIndex: 5, infoWindow: const InfoWindow(title: AppStrings.finishPoint))); _polylines.add(Polyline(polylineId: const PolylineId('planned_route'), points: [_plannedStart!, _plannedEnd!], color: Colors.white.withOpacity(0.1), width: 2, zIndex: 1)); } else { _plannedStart = point; _plannedEnd = null; _markers.removeWhere((m) => m.markerId.value.startsWith('planned')); _polylines.removeWhere((p) => p.polylineId.value == 'planned_route'); - _markers.add(Marker(markerId: const MarkerId('planned_start'), position: point, icon: _startIcon ?? BitmapDescriptor.defaultMarker, zIndex: 5)); + _markers.add(Marker(markerId: const MarkerId('planned_start'), position: point, icon: _startIcon ?? BitmapDescriptor.defaultMarker, zIndex: 5, infoWindow: const InfoWindow(title: AppStrings.startPoint))); } }); } @@ -220,7 +220,7 @@ class _GoogleMapScreenState extends State { _totalDistance = 0.0; _currentPosition = _plannedStart ?? _currentPosition; _routePoints.add(_currentPosition); - _updateMarkers(); // Reposiciona a seta no início + _updateMarkers(); }); _simulationTimer = Timer.periodic(const Duration(milliseconds: 100), (timer) { @@ -248,10 +248,10 @@ class _GoogleMapScreenState extends State { Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.background, - appBar: AppBar(title: Text(_isPlanningMode ? 'PLANEJAR ROTA' : 'CORRIDA VIVA', style: const TextStyle(fontWeight: FontWeight.w900, color: Colors.white, letterSpacing: 2)), centerTitle: true, backgroundColor: Colors.transparent, elevation: 0, leading: IconButton(icon: const Icon(Icons.arrow_back_ios_new, color: Colors.white), onPressed: () => Navigator.pop(context)), actions: [IconButton(icon: Icon(_isPlanningMode ? Icons.check_circle_rounded : Icons.add_location_alt_rounded, color: AppColors.coral, size: 30), onPressed: () => setState(() => _isPlanningMode = !_isPlanningMode))]), + appBar: AppBar(title: Text(_isPlanningMode ? AppStrings.mapTitlePlanning : AppStrings.mapTitleRunning, style: const TextStyle(fontWeight: FontWeight.w900, color: Colors.white, letterSpacing: 2)), centerTitle: true, backgroundColor: Colors.transparent, elevation: 0, leading: IconButton(icon: const Icon(Icons.arrow_back_ios_new, color: Colors.white), onPressed: () => Navigator.pop(context)), actions: [IconButton(icon: Icon(_isPlanningMode ? Icons.check_circle_rounded : Icons.add_location_alt_rounded, color: AppColors.coral, size: 30), onPressed: () => setState(() => _isPlanningMode = !_isPlanningMode))]), extendBodyBehindAppBar: true, - body: Stack(children: [Center(child: Container(width: MediaQuery.of(context).size.width * 0.94, height: MediaQuery.of(context).size.height * 0.7, decoration: BoxDecoration(color: AppColors.backgroundGrey, borderRadius: BorderRadius.circular(55), border: Border.all(color: Colors.white.withOpacity(0.1), width: 3), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.7), blurRadius: 50, offset: const Offset(0, 30))]), child: ClipRRect(borderRadius: BorderRadius.circular(52), child: _isLoading ? const Center(child: CircularProgressIndicator(color: AppColors.coral)) : GoogleMap(initialCameraPosition: CameraPosition(target: _currentPosition, zoom: 17.5), onMapCreated: (controller) => _mapController = controller, onTap: _onMapTap, markers: _markers, polylines: _polylines, zoomControlsEnabled: false, myLocationButtonEnabled: false, compassEnabled: false, mapToolbarEnabled: false)))), Positioned(top: 115, left: 45, right: 45, child: Container(padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 25), decoration: BoxDecoration(color: AppColors.background.withOpacity(0.95), borderRadius: BorderRadius.circular(25), border: Border.all(color: Colors.white10), boxShadow: [BoxShadow(color: Colors.black26, blurRadius: 10)]), child: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [_buildStat("RITMO", "${(_currentSpeed * 3.6).toStringAsFixed(1)}", "KM/H"), Container(width: 1, height: 35, color: Colors.white10), _buildStat("TRAJETO", (_totalDistance / 1000).toStringAsFixed(2), "KM")]))), if (_isPlanningMode) Positioned(bottom: 140, left: 60, right: 60, child: Container(padding: const EdgeInsets.all(12), decoration: BoxDecoration(color: Colors.black.withOpacity(0.85), borderRadius: BorderRadius.circular(20), border: Border.all(color: AppColors.coral.withOpacity(0.5))), child: const Text("Toque para definir Início e Fim", textAlign: TextAlign.center, style: TextStyle(color: Colors.white, fontSize: 13, fontWeight: FontWeight.bold))))]), - floatingActionButton: FloatingActionButton.extended(onPressed: _toggleSimulation, label: Text(_isSimulating ? "PARAR" : "INICIAR CORRIDA", style: const TextStyle(fontWeight: FontWeight.w900, letterSpacing: 1.5)), icon: Icon(_isSimulating ? Icons.stop_rounded : Icons.play_arrow_rounded, size: 32), backgroundColor: _isSimulating ? AppColors.coral : Colors.white, foregroundColor: _isSimulating ? Colors.white : AppColors.background, elevation: 15), + body: Stack(children: [Center(child: Container(width: MediaQuery.of(context).size.width * 0.94, height: MediaQuery.of(context).size.height * 0.7, decoration: BoxDecoration(color: AppColors.backgroundGrey, borderRadius: BorderRadius.circular(55), border: Border.all(color: Colors.white.withOpacity(0.1), width: 3), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.7), blurRadius: 50, offset: const Offset(0, 30))]), child: ClipRRect(borderRadius: BorderRadius.circular(52), child: _isLoading ? const Center(child: CircularProgressIndicator(color: AppColors.coral)) : GoogleMap(initialCameraPosition: CameraPosition(target: _currentPosition, zoom: 17.5), onMapCreated: (controller) => _mapController = controller, onTap: _onMapTap, markers: _markers, polylines: _polylines, zoomControlsEnabled: false, myLocationButtonEnabled: false, compassEnabled: false, mapToolbarEnabled: false)))), Positioned(top: 115, left: 45, right: 45, child: Container(padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 25), decoration: BoxDecoration(color: AppColors.background.withOpacity(0.95), borderRadius: BorderRadius.circular(25), border: Border.all(color: Colors.white10), boxShadow: [BoxShadow(color: Colors.black26, blurRadius: 10)]), child: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [_buildStat(AppStrings.mapPace, "${(_currentSpeed * 3.6).toStringAsFixed(1)}", AppStrings.kmhUnit), Container(width: 1, height: 35, color: Colors.white10), _buildStat(AppStrings.mapRoute, (_totalDistance / 1000).toStringAsFixed(2), AppStrings.kmUnit)]))), if (_isPlanningMode) Positioned(bottom: 140, left: 60, right: 60, child: Container(padding: const EdgeInsets.all(12), decoration: BoxDecoration(color: Colors.black.withOpacity(0.85), borderRadius: BorderRadius.circular(20), border: Border.all(color: AppColors.coral.withOpacity(0.5))), child: const Text(AppStrings.planningInstruction, textAlign: TextAlign.center, style: TextStyle(color: Colors.white, fontSize: 13, fontWeight: FontWeight.bold))))]), + floatingActionButton: FloatingActionButton.extended(onPressed: _toggleSimulation, label: Text(_isSimulating ? AppStrings.btnStop : AppStrings.btnStartRun, style: const TextStyle(fontWeight: FontWeight.w900, letterSpacing: 1.5)), icon: Icon(_isSimulating ? Icons.stop_rounded : Icons.play_arrow_rounded, size: 32), backgroundColor: _isSimulating ? AppColors.coral : Colors.white, foregroundColor: _isSimulating ? Colors.white : AppColors.background, elevation: 15), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, ); }