MobilApp/lib/widgets/gnss_status_chip.dart

189 lines
5.7 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../services/gnss/gnss_connection.dart';
import '../services/gnss/gnss_device_service.dart';
import '../services/gnss/gnss_service.dart';
import 'gnss_device_picker_dialog.dart';
/// GNSS kapcsolat + fix minőség chip az AppBar-ban.
///
/// Tapintásra megnyitja az eszközkiválasztó dialógot.
/// Kompakt: csak az AppBar-ban lévő kis helyet foglalja el.
///
/// Állapotok:
/// - Szürke: nincs eszköz kiválasztva
/// - Piros: eszköz kiválasztva, nincs kapcsolat
/// - Narancs: csatlakozva, nincs GPS fix
/// - Sárga: autonóm GPS (quality 1)
/// - Kék: DGPS (quality 2)
/// - Világoszöld: RTK Float (quality 5)
/// - Zöld: RTK Fix (quality 4) ← ideális állapot
class GnssStatusChip extends StatelessWidget {
const GnssStatusChip({super.key});
@override
Widget build(BuildContext context) {
return Obx(() {
final connState = GnssService.to.connectionState.value;
final quality = GnssService.to.gpsQuality.value;
final device = GnssDeviceService.to.selectedDevice.value;
final sats = GnssService.to.satelliteCount.value;
final isConnected = connState == GnssConnectionState.connected;
final isConnecting = connState == GnssConnectionState.connecting;
final color = _chipColor(isConnected, quality);
final label = _chipLabel(connState, quality, device?.name);
return GestureDetector(
onTap: () => GnssDevicePickerDialog.show(),
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: color.withOpacity(0.15),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: color.withOpacity(0.5)),
),
child: Row(mainAxisSize: MainAxisSize.min, children: [
// Állapot ikon
if (isConnecting)
SizedBox(
width: 10,
height: 10,
child: CircularProgressIndicator(
strokeWidth: 1.5,
color: color,
),
)
else
Icon(
_chipIcon(isConnected, quality),
size: 12,
color: color,
),
const SizedBox(width: 4),
// Felirat
Text(
label,
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w600,
color: color,
),
),
// Műholdak száma (csak ha van fix)
if (isConnected && quality > 0) ...[
const SizedBox(width: 4),
Text(
'($sats)',
style: TextStyle(
fontSize: 10,
color: color.withOpacity(0.8),
),
),
],
]),
),
);
});
}
Color _chipColor(bool connected, int quality) {
if (!connected) return Colors.grey;
return switch (quality) {
4 => Colors.greenAccent,
5 => Colors.lightGreen,
2 => Colors.blue,
1 => Colors.orange,
_ => Colors.orange.shade300,
};
}
IconData _chipIcon(bool connected, int quality) {
if (!connected) return Icons.gps_off;
if (quality == 0) return Icons.gps_not_fixed;
return Icons.gps_fixed;
}
String _chipLabel(
GnssConnectionState state, int quality, String? deviceName) {
return switch (state) {
GnssConnectionState.connecting => 'Kapcsolódás...',
GnssConnectionState.disconnected =>
deviceName != null ? 'Nincs kapcsolat' : 'Nincs eszköz',
GnssConnectionState.error => 'Hiba',
GnssConnectionState.connected => switch (quality) {
4 => 'RTK Fix',
5 => 'RTK Float',
2 => 'DGPS',
1 => 'GPS',
_ => 'Fix nélkül',
},
};
}
}
/// NTRIP kapcsolat chip az AppBar-ban.
///
/// Tapintásra az NTRIP beállítások oldalra navigál.
/// Csak akkor látható, ha van kiválasztott GNSS eszköz.
class NtripStatusChip extends StatelessWidget {
/// NTRIP csatlakozva van-e — a controllerből kapja.
final RxBool isConnected;
/// Csatlakozás / leválasztás callback.
final VoidCallback? onToggle;
/// NTRIP beállítások megnyitása.
final VoidCallback? onSettings;
const NtripStatusChip({
super.key,
required this.isConnected,
this.onToggle,
this.onSettings,
});
@override
Widget build(BuildContext context) {
return Obx(() {
final connected = isConnected.value;
final color = connected ? Colors.greenAccent : Colors.grey;
return GestureDetector(
onTap: onToggle,
onLongPress: onSettings,
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: color.withOpacity(0.12),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: color.withOpacity(0.45)),
),
child: Row(mainAxisSize: MainAxisSize.min, children: [
Icon(
Icons.cell_tower,
size: 12,
color: color,
),
const SizedBox(width: 4),
Text(
connected ? 'NTRIP' : 'NTRIP off',
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w600,
color: color,
),
),
]),
),
);
});
}
}