Terepbejárás oldalon vonal és terület tulajdonságainak szerkesztése, mentés
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
|
||||
|
||||
class ColorRow extends StatelessWidget {
|
||||
final MapSurveyController ctrl;
|
||||
static const _palette = [
|
||||
Color(0xFF6C63FF),
|
||||
Color(0xFFE74C3C),
|
||||
Color(0xFF27AE60),
|
||||
Color(0xFFE91E8C),
|
||||
Color(0xFFE67E22),
|
||||
Color(0xFF3498DB),
|
||||
Color(0xFF8BC34A),
|
||||
];
|
||||
const ColorRow({required this.ctrl});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Kitöltési szín',
|
||||
style: TextStyle(fontSize: 13, color: Colors.grey.shade600)),
|
||||
const SizedBox(height: 10),
|
||||
Obx(() => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: _palette.map((color) {
|
||||
final sel = ctrl.activeEditColor.value == color;
|
||||
return GestureDetector(
|
||||
onTap: () => ctrl.activeEditColor.value = color,
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 150),
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: sel
|
||||
? Theme.of(context).colorScheme.onSurface
|
||||
: Colors.transparent,
|
||||
width: 3,
|
||||
),
|
||||
boxShadow: sel
|
||||
? [
|
||||
BoxShadow(
|
||||
color: color.withOpacity(0.45),
|
||||
blurRadius: 8,
|
||||
spreadRadius: 2)
|
||||
]
|
||||
: null,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
)),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:terepi_seged/enums/map_edit_tool.dart';
|
||||
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
|
||||
|
||||
class LabelField extends StatefulWidget {
|
||||
final MapSurveyController ctrl;
|
||||
const LabelField({required this.ctrl});
|
||||
|
||||
@override
|
||||
State<LabelField> createState() => LabelFieldState();
|
||||
}
|
||||
|
||||
class LabelFieldState extends State<LabelField> {
|
||||
late final TextEditingController _text;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_text = TextEditingController(text: widget.ctrl.activeEditLabel.value);
|
||||
_text.addListener(() => widget.ctrl.activeEditLabel.value = _text.text);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_text.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final hint = switch (widget.ctrl.activeEditTool.value) {
|
||||
MapEditTool.point => 'Pont neve...',
|
||||
MapEditTool.line => 'Vonal neve...',
|
||||
MapEditTool.polygon => 'Terület neve...',
|
||||
MapEditTool.none => 'Felirat...',
|
||||
};
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Felirat',
|
||||
style: TextStyle(fontSize: 13, color: Colors.grey.shade600)),
|
||||
const SizedBox(height: 6),
|
||||
TextField(
|
||||
controller: _text,
|
||||
decoration: InputDecoration(
|
||||
hintText: hint,
|
||||
filled: true,
|
||||
fillColor: Colors.grey.shade100,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LabeledSlider extends StatelessWidget {
|
||||
final String label;
|
||||
final double value;
|
||||
final double min, max;
|
||||
final int? divisions;
|
||||
final String display;
|
||||
final Color color;
|
||||
final ValueChanged<double> onChanged;
|
||||
const LabeledSlider({
|
||||
required this.label,
|
||||
required this.value,
|
||||
required this.min,
|
||||
required this.max,
|
||||
required this.display,
|
||||
required this.color,
|
||||
required this.onChanged,
|
||||
this.divisions,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Row(children: [
|
||||
SizedBox(
|
||||
width: 90,
|
||||
child: Text(label,
|
||||
style: TextStyle(fontSize: 13, color: Colors.grey.shade600)),
|
||||
),
|
||||
Expanded(
|
||||
child: SliderTheme(
|
||||
data: SliderTheme.of(context).copyWith(
|
||||
activeTrackColor: color,
|
||||
thumbColor: color,
|
||||
overlayColor: color.withOpacity(0.15),
|
||||
inactiveTrackColor: Colors.grey.shade200,
|
||||
trackHeight: 3.0,
|
||||
thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 8),
|
||||
),
|
||||
child: Slider(
|
||||
value: value.clamp(min, max),
|
||||
min: min,
|
||||
max: max,
|
||||
divisions: divisions,
|
||||
onChanged: onChanged,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 48,
|
||||
child: Text(display,
|
||||
textAlign: TextAlign.right,
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontFeatures: [FontFeature.tabularFigures()])),
|
||||
),
|
||||
]);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/enums/map_edit_tool.dart';
|
||||
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
|
||||
|
||||
import 'map_edit_line_or_polygon_drawing_content.dart';
|
||||
import 'map_edit_point_drawing_content.dart';
|
||||
|
||||
class MapEditDrawingToolbar extends StatelessWidget {
|
||||
final MapSurveyController controller;
|
||||
|
||||
const MapEditDrawingToolbar({
|
||||
super.key,
|
||||
required this.controller,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Obx(() {
|
||||
final tool = controller.activeEditTool.value;
|
||||
|
||||
if (tool == MapEditTool.none) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return SafeArea(
|
||||
top: false,
|
||||
minimum: const EdgeInsets.fromLTRB(10, 0, 10, 10),
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Material(
|
||||
elevation: 8,
|
||||
color: Theme.of(context).colorScheme.surface.withOpacity(0.97),
|
||||
borderRadius: BorderRadius.circular(22),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 560,
|
||||
),
|
||||
padding: const EdgeInsets.fromLTRB(10, 8, 10, 8),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(22),
|
||||
border: Border.all(
|
||||
color:
|
||||
Theme.of(context).colorScheme.outline.withOpacity(0.22),
|
||||
),
|
||||
),
|
||||
child: tool == MapEditTool.point
|
||||
? PointDrawingContent(controller: controller)
|
||||
: LineOrPolygonDrawingContent(controller: controller),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/enums/map_edit_tool.dart';
|
||||
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
|
||||
|
||||
import 'map_edit_small_status_chip.dart';
|
||||
import 'map_edit_square_toolbar_button.dart';
|
||||
|
||||
class LineOrPolygonDrawingContent extends StatelessWidget {
|
||||
final MapSurveyController controller;
|
||||
|
||||
const LineOrPolygonDrawingContent({
|
||||
required this.controller,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Obx(() {
|
||||
final pointCount = controller.editorPointCount.value;
|
||||
final canFinish = controller.canFinishGeometry;
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
controller.activeEditToolIcon,
|
||||
size: 20,
|
||||
color: colorScheme.primary,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${controller.activeEditToolTitle} · $pointCount pont',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
),
|
||||
SmallStatusChip(
|
||||
text: _requiredPointText(controller.activeEditTool.value),
|
||||
color: canFinish
|
||||
? colorScheme.primary
|
||||
: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
controller.activeEditToolHint,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
height: 1.15,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
// SquareToolbarButton(
|
||||
// tooltip: 'Utolsó pont törlése',
|
||||
// icon: Icons.undo,
|
||||
// // onPressed: controller.canUndo ? controller.undoLastPoint : null,
|
||||
// onPressed: () {},
|
||||
// ),
|
||||
// const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: controller.cancelEditing,
|
||||
icon: const Icon(Icons.close, size: 18),
|
||||
label: const Text('Mégse'),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: FilledButton.icon(
|
||||
onPressed: canFinish ? controller.finishGeometry : null,
|
||||
icon: const Icon(Icons.check, size: 18),
|
||||
label: Text(controller.finishButtonText),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
String _requiredPointText(MapEditTool tool) {
|
||||
switch (tool) {
|
||||
case MapEditTool.line:
|
||||
return 'min. 2';
|
||||
case MapEditTool.polygon:
|
||||
return 'min. 3';
|
||||
case MapEditTool.point:
|
||||
return '1 pont';
|
||||
case MapEditTool.none:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
|
||||
|
||||
import 'map_edit_small_status_chip.dart';
|
||||
|
||||
class PointDrawingContent extends StatelessWidget {
|
||||
final MapSurveyController controller;
|
||||
|
||||
const PointDrawingContent({
|
||||
required this.controller,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Obx(() {
|
||||
// final hasPoint = controller.draftPoints.isNotEmpty;
|
||||
final hasPoint = true;
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
controller.activeEditToolIcon,
|
||||
size: 20,
|
||||
color: colorScheme.primary,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
hasPoint
|
||||
? 'Pont kiválasztva'
|
||||
: controller.activeEditToolTitle,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (hasPoint)
|
||||
SmallStatusChip(
|
||||
text: '1 pont',
|
||||
color: colorScheme.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
hasPoint
|
||||
? 'A pont helye kijelölve. A mentéshez nyomd meg a Kész gombot.'
|
||||
: controller.activeEditToolHint,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
height: 1.15,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: controller.cancelEditing,
|
||||
icon: const Icon(Icons.close, size: 18),
|
||||
label: const Text('Mégse'),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: OutlinedButton.icon(
|
||||
//onPressed: controller.addPointFromCurrentPosition,
|
||||
onPressed: () {},
|
||||
icon: const Icon(Icons.my_location, size: 18),
|
||||
label: const Text('Saját hely'),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: FilledButton.icon(
|
||||
// onPressed: controller.canFinishGeometry
|
||||
// ? controller.finishGeometry
|
||||
// : null,
|
||||
onPressed: () {},
|
||||
icon: const Icon(Icons.check, size: 18),
|
||||
label: const Text('Kész'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SmallStatusChip extends StatelessWidget {
|
||||
final String text;
|
||||
final Color color;
|
||||
|
||||
const SmallStatusChip({
|
||||
required this.text,
|
||||
required this.color,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 7,
|
||||
vertical: 3,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withOpacity(0.10),
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
border: Border.all(
|
||||
color: color.withOpacity(0.55),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
text,
|
||||
style: Theme.of(context).textTheme.labelSmall?.copyWith(
|
||||
color: color,
|
||||
fontWeight: FontWeight.w800,
|
||||
height: 1.0,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SquareToolbarButton extends StatelessWidget {
|
||||
final String tooltip;
|
||||
final IconData icon;
|
||||
final VoidCallback? onPressed;
|
||||
|
||||
const SquareToolbarButton({
|
||||
required this.tooltip,
|
||||
required this.icon,
|
||||
required this.onPressed,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Tooltip(
|
||||
message: tooltip,
|
||||
child: SizedBox(
|
||||
width: 42,
|
||||
height: 40,
|
||||
child: OutlinedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
padding: EdgeInsets.zero,
|
||||
minimumSize: const Size(42, 40),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
onPressed: onPressed,
|
||||
child: Icon(
|
||||
icon,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/enums/map_edit_tool.dart';
|
||||
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
|
||||
|
||||
import 'map_toolbar_action.dart';
|
||||
import 'map_toolbar_divider.dart';
|
||||
|
||||
class MapEditCompactToolbar extends StatelessWidget {
|
||||
final MapSurveyController controller;
|
||||
|
||||
const MapEditCompactToolbar({
|
||||
super.key,
|
||||
required this.controller,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Obx(() {
|
||||
final activeTool = controller.activeEditTool.value;
|
||||
|
||||
return SafeArea(
|
||||
top: false,
|
||||
minimum: const EdgeInsets.fromLTRB(10, 0, 10, 10),
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Material(
|
||||
elevation: 8,
|
||||
color: Theme.of(context).colorScheme.surface.withOpacity(0.96),
|
||||
borderRadius: BorderRadius.circular(22),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 520,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 6,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(22),
|
||||
border: Border.all(
|
||||
color:
|
||||
Theme.of(context).colorScheme.outline.withOpacity(0.22),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ToolbarAction(
|
||||
icon: Icons.add_location_alt_outlined,
|
||||
label: 'Pont',
|
||||
selected: activeTool == MapEditTool.point,
|
||||
onTap: controller.startPointTool,
|
||||
),
|
||||
ToolbarAction(
|
||||
icon: Icons.polyline_outlined,
|
||||
label: 'Vonal',
|
||||
selected: activeTool == MapEditTool.line,
|
||||
onTap: controller.startLineTool,
|
||||
),
|
||||
ToolbarAction(
|
||||
icon: Icons.border_outer_outlined,
|
||||
label: 'Terület',
|
||||
selected: activeTool == MapEditTool.polygon,
|
||||
onTap: controller.startPolygonTool,
|
||||
),
|
||||
const ToolbarDivider(),
|
||||
ToolbarAction(
|
||||
icon: Icons.list_alt_outlined,
|
||||
label: 'Lista',
|
||||
selected: false,
|
||||
onTap: controller.openFeatureList,
|
||||
),
|
||||
ToolbarAction(
|
||||
icon: Icons.layers_outlined,
|
||||
label: 'Rétegek',
|
||||
selected: false,
|
||||
onTap: controller.openLayerPanel,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:terepi_seged/enums/map_edit_tool.dart';
|
||||
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
|
||||
|
||||
import 'color_row.dart';
|
||||
import 'label_field.dart';
|
||||
import 'opacity_slider.dart';
|
||||
import 'save_sheet_actions.dart';
|
||||
import 'sheet_handle.dart';
|
||||
import 'stroke_slider.dart';
|
||||
|
||||
class MapFeatureSaveSheet extends StatelessWidget {
|
||||
final MapSurveyController ctrl;
|
||||
final ScrollController scrollCtrl;
|
||||
const MapFeatureSaveSheet({
|
||||
required this.ctrl,
|
||||
required this.scrollCtrl,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.15),
|
||||
blurRadius: 16,
|
||||
offset: const Offset(0, -4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: CustomScrollView(
|
||||
controller: scrollCtrl,
|
||||
slivers: [
|
||||
SliverToBoxAdapter(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Handle
|
||||
SheetHandle(),
|
||||
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Stílus',
|
||||
style: TextStyle(
|
||||
fontSize: 18, fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ColorRow(ctrl: ctrl),
|
||||
const SizedBox(height: 18),
|
||||
OpacitySlider(ctrl: ctrl),
|
||||
const SizedBox(height: 10),
|
||||
if (ctrl.activeEditTool.value != MapEditTool.point) ...[
|
||||
StrokeSlider(ctrl: ctrl),
|
||||
const SizedBox(height: 10),
|
||||
],
|
||||
LabelField(ctrl: ctrl),
|
||||
const SizedBox(height: 24),
|
||||
SaveSheetActions(ctrl: ctrl),
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).padding.bottom + 12),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ToolbarAction extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final String label;
|
||||
final bool selected;
|
||||
final VoidCallback onTap;
|
||||
|
||||
const ToolbarAction({
|
||||
required this.icon,
|
||||
required this.label,
|
||||
required this.selected,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
final foreground = selected
|
||||
? colorScheme.onPrimaryContainer
|
||||
: colorScheme.onSurfaceVariant;
|
||||
|
||||
final background = selected
|
||||
? colorScheme.primaryContainer.withOpacity(0.90)
|
||||
: Colors.transparent;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 1),
|
||||
child: Tooltip(
|
||||
message: label,
|
||||
waitDuration: const Duration(milliseconds: 500),
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
onTap: onTap,
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 160),
|
||||
curve: Curves.easeOut,
|
||||
width: 58,
|
||||
height: 48,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: background,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: selected
|
||||
? Border.all(
|
||||
color: colorScheme.primary.withOpacity(0.35),
|
||||
width: 1,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
size: 21,
|
||||
color: foreground,
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
label,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.labelSmall?.copyWith(
|
||||
color: foreground,
|
||||
fontWeight:
|
||||
selected ? FontWeight.w800 : FontWeight.w600,
|
||||
height: 1.0,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ToolbarDivider extends StatelessWidget {
|
||||
const ToolbarDivider();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: 1,
|
||||
height: 32,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 4),
|
||||
color: Theme.of(context).colorScheme.outline.withOpacity(0.22),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
|
||||
|
||||
import 'labeled_slider.dart';
|
||||
|
||||
class OpacitySlider extends StatelessWidget {
|
||||
final MapSurveyController ctrl;
|
||||
const OpacitySlider({required this.ctrl});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Obx(() => LabeledSlider(
|
||||
label: 'Átlátszóság',
|
||||
value: ctrl.activeEditOpacity.value,
|
||||
min: 0.1,
|
||||
max: 1.0,
|
||||
display: '${(ctrl.activeEditOpacity.value * 100).round()}%',
|
||||
color: ctrl.activeEditColor.value,
|
||||
onChanged: (v) => ctrl.activeEditOpacity.value = v,
|
||||
));
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
|
||||
|
||||
class SaveSheetActions extends StatelessWidget {
|
||||
final MapSurveyController ctrl;
|
||||
const SaveSheetActions({required this.ctrl});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(children: [
|
||||
// ← Vissza — bezárja a sheet-et, folytatja a rajzolást
|
||||
Expanded(
|
||||
child: OutlinedButton.icon(
|
||||
style: OutlinedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape:
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||
),
|
||||
icon: const Icon(Icons.arrow_back, size: 18),
|
||||
label: const Text('Vissza'),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
|
||||
// Mentés — végleges mentés, mindkét sheet bezárása
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Obx(() => FilledButton.icon(
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: ctrl.activeEditColor.value,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10)),
|
||||
),
|
||||
icon: const Icon(Icons.check, size: 18),
|
||||
label: const Text(
|
||||
'Mentés',
|
||||
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 15),
|
||||
),
|
||||
onPressed: () async {
|
||||
//Navigator.pop(context); // style sheet bezárás
|
||||
Get.back();
|
||||
await ctrl.finishDraft();
|
||||
},
|
||||
)),
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SheetHandle extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) => Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: 36,
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.withOpacity(0.35),
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
|
||||
|
||||
import 'labeled_slider.dart';
|
||||
|
||||
class StrokeSlider extends StatelessWidget {
|
||||
final MapSurveyController ctrl;
|
||||
const StrokeSlider({required this.ctrl});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Obx(() => LabeledSlider(
|
||||
label: 'Körvonal',
|
||||
value: ctrl.activeEditStrokeWidth.value,
|
||||
min: 0.5,
|
||||
max: 10.0,
|
||||
divisions: 19,
|
||||
display: '${ctrl.activeEditStrokeWidth.value.toStringAsFixed(1)} px',
|
||||
color: ctrl.activeEditColor.value,
|
||||
onChanged: (v) => ctrl.activeEditStrokeWidth.value = v,
|
||||
));
|
||||
}
|
||||
Reference in New Issue
Block a user