Kitűzés: kényelmi funkciók, pontok listája, export
This commit is contained in:
@@ -0,0 +1,309 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/services/project_service.dart';
|
||||
import 'package:terepi_seged/services/stakeout_export_service.dart';
|
||||
import 'package:terepi_seged/services/stakeout_service.dart';
|
||||
|
||||
import '../../../../models/stakeout_point.dart';
|
||||
|
||||
/// Kitűzési pontlista — bottom sheet a panelről.
|
||||
///
|
||||
/// Szűrés státusz és vonal szerint; soronként távolság a jelenlegi
|
||||
/// pozíciótól, kitűzötteknél az eltérések; koppintás = az legyen a cél;
|
||||
/// menü: kihagyás / visszaállítás / törlés. Fejlécből CSV-export
|
||||
/// (magyar Excel-barát vagy nemzetközi dialektus).
|
||||
class StakeoutListSheet extends StatefulWidget {
|
||||
const StakeoutListSheet({super.key});
|
||||
|
||||
static Future<void> show() {
|
||||
return Get.bottomSheet(
|
||||
const StakeoutListSheet(),
|
||||
isScrollControlled: true,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
State<StakeoutListSheet> createState() => _StakeoutListSheetState();
|
||||
}
|
||||
|
||||
class _StakeoutListSheetState extends State<StakeoutListSheet> {
|
||||
StakeoutStatus? _statusFilter; // null = mind
|
||||
String? _lineFilter; // null = mind
|
||||
|
||||
StakeoutService get svc => StakeoutService.to;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return SafeArea(
|
||||
top: false,
|
||||
child: Material(
|
||||
color: colorScheme.surface,
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(24)),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: MediaQuery.sizeOf(context).height * 0.85),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: 42,
|
||||
height: 4,
|
||||
margin: const EdgeInsets.only(top: 12, bottom: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: colorScheme.outlineVariant,
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
),
|
||||
),
|
||||
|
||||
// ── Fejléc + export ────────────────────────────────
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.list_alt),
|
||||
const SizedBox(width: 8),
|
||||
Obx(() => Text(
|
||||
'Kitűzési pontok (${svc.points.length})',
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
)),
|
||||
const Spacer(),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.ios_share),
|
||||
tooltip: 'Export CSV',
|
||||
onPressed: _exportDialog,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// ── Szűrők ─────────────────────────────────────────
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SegmentedButton<StakeoutStatus?>(
|
||||
segments: const [
|
||||
ButtonSegment(value: null, label: Text('Mind')),
|
||||
ButtonSegment(
|
||||
value: StakeoutStatus.pending,
|
||||
label: Text('Vár')),
|
||||
ButtonSegment(
|
||||
value: StakeoutStatus.staked,
|
||||
label: Text('Kész')),
|
||||
ButtonSegment(
|
||||
value: StakeoutStatus.skipped,
|
||||
label: Text('Kihagyva')),
|
||||
],
|
||||
selected: {_statusFilter},
|
||||
onSelectionChanged: (s) =>
|
||||
setState(() => _statusFilter = s.first),
|
||||
showSelectedIcon: false,
|
||||
style: const ButtonStyle(
|
||||
visualDensity: VisualDensity.compact,
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Obx(() {
|
||||
final lines = svc.lines;
|
||||
if (lines.length <= 1) return const SizedBox.shrink();
|
||||
return DropdownButton<String?>(
|
||||
value: _lineFilter,
|
||||
hint:
|
||||
const Text('Vonal', style: TextStyle(fontSize: 12)),
|
||||
items: [
|
||||
const DropdownMenuItem(
|
||||
value: null, child: Text('Mind')),
|
||||
for (final l in lines)
|
||||
DropdownMenuItem(
|
||||
value: l,
|
||||
child: Text(l.isEmpty ? '(nincs)' : l)),
|
||||
],
|
||||
onChanged: (v) => setState(() => _lineFilter = v),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Divider(height: 12),
|
||||
|
||||
// ── Lista ──────────────────────────────────────────
|
||||
Flexible(
|
||||
child: Obx(() {
|
||||
var rows = svc.points.toList();
|
||||
if (_statusFilter != null) {
|
||||
rows =
|
||||
rows.where((p) => p.status == _statusFilter).toList();
|
||||
}
|
||||
if (_lineFilter != null) {
|
||||
rows = rows.where((p) => p.lineId == _lineFilter).toList();
|
||||
}
|
||||
rows.sort((a, b) => a.lineId != b.lineId
|
||||
? a.lineId.compareTo(b.lineId)
|
||||
: a.station.compareTo(b.station));
|
||||
|
||||
if (rows.isEmpty) {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.all(32),
|
||||
child: Text('Nincs a szűrésnek megfelelő pont.'),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: rows.length,
|
||||
itemBuilder: (context, i) => _row(context, rows[i]),
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _row(BuildContext context, StakeoutPoint p) {
|
||||
final isTarget = svc.target.value?.uuid == p.uuid;
|
||||
|
||||
final (color, icon) = switch (p.status) {
|
||||
StakeoutStatus.staked => (Colors.green, Icons.check_circle),
|
||||
StakeoutStatus.skipped => (Colors.grey, Icons.block),
|
||||
StakeoutStatus.pending => (
|
||||
Colors.deepOrange,
|
||||
Icons.radio_button_unchecked
|
||||
),
|
||||
};
|
||||
|
||||
// Távolság a jelenlegi pozíciótól (ha van).
|
||||
String distText = '';
|
||||
if (svc.hasPosition.value) {
|
||||
final dy = p.planEovY - svc.curEovY.value;
|
||||
final dx = p.planEovX - svc.curEovX.value;
|
||||
final d = math.sqrt(dy * dy + dx * dx);
|
||||
distText = d >= 1000
|
||||
? '${(d / 1000).toStringAsFixed(1)} km'
|
||||
: '${d.toStringAsFixed(0)} m';
|
||||
}
|
||||
|
||||
String cm(double? v) => v == null ? '—' : '${(v * 100).toStringAsFixed(0)}';
|
||||
|
||||
final sub = p.status == StakeoutStatus.staked
|
||||
? 'in ${cm(p.devInline)} · cross ${cm(p.devCrossline)}'
|
||||
'${p.devDz != null ? ' · dZ ${cm(p.devDz)}' : ''} cm'
|
||||
: [
|
||||
if (distText.isNotEmpty) distText,
|
||||
if (p.isOffset) 'eltolt (${p.offsetDist?.toStringAsFixed(1)} m)',
|
||||
].join(' · ');
|
||||
|
||||
return ListTile(
|
||||
dense: true,
|
||||
selected: isTarget,
|
||||
leading: Icon(icon, color: color, size: 20),
|
||||
title: Text(p.displayId,
|
||||
style: TextStyle(
|
||||
fontWeight: isTarget ? FontWeight.w700 : FontWeight.w500)),
|
||||
subtitle:
|
||||
sub.isEmpty ? null : Text(sub, style: const TextStyle(fontSize: 11)),
|
||||
onTap: () {
|
||||
svc.setTarget(p);
|
||||
Get.back();
|
||||
},
|
||||
trailing: PopupMenuButton<String>(
|
||||
onSelected: (a) async {
|
||||
switch (a) {
|
||||
case 'target':
|
||||
svc.setTarget(p);
|
||||
Get.back();
|
||||
case 'skip':
|
||||
await svc.setPointStatus(p, StakeoutStatus.skipped);
|
||||
case 'restore':
|
||||
await svc.setPointStatus(p, StakeoutStatus.pending);
|
||||
case 'delete':
|
||||
final ok = await Get.dialog<bool>(AlertDialog(
|
||||
title: const Text('Pont törlése'),
|
||||
content: Text('${p.displayId} törlése a kitűzési listából?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Get.back(result: false),
|
||||
child: const Text('Mégse')),
|
||||
FilledButton(
|
||||
onPressed: () => Get.back(result: true),
|
||||
child: const Text('Törlés')),
|
||||
],
|
||||
));
|
||||
if (ok == true) await svc.deletePoint(p);
|
||||
}
|
||||
},
|
||||
itemBuilder: (_) => [
|
||||
const PopupMenuItem(value: 'target', child: Text('Ez legyen a cél')),
|
||||
if (p.status != StakeoutStatus.skipped)
|
||||
const PopupMenuItem(value: 'skip', child: Text('Kihagyás')),
|
||||
if (p.status != StakeoutStatus.pending)
|
||||
const PopupMenuItem(
|
||||
value: 'restore', child: Text('Visszaállítás várakozóra')),
|
||||
const PopupMenuItem(value: 'delete', child: Text('Törlés')),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// ── Export dialógus ────────────────────────────────────────────
|
||||
|
||||
Future<void> _exportDialog() async {
|
||||
final hungarian = true.obs;
|
||||
final stakedOnly = false.obs;
|
||||
|
||||
await Get.dialog(AlertDialog(
|
||||
title: const Text('Export CSV'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Obx(() => SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
dense: true,
|
||||
title: const Text('Magyar Excel-formátum'),
|
||||
subtitle: const Text('pontosvessző + tizedesvessző',
|
||||
style: TextStyle(fontSize: 11)),
|
||||
value: hungarian.value,
|
||||
onChanged: (v) => hungarian.value = v,
|
||||
)),
|
||||
Obx(() => SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
dense: true,
|
||||
title: const Text('Csak a kitűzött pontok'),
|
||||
value: stakedOnly.value,
|
||||
onChanged: (v) => stakedOnly.value = v,
|
||||
)),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(onPressed: Get.back, child: const Text('Mégse')),
|
||||
FilledButton.icon(
|
||||
icon: const Icon(Icons.ios_share, size: 18),
|
||||
label: const Text('Export'),
|
||||
onPressed: () async {
|
||||
Get.back();
|
||||
try {
|
||||
await StakeoutExportService.exportAndShare(
|
||||
points: svc.points.toList(),
|
||||
hungarian: hungarian.value,
|
||||
stakedOnly: stakedOnly.value,
|
||||
projectName: ProjectService.to.activeProject.value?.name ?? '',
|
||||
);
|
||||
} catch (e) {
|
||||
Get.snackbar('Export', e.toString(),
|
||||
snackPosition: SnackPosition.BOTTOM);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ import 'dart:ui' show FontFeature;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/map_survey/presentations/widgets/stakeout_list_sheet.dart';
|
||||
import 'package:terepi_seged/pages/map_survey/presentations/widgets/stakeout_settings_dialog.dart';
|
||||
import 'package:terepi_seged/routes/app_pages.dart';
|
||||
import 'package:terepi_seged/services/gnss/gnss_service.dart';
|
||||
import 'package:terepi_seged/services/stakeout_service.dart';
|
||||
@@ -88,7 +90,7 @@ class StakeoutPanel extends StatelessWidget {
|
||||
children: [
|
||||
Text(t.displayId,
|
||||
style: const TextStyle(
|
||||
fontSize: 17, fontWeight: FontWeight.w700)),
|
||||
fontSize: 12, fontWeight: FontWeight.w700)),
|
||||
if (progress != null)
|
||||
Text(
|
||||
'${progress.staked}/${progress.total} kitűzve'
|
||||
@@ -132,6 +134,18 @@ class StakeoutPanel extends StatelessWidget {
|
||||
tooltip: 'Haptikus visszajelzés',
|
||||
onPressed: () => svc.hapticsEnabled.toggle(),
|
||||
)),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.list_alt),
|
||||
visualDensity: VisualDensity.compact,
|
||||
tooltip: 'Pontlista / export',
|
||||
onPressed: () => StakeoutListSheet.show(),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.tune),
|
||||
visualDensity: VisualDensity.compact,
|
||||
tooltip: 'Kitűzési beálítások',
|
||||
onPressed: () => showStakeoutSettingsDialog(),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.upload_file),
|
||||
visualDensity: VisualDensity.compact,
|
||||
@@ -160,28 +174,60 @@ class StakeoutPanel extends StatelessWidget {
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(svc.nearPhase.value ? Icons.map : Icons.adjust),
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: EdgeInsets.zero,
|
||||
constraints:
|
||||
const BoxConstraints(minWidth: 36, minHeight: 36),
|
||||
tooltip:
|
||||
svc.nearPhase.value ? 'Térkép-nézet' : 'Céltábla-nézet',
|
||||
onPressed: svc.togglePhase,
|
||||
),
|
||||
OutlinedButton(
|
||||
onPressed: svc.skipCurrent,
|
||||
style: OutlinedButton.styleFrom(
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
child: const Text('Kihagy'),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const SizedBox(width: 6),
|
||||
OutlinedButton.icon(
|
||||
onPressed: () => _offsetDialog(svc),
|
||||
style: OutlinedButton.styleFrom(
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
icon: const Icon(Icons.alt_route, size: 18),
|
||||
label: const Text('Eltolás'),
|
||||
),
|
||||
const Spacer(),
|
||||
FilledButton.icon(
|
||||
onPressed: () => _store(svc),
|
||||
style: within
|
||||
? FilledButton.styleFrom(backgroundColor: Colors.green)
|
||||
: null,
|
||||
icon: const Icon(Icons.push_pin),
|
||||
label: const Text('Tárol'),
|
||||
const SizedBox(width: 6),
|
||||
// Expanded: a Tárol tölti ki a maradék helyet —
|
||||
// fix-szélesség-összeg helyett, így nincs overflow.
|
||||
Expanded(
|
||||
child: FilledButton.icon(
|
||||
onPressed:
|
||||
svc.isAveraging.value ? null : () => _store(svc),
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: within ? Colors.green : null,
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
),
|
||||
icon: svc.isAveraging.value
|
||||
? const SizedBox(
|
||||
width: 18,
|
||||
height: 18,
|
||||
child: CircularProgressIndicator(strokeWidth: 2))
|
||||
: const Icon(Icons.push_pin, size: 18),
|
||||
label: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Text(svc.isAveraging.value
|
||||
? 'Átlagolás ${svc.averagingElapsed.value}/'
|
||||
'${svc.averagingSeconds.value} s'
|
||||
: 'Tárol'),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -241,6 +287,7 @@ class StakeoutPanel extends StatelessWidget {
|
||||
Future<void> _offsetDialog(StakeoutService svc) async {
|
||||
final distCtrl = TextEditingController(text: '2');
|
||||
final toRight = true.obs;
|
||||
final both = false.obs;
|
||||
|
||||
await Get.dialog(AlertDialog(
|
||||
title: const Text('Eltolt pont (transzverzális)'),
|
||||
@@ -284,6 +331,15 @@ class StakeoutPanel extends StatelessWidget {
|
||||
selected: {toRight.value},
|
||||
onSelectionChanged: (s) => toRight.value = s.first,
|
||||
)),
|
||||
Obx(() => CheckboxListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
dense: true,
|
||||
title: const Text('Pár létrehozása (bal ÉS jobb)'),
|
||||
subtitle: const Text('az akadály két oldalára',
|
||||
style: TextStyle(fontSize: 11)),
|
||||
value: both.value,
|
||||
onChanged: (v) => both.value = v ?? false,
|
||||
))
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
@@ -292,14 +348,45 @@ class StakeoutPanel extends StatelessWidget {
|
||||
onPressed: () async {
|
||||
final d = double.tryParse(distCtrl.text.replaceAll(',', '.'));
|
||||
if (d == null || d <= 0) return;
|
||||
|
||||
// Megrendelői offset-korlát ellenőrzése (beállításokból).
|
||||
if (svc.maxOffset.value > 0 && d > svc.maxOffset.value) {
|
||||
final ok = await Get.dialog<bool>(AlertDialog(
|
||||
icon: const Icon(Icons.warning_amber, color: Colors.orange),
|
||||
title: const Text('Offset-korlát túllépése'),
|
||||
content: Text('A megadott ${d.toStringAsFixed(1)} m nagyobb '
|
||||
'a beállított max. ${svc.maxOffset.value.toStringAsFixed(1)} m '
|
||||
'crossline eltolásnál.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Get.back(result: false),
|
||||
child: const Text('Mégse')),
|
||||
FilledButton(
|
||||
onPressed: () => Get.back(result: true),
|
||||
child: const Text('Mégis')),
|
||||
],
|
||||
));
|
||||
if (ok != true) return;
|
||||
}
|
||||
|
||||
Get.back();
|
||||
final p = await svc.createOffset(dist: d, toRight: toRight.value);
|
||||
if (p != null) {
|
||||
Get.snackbar(
|
||||
'Eltolt pont létrehozva',
|
||||
'${p.displayId} · ${d.toStringAsFixed(2)} m '
|
||||
'${toRight.value ? 'jobbra' : 'balra'} — ez az új cél.',
|
||||
if (both.value) {
|
||||
// Előbb az ellenoldali, aztán a választott — így a
|
||||
// választott oldal lesz az aktív cél.
|
||||
await svc.createOffset(dist: d, toRight: !toRight.value);
|
||||
await svc.createOffset(dist: d, toRight: toRight.value);
|
||||
Get.snackbar('Eltolt pontpár létrehozva',
|
||||
'±${d.toStringAsFixed(2)} m a vonalra merőlegesen.',
|
||||
snackPosition: SnackPosition.BOTTOM);
|
||||
} else {
|
||||
final p = await svc.createOffset(dist: d, toRight: toRight.value);
|
||||
if (p != null) {
|
||||
Get.snackbar(
|
||||
'Eltolt pont létrehozva',
|
||||
'${p.displayId} · ${d.toStringAsFixed(2)} m '
|
||||
'${toRight.value ? 'jobbra' : 'balra'} — ez az új cél.',
|
||||
snackPosition: SnackPosition.BOTTOM);
|
||||
}
|
||||
}
|
||||
},
|
||||
child: const Text('Létrehozás'),
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../../services/stakeout_service.dart';
|
||||
|
||||
/// Kitűzési beállítások dialógus — a panel fogaskerék-ikonjáról.
|
||||
/// Minden érték a StakeoutService Rx-eiben él, és a service perzisztálja
|
||||
/// (SharedPreferences), így app-újraindítás után is megmaradnak.
|
||||
Future<void> showStakeoutSettingsDialog() async {
|
||||
final svc = StakeoutService.to;
|
||||
|
||||
final tolCtrl = TextEditingController(
|
||||
text: (svc.toleranceXY.value * 100).toStringAsFixed(0));
|
||||
final maxOffCtrl = TextEditingController(
|
||||
text: svc.maxOffset.value > 0
|
||||
? svc.maxOffset.value.toStringAsFixed(1)
|
||||
: '');
|
||||
|
||||
await Get.dialog(AlertDialog(
|
||||
title: const Text('Kitűzési beállítások'),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TextField(
|
||||
controller: tolCtrl,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Tűrés (cm)',
|
||||
helperText: 'A céltábla zöld köre és a "tűrésen belül" jelzés',
|
||||
isDense: true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
const Text('Átlagolás tároláskor',
|
||||
style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600)),
|
||||
const SizedBox(height: 6),
|
||||
Obx(() => SegmentedButton<int>(
|
||||
segments: const [
|
||||
ButtonSegment(value: 0, label: Text('Ki')),
|
||||
ButtonSegment(value: 3, label: Text('3 s')),
|
||||
ButtonSegment(value: 5, label: Text('5 s')),
|
||||
ButtonSegment(value: 10, label: Text('10 s')),
|
||||
],
|
||||
selected: {svc.averagingSeconds.value},
|
||||
onSelectionChanged: (s) => svc.averagingSeconds.value = s.first,
|
||||
showSelectedIcon: false,
|
||||
style: const ButtonStyle(visualDensity: VisualDensity.compact),
|
||||
)),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'Bekapcsolva a "Tárol" a megadott ideig gyűjti és átlagolja '
|
||||
'a pozíciókat — csökkenti a pillanatnyi zaj hatását.',
|
||||
style: TextStyle(fontSize: 11, color: Colors.grey.shade600),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Obx(() => SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
dense: true,
|
||||
title: const Text('Haptikus visszajelzés'),
|
||||
subtitle: const Text('közeledve sűrűsödő rezgés',
|
||||
style: TextStyle(fontSize: 11)),
|
||||
value: svc.hapticsEnabled.value,
|
||||
onChanged: (v) => svc.hapticsEnabled.value = v,
|
||||
)),
|
||||
Obx(() => SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
dense: true,
|
||||
title: const Text('Hangjelzés'),
|
||||
subtitle: const Text('kattanás a pulzusokkal, hang a tűrésnél',
|
||||
style: TextStyle(fontSize: 11)),
|
||||
value: svc.soundEnabled.value,
|
||||
onChanged: (v) => svc.soundEnabled.value = v,
|
||||
)),
|
||||
const SizedBox(height: 6),
|
||||
TextField(
|
||||
controller: maxOffCtrl,
|
||||
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Max. crossline eltolás (m, üres = nincs korlát)',
|
||||
labelStyle: TextStyle(fontSize: 12),
|
||||
helperText: 'A specifikáció szerinti offset-korlát — '
|
||||
'e fölött az eltolás-dialógus figyelmeztet.',
|
||||
helperMaxLines: 2,
|
||||
isDense: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(onPressed: Get.back, child: const Text('Mégse')),
|
||||
FilledButton(
|
||||
onPressed: () async {
|
||||
final tolCm = double.tryParse(tolCtrl.text.replaceAll(',', '.'));
|
||||
if (tolCm != null && tolCm > 0) {
|
||||
svc.toleranceXY.value = tolCm / 100.0;
|
||||
}
|
||||
final maxOff = double.tryParse(maxOffCtrl.text.replaceAll(',', '.'));
|
||||
svc.maxOffset.value = maxOff ?? 0;
|
||||
|
||||
await svc.saveSettings();
|
||||
Get.back();
|
||||
},
|
||||
child: const Text('Mentés'),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
Reference in New Issue
Block a user