diff --git a/lib/pages/shell/presentations/views/shell_view.dart b/lib/pages/shell/presentations/views/shell_view.dart index 12ad0c2..655d64c 100644 --- a/lib/pages/shell/presentations/views/shell_view.dart +++ b/lib/pages/shell/presentations/views/shell_view.dart @@ -5,7 +5,7 @@ import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_surv import 'package:terepi_seged/services/ntrip_service.dart'; import 'package:terepi_seged/widgets/gnss_status_chip.dart'; import 'package:terepi_seged/widgets/shell_adaptive_appbar.dart'; -import 'package:terepi_seged/widgets/shell_map_appbar.dart'; +import 'package:terepi_seged/widgets/appbar/shell_map_appbar.dart'; import '../../../../widgets/app_drawer.dart'; import '../../../map_survey/presentations/views/map_survey_view.dart'; diff --git a/lib/widgets/appbar/fix_chip.dart b/lib/widgets/appbar/fix_chip.dart new file mode 100644 index 0000000..1854d9c --- /dev/null +++ b/lib/widgets/appbar/fix_chip.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +class FixChip extends StatelessWidget { + final String label; + final Color color; + + const FixChip({ + required this.label, + required this.color, + }); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 2), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(999), + border: Border.all(color: color), + color: color.withOpacity(0.12), + ), + child: Text( + label, + style: Theme.of(context).textTheme.labelSmall?.copyWith( + color: color, + fontWeight: FontWeight.w800, + ), + ), + ); + } +} diff --git a/lib/widgets/appbar/gnss_status_strip.dart b/lib/widgets/appbar/gnss_status_strip.dart new file mode 100644 index 0000000..bc82043 --- /dev/null +++ b/lib/widgets/appbar/gnss_status_strip.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart'; +import 'package:terepi_seged/services/gnss/gnss_service.dart'; + +import 'fix_chip.dart'; +import 'mini_status_value.dart'; +import 'satellite_mini_value.dart'; + +class GnssStatusStrip extends StatelessWidget { + final MapSurveyController controller; + + const GnssStatusStrip({ + required this.controller, + }); + + @override + Widget build(BuildContext context) { + final colorScheme = Theme.of(context).colorScheme; + + return Obx(() { + return Container( + height: 28, + padding: const EdgeInsets.symmetric(horizontal: 10), + decoration: BoxDecoration( + color: colorScheme.surfaceContainerHighest.withOpacity(0.75), + border: Border( + top: BorderSide( + color: colorScheme.outlineVariant.withOpacity(0.6), + ), + ), + ), + child: Row( + children: [ + MiniStatusValue( + label: 'H', + value: controller.horizontalAccuracyText, + //color: controller.horizontalAccuracyColor(context), + color: Colors.green, + ), + const SizedBox(width: 10), + MiniStatusValue( + label: 'V', + value: controller.verticalAccuracyText, + //color: controller.verticalAccuracyColor(context), + color: Colors.green, + ), + const Spacer(), + FixChip( + //label: controller.fixLabel, // GPS, DGPS, FLOAT, FIX + //color: controller.fixColor(context), + label: 'GPS', + color: Colors.green), + const SizedBox(width: 8), + SatelliteMiniValue( + used: GnssService.to.totalUsedSatellites, + inView: GnssService.to.totalVisibleSatellites, + //onTap: controller.showGnssSkyPlotSheet, + onTap: () {}, + ), + ], + ), + ); + }); + } +} diff --git a/lib/widgets/appbar/mini_status_value.dart b/lib/widgets/appbar/mini_status_value.dart new file mode 100644 index 0000000..b8c1724 --- /dev/null +++ b/lib/widgets/appbar/mini_status_value.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; + +class MiniStatusValue extends StatelessWidget { + final String label; + final String value; + final Color color; + + const MiniStatusValue({ + required this.label, + required this.value, + required this.color, + }); + + @override + Widget build(BuildContext context) { + return RichText( + text: TextSpan( + style: Theme.of(context).textTheme.labelMedium, + children: [ + TextSpan( + text: '$label ', + style: TextStyle( + color: Theme.of(context).colorScheme.onSurfaceVariant, + fontWeight: FontWeight.w600, + ), + ), + TextSpan( + text: value, + style: TextStyle( + color: color, + fontWeight: FontWeight.w800, + ), + ), + ], + ), + ); + } +} diff --git a/lib/widgets/appbar/satellite_mini_value.dart b/lib/widgets/appbar/satellite_mini_value.dart new file mode 100644 index 0000000..b3c4499 --- /dev/null +++ b/lib/widgets/appbar/satellite_mini_value.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; + +class SatelliteMiniValue extends StatelessWidget { + final int used; + final int inView; + final VoidCallback onTap; + + const SatelliteMiniValue({ + required this.used, + required this.inView, + required this.onTap, + }); + + @override + Widget build(BuildContext context) { + return InkWell( + borderRadius: BorderRadius.circular(999), + onTap: onTap, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.satellite_alt, size: 15), + const SizedBox(width: 4), + Text( + '$used/$inView', + style: Theme.of(context).textTheme.labelMedium?.copyWith( + fontWeight: FontWeight.w800, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/widgets/appbar/shell_map_appbar.dart b/lib/widgets/appbar/shell_map_appbar.dart new file mode 100644 index 0000000..9de0af1 --- /dev/null +++ b/lib/widgets/appbar/shell_map_appbar.dart @@ -0,0 +1,161 @@ +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/pages/tracking/presentation/controllers/tracking_controller.dart'; +import 'package:terepi_seged/services/gnss/gnss_service.dart'; +import 'package:terepi_seged/services/ntrip_service.dart'; +import 'package:terepi_seged/widgets/appbar/gnss_status_strip.dart'; +import 'package:terepi_seged/widgets/gnss_status_chip.dart'; +import 'package:terepi_seged/widgets/map_mode_menu_anchor.dart'; + +import '../tracking/tracking_sheet.dart'; + +class ShellMapAppBar extends StatelessWidget implements PreferredSizeWidget { + final MapSurveyController controller; + + const ShellMapAppBar({ + super.key, + required this.controller, + }); + + @override + Size get preferredSize => const Size.fromHeight(72); + + @override + Widget build(BuildContext context) { + return AppBar( + toolbarHeight: 50, + automaticallyImplyLeading: false, + //leadingWidth: 44, + titleSpacing: 0, + leading: Builder(builder: (context) { + return IconButton( + //padding: EdgeInsets.zero, + visualDensity: VisualDensity.compact, + //constraints: const BoxConstraints(minWidth: 40, minHeight: 40), + icon: const Icon(Icons.menu), + onPressed: () { + Scaffold.of(context).openDrawer(); + }, + ); + }), + title: 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 Icon(Icons.satellite_alt, size: 12), + // SizedBox(width: 2), + // Text( + // '${GnssService.to.totalVisibleSatellites}/${GnssService.to.totalUsedSatellites}', + // style: TextStyle( + // fontSize: 12, + // 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: [ + const GnssIconStatusChip(), + Obx(() { + final isRec = TrackingController.to.isRecording.value; + return Badge( + isLabelVisible: isRec, + label: null, // csak piros pont, szám nélkül + backgroundColor: Colors.red, + child: IconButton( + icon: const Icon(Icons.route_outlined), + tooltip: 'Nyomvonal', + onPressed: () => _openTrackingSheet(context), + ), + ); + }), + 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'), + ), + ]) + ], + bottom: PreferredSize( + preferredSize: const Size.fromHeight(28), + child: GnssStatusStrip(controller: controller))); + } + + 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; + } + + void _openTrackingSheet(BuildContext context) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (_) => const TrackingSheet(), + ); + } +} diff --git a/lib/widgets/shell_map_appbar.dart b/lib/widgets/shell_map_appbar.dart deleted file mode 100644 index a35fdd0..0000000 --- a/lib/widgets/shell_map_appbar.dart +++ /dev/null @@ -1,156 +0,0 @@ -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/pages/tracking/presentation/controllers/tracking_controller.dart'; -import 'package:terepi_seged/services/gnss/gnss_service.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'; - -import 'tracking/tracking_sheet.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 Icon(Icons.satellite_alt, size: 12), - SizedBox(width: 2), - Text( - '${GnssService.to.totalVisibleSatellites}/${GnssService.to.totalUsedSatellites}', - style: TextStyle( - fontSize: 12, - 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: [ - Obx(() { - final isRec = TrackingController.to.isRecording.value; - return Badge( - isLabelVisible: isRec, - label: null, // csak piros pont, szám nélkül - backgroundColor: Colors.red, - child: IconButton( - icon: const Icon(Icons.route_outlined), - tooltip: 'Nyomvonal', - onPressed: () => _openTrackingSheet(context), - ), - ); - }), - 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; - } - - void _openTrackingSheet(BuildContext context) { - showModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - builder: (_) => const TrackingSheet(), - ); - } -}