抽离 保存弹窗
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 通用带输入框的确认弹窗组件
|
||||
/// [title]:弹窗标题
|
||||
/// [hintText]:输入框提示文字
|
||||
/// [labelText]:输入框标签文字
|
||||
/// [confirmText]:确认按钮文字(默认"保存")
|
||||
/// [cancelText]:取消按钮文字(默认"取消")
|
||||
/// [onConfirm]:确认按钮回调,参数为输入的文本,返回bool表示是否关闭弹窗
|
||||
/// [inputValidator]:输入内容校验器,返回null表示校验通过,返回字符串表示错误提示
|
||||
Future<void> showInputConfirmDialog({
|
||||
required BuildContext context,
|
||||
required String title,
|
||||
required String hintText,
|
||||
String labelText = '',
|
||||
String confirmText = '保存',
|
||||
String cancelText = '取消',
|
||||
required Function(String inputText) onConfirm,
|
||||
String? Function(String inputText)? inputValidator,
|
||||
}) async {
|
||||
// 输入框控制器
|
||||
final TextEditingController _controller = TextEditingController();
|
||||
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(title),
|
||||
content: TextField(
|
||||
controller: _controller,
|
||||
decoration: InputDecoration(
|
||||
hintText: hintText,
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: labelText,
|
||||
),
|
||||
autofocus: true, // 自动聚焦输入框
|
||||
),
|
||||
actions: [
|
||||
// 取消按钮
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(cancelText),
|
||||
),
|
||||
// 确认按钮
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
// 获取输入文本并去空格
|
||||
final String inputText = _controller.text.trim();
|
||||
|
||||
// 1. 执行自定义校验
|
||||
if (inputValidator != null) {
|
||||
final String? errorMsg = inputValidator(inputText);
|
||||
if (errorMsg != null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(errorMsg),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 执行确认回调
|
||||
onConfirm(inputText);
|
||||
|
||||
// 3. 关闭弹窗
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(confirmText),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import 'package:maibu_satabot_v2/features/devices/presentation/bloc/devices_cubi
|
||||
import 'package:maibu_satabot_v2/features/devices/presentation/bloc/devices_state.dart';
|
||||
import 'package:maibu_satabot_v2/features/home/presentation/widgets/BottomDirectionLine.dart';
|
||||
import 'package:maibu_satabot_v2/features/home/presentation/widgets/common/enum.dart';
|
||||
import 'package:maibu_satabot_v2/features/home/presentation/widgets/common/input_confirm_dialog.dart';
|
||||
import 'package:maibu_satabot_v2/features/home/presentation/widgets/common/tracepoint.dart';
|
||||
import 'package:maibu_satabot_v2/features/home/presentation/widgets/map/CenterLocation.dart';
|
||||
import 'package:maibu_satabot_v2/features/home/presentation/widgets/map/HeadingPointer.dart';
|
||||
@@ -64,9 +65,9 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
bool _isRefreshing = false; // 新增:页面刷新状态标志
|
||||
|
||||
final MapController _mapController = MapController();
|
||||
final TextEditingController _plotNameController = TextEditingController();
|
||||
// 初始化轨迹管理器(泛型指定为LatLng)
|
||||
late final TracePoint<PlotPoint> _traceManager;
|
||||
late String workMode = "弓字模式"; // 作业模式:默认值为"弓字模式"
|
||||
|
||||
LatLng? _currentLatLng;
|
||||
StreamSubscription<Position>? _positionSub;
|
||||
@@ -215,65 +216,31 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
}
|
||||
|
||||
void _showSavePlotDialog() {
|
||||
// 清空上次的输入内容
|
||||
_plotNameController.clear();
|
||||
|
||||
// 显示弹窗
|
||||
showDialog(
|
||||
showInputConfirmDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('保存地块'),
|
||||
content: TextField(
|
||||
controller: _plotNameController,
|
||||
decoration: const InputDecoration(
|
||||
hintText: '请输入地块名称(如:北地块、一号田)',
|
||||
border: OutlineInputBorder(),
|
||||
labelText: '地块名称',
|
||||
),
|
||||
title: '保存地块', // 自定义标题
|
||||
hintText: '请输入地块名称(如:北地块、一号田)', // 自定义输入提示
|
||||
labelText: '地块名称', // 自定义输入框标签
|
||||
confirmText: '保存', // 确认按钮文字
|
||||
cancelText: '取消', // 取消按钮文字
|
||||
// 输入校验器(可选)
|
||||
inputValidator: (inputText) {
|
||||
if (inputText.isEmpty) {
|
||||
return '地块名称不能为空!';
|
||||
}
|
||||
if (inputText.length > 20) {
|
||||
return '地块名称不能超过20个字符!';
|
||||
}
|
||||
return null; // 校验通过
|
||||
},
|
||||
onConfirm: (plotName) {
|
||||
_savePlotData(plotName);
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('地块「$plotName」保存成功!'),
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
actions: [
|
||||
// 取消按钮
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // 关闭弹窗
|
||||
},
|
||||
child: const Text('取消'),
|
||||
),
|
||||
// 确认保存按钮
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
// 获取输入的地块名称并去除首尾空格
|
||||
String plotName = _plotNameController.text.trim();
|
||||
|
||||
// 验证输入是否为空
|
||||
if (plotName.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('地块名称不能为空!'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// 执行保存逻辑
|
||||
_savePlotData(plotName);
|
||||
|
||||
// 关闭弹窗
|
||||
Navigator.of(context).pop();
|
||||
|
||||
// 保存成功提示
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('地块「$plotName」保存成功!'),
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Text('保存'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -501,9 +468,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
_positionSub?.cancel();
|
||||
_traceManager.reset();
|
||||
_mapController.dispose();
|
||||
// 修复:_sub 是 non-null 类型,直接 cancel 无需 ?
|
||||
_sub.cancel();
|
||||
_plotNameController.dispose(); // 新增:释放文本控制器资源
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -555,9 +520,13 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
try {
|
||||
final dynamic nestedJsonRaw =
|
||||
selectedPlotPath.jsonData['jsonData'];
|
||||
|
||||
if (nestedJsonRaw != null && nestedJsonRaw is String) {
|
||||
final String nestedJsonStr = nestedJsonRaw;
|
||||
final dynamic parsedJson = jsonDecode(nestedJsonStr);
|
||||
workMode = parsedJson['planModel'] == WorkMode.bow.value
|
||||
? "弓字模式"
|
||||
: "自定义模式";
|
||||
if (parsedJson is Map<String, dynamic>) {
|
||||
final Map<String, dynamic> nestedJson = parsedJson;
|
||||
final dynamic rawPath = nestedJson['path'];
|
||||
@@ -716,19 +685,6 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
String workMode = "未知模式";
|
||||
if (_selectedPlotPath != null) {
|
||||
try {
|
||||
final String nestedJsonStr =
|
||||
_selectedPlotPath!.jsonData['jsonData'] as String;
|
||||
final Map<String, dynamic> nestedJson = jsonDecode(nestedJsonStr);
|
||||
workMode = nestedJson['planModel'] == WorkMode.bow.value
|
||||
? "弓字模式"
|
||||
: "自定义模式";
|
||||
} catch (e) {
|
||||
workMode = "未知模式";
|
||||
}
|
||||
}
|
||||
return Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
|
||||
Reference in New Issue
Block a user