Merge remote-tracking branch 'origin/main'
This commit is contained in:
46
lib/constants/app_strings.dart
Normal file
46
lib/constants/app_strings.dart
Normal file
@@ -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";
|
||||
}
|
||||
@@ -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<RunningScreen>
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"COMPLETO",
|
||||
AppStrings.complete,
|
||||
style: TextStyle(
|
||||
color: Colors.white.withOpacity(0.5),
|
||||
fontSize: 11,
|
||||
@@ -144,7 +145,7 @@ class _RunningScreenState extends State<RunningScreen>
|
||||
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<RunningScreen>
|
||||
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<RunningScreen>
|
||||
top: 12,
|
||||
left: 12,
|
||||
child: Text(
|
||||
"MAPA",
|
||||
AppStrings.mapPreview,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 10,
|
||||
@@ -287,11 +288,11 @@ class _RunningScreenState extends State<RunningScreen>
|
||||
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),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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<BluetoothConnectionScreen> {
|
||||
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<BluetoothConnectionScreen> {
|
||||
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<BluetoothConnectionScreen> {
|
||||
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<BluetoothConnectionScreen> {
|
||||
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<BluetoothConnectionScreen> {
|
||||
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<BluetoothConnectionScreen> {
|
||||
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<BluetoothConnectionScreen> {
|
||||
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<BluetoothConnectionScreen> {
|
||||
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<BluetoothConnectionScreen> {
|
||||
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<BluetoothConnectionScreen> {
|
||||
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<BluetoothConnectionScreen> {
|
||||
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),
|
||||
|
||||
@@ -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<GoogleMapScreen> {
|
||||
GoogleMapController? _mapController;
|
||||
StreamSubscription<Position>? _positionStreamSubscription;
|
||||
Timer? _simulationTimer;
|
||||
|
||||
|
||||
// Controle de frequência de atualização para evitar sobrecarga e crashes
|
||||
DateTime? _lastUpdate;
|
||||
|
||||
|
||||
final List<LatLng> _routePoints = [];
|
||||
final Set<Polyline> _polylines = {};
|
||||
final Set<Marker> _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<GoogleMapScreen> {
|
||||
}
|
||||
}
|
||||
}, onError: (error) {
|
||||
debugPrint("Erro no GPS: $error");
|
||||
debugPrint("${AppStrings.unknownDevice}: $error");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -137,7 +139,7 @@ class _GoogleMapScreenState extends State<GoogleMapScreen> {
|
||||
_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<GoogleMapScreen> {
|
||||
}
|
||||
|
||||
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<GoogleMapScreen> {
|
||||
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<GoogleMapScreen> {
|
||||
_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<GoogleMapScreen> {
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user