Új appbar, NtripSettingsSheet
This commit is contained in:
@@ -19,8 +19,8 @@ import 'gnss_device_picker_dialog.dart';
|
||||
/// - 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});
|
||||
class GnssIconStatusChip extends StatelessWidget {
|
||||
const GnssIconStatusChip({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -84,6 +84,61 @@ class GnssStatusChip extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class GnssTextStatusChip extends StatelessWidget {
|
||||
const GnssTextStatusChip({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Obx(() {
|
||||
final connState = GnssService.to.connectionState.value;
|
||||
final quality = GnssService.to.gpsQuality.value;
|
||||
final isConn = connState == GnssConnectionState.connected;
|
||||
final isConnecting = connState == GnssConnectionState.connecting;
|
||||
final color = _chipColor(isConn, quality);
|
||||
|
||||
return isConnecting
|
||||
? Text('')
|
||||
: Text(_chipLabel(connState, quality, ''),
|
||||
style: TextStyle(
|
||||
fontSize: 12, fontWeight: FontWeight.w600, color: color));
|
||||
});
|
||||
}
|
||||
|
||||
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 ? '-----' : 'N-----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.
|
||||
@@ -143,3 +198,38 @@ class NtripStatusChip extends StatelessWidget {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class NtripIconStatusChip 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 NtripIconStatusChip({
|
||||
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: Icon(
|
||||
Icons.cell_tower,
|
||||
color: color,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/enums/map_survey_mode.dart';
|
||||
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
|
||||
import 'package:terepi_seged/pages/shell/presentations/controllers/shell_controller.dart';
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get_state_manager/get_state_manager.dart';
|
||||
import 'package:terepi_seged/enums/map_survey_mode.dart';
|
||||
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
|
||||
|
||||
class MapModeMenuAnchor extends StatelessWidget {
|
||||
final MapSurveyController controller;
|
||||
|
||||
const MapModeMenuAnchor({super.key, required this.controller});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Obx(() {
|
||||
return MenuAnchor(
|
||||
menuChildren: [
|
||||
MenuItemButton(
|
||||
leadingIcon: const Icon(Icons.map),
|
||||
trailingIcon: controller.mode.value == MapSurveyMode.browse
|
||||
? const Icon(Icons.check)
|
||||
: null,
|
||||
onPressed: () => controller.setMode(MapSurveyMode.browse),
|
||||
child: const Text('Térkép')),
|
||||
MenuItemButton(
|
||||
leadingIcon: const Icon(Icons.add_location_alt),
|
||||
trailingIcon: controller.mode.value == MapSurveyMode.measure
|
||||
? const Icon(Icons.check)
|
||||
: null,
|
||||
onPressed: () => controller.setMode(MapSurveyMode.measure),
|
||||
child: const Text('Bemérés')),
|
||||
MenuItemButton(
|
||||
leadingIcon: const Icon(Icons.gps_fixed),
|
||||
trailingIcon: controller.mode.value == MapSurveyMode.stakeout
|
||||
? const Icon(Icons.check)
|
||||
: null,
|
||||
onPressed: () => controller.setMode(MapSurveyMode.stakeout),
|
||||
child: const Text('Kitűzés')),
|
||||
MenuItemButton(
|
||||
leadingIcon: const Icon(Icons.hiking),
|
||||
trailingIcon: controller.mode.value == MapSurveyMode.fieldWalk
|
||||
? const Icon(Icons.check)
|
||||
: null,
|
||||
onPressed: () => controller.setMode(MapSurveyMode.fieldWalk),
|
||||
child: const Text('Bejárás')),
|
||||
MenuItemButton(
|
||||
leadingIcon: const Icon(Icons.route),
|
||||
trailingIcon: controller.mode.value == MapSurveyMode.browse
|
||||
? const Icon(Icons.check)
|
||||
: null,
|
||||
onPressed: () => controller.setMode(MapSurveyMode.browse),
|
||||
child: const Text('Track')),
|
||||
],
|
||||
builder: (context, menuController, child) {
|
||||
return InkWell(
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
onTap: () {
|
||||
if (menuController.isOpen) {
|
||||
menuController.close();
|
||||
} else {
|
||||
menuController.open();
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 4,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(mainAxisSize: MainAxisSize.min, children: [
|
||||
Icon(controller.currentModeIcon, size: 14),
|
||||
const SizedBox(width: 1),
|
||||
Text(controller.currentModeLabel,
|
||||
style: const TextStyle(
|
||||
fontSize: 14, fontWeight: FontWeight.w600)),
|
||||
const Icon(Icons.arrow_drop_down, size: 18),
|
||||
]),
|
||||
Text('Projekt',
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
fontStyle: FontStyle.italic,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: colorScheme.onSurfaceVariant))
|
||||
],
|
||||
)));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:terepi_seged/pages/shell/presentations/controllers/shell_controller.dart';
|
||||
|
||||
class ShellAdaptiveAppBar extends StatelessWidget
|
||||
implements PreferredSizeWidget {
|
||||
final ShellController controller;
|
||||
|
||||
const ShellAdaptiveAppBar({
|
||||
super.key,
|
||||
required this.controller,
|
||||
});
|
||||
|
||||
@override
|
||||
Size get preferredSize => const Size.fromHeight(60);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppBar(
|
||||
title: const Text('Adatook'),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get_state_manager/get_state_manager.dart';
|
||||
import 'package:get/state_manager.dart';
|
||||
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
|
||||
import 'package:terepi_seged/pages/shell/presentations/controllers/shell_controller.dart';
|
||||
import 'package:terepi_seged/services/ntrip_service.dart';
|
||||
import 'package:terepi_seged/widgets/gnss_status_chip.dart';
|
||||
import 'package:terepi_seged/widgets/map_mode_menu_anchor.dart';
|
||||
|
||||
class ShellMapAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
final MapSurveyController controller;
|
||||
|
||||
const ShellMapAppBar({
|
||||
super.key,
|
||||
required this.controller,
|
||||
});
|
||||
|
||||
@override
|
||||
Size get preferredSize => const Size.fromHeight(52);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppBar(
|
||||
toolbarHeight: 60,
|
||||
leadingWidth: 44,
|
||||
titleSpacing: 0,
|
||||
leading: Builder(builder: (context) {
|
||||
return IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(minWidth: 40, minHeight: 40),
|
||||
icon: const Icon(Icons.menu),
|
||||
onPressed: () {
|
||||
Scaffold.of(context).openDrawer();
|
||||
},
|
||||
);
|
||||
}),
|
||||
title: Obx(() {
|
||||
return Row(children: [
|
||||
MapModeMenuAnchor(controller: controller),
|
||||
const SizedBox(width: 2),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Row(children: [
|
||||
const Text('H:', style: TextStyle(fontSize: 12)),
|
||||
SizedBox(width: 2),
|
||||
Text(controller.horizontalAccuracyText,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: _errorColor(max(
|
||||
controller.gpsLatitudeError.value,
|
||||
controller.gpsLongitudeError.value)),
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFeatures: const [FontFeature.tabularFigures()]))
|
||||
]),
|
||||
Row(children: [
|
||||
const Text('V:', style: TextStyle(fontSize: 12)),
|
||||
SizedBox(width: 2),
|
||||
Text(controller.verticalAccuracyText,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color:
|
||||
_errorColor(controller.gpsAltitudeError.value),
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFeatures: const [FontFeature.tabularFigures()]))
|
||||
])
|
||||
]),
|
||||
SizedBox(width: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
GnssTextStatusChip(),
|
||||
Row(children: [
|
||||
const Text('V:', style: TextStyle(fontSize: 12)),
|
||||
SizedBox(width: 2),
|
||||
Text(controller.verticalAccuracyText,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color:
|
||||
_errorColor(controller.gpsAltitudeError.value),
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFeatures: const [FontFeature.tabularFigures()]))
|
||||
])
|
||||
]),
|
||||
const GnssIconStatusChip(),
|
||||
const SizedBox(width: 2),
|
||||
NtripIconStatusChip(
|
||||
isConnected: NtripService.to.isConnected,
|
||||
onToggle: () {
|
||||
NtripService.to.isConnected.value
|
||||
? NtripService.to.disconnect()
|
||||
: NtripService.to.connect();
|
||||
},
|
||||
onSettings: () {
|
||||
HapticFeedback.mediumImpact();
|
||||
controller.openNtripsettings();
|
||||
}),
|
||||
]);
|
||||
}),
|
||||
actions: [
|
||||
PopupMenuButton(
|
||||
tooltip: 'További funkciók',
|
||||
icon: const Icon(Icons.more_vert),
|
||||
onSelected: null,
|
||||
itemBuilder: (context) => const [
|
||||
PopupMenuItem(
|
||||
value: 1,
|
||||
child: Text('Koordináták'),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: 1,
|
||||
child: Text('Rétegek'),
|
||||
),
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
Color _errorColor(double e) {
|
||||
if (e < 0.05) return Colors.greenAccent;
|
||||
if (e < 0.2) return Colors.green;
|
||||
if (e < 1.0) return Colors.orange;
|
||||
return Colors.red;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user