import 'package:flutter/material.dart'; import '../../../core/storage/local_storage.dart'; import '../../../models/watermark.dart'; /// 编辑这一张照片的水印内容(时间 / 地址 / 天气 / 温度 / 备注) /// /// 返回 null 表示用户取消了。 Future showWatermarkContentSheet( BuildContext context, { required WatermarkData initial, }) { return showModalBottomSheet( context: context, backgroundColor: Colors.white, isScrollControlled: true, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), builder: (_) => _WatermarkContentSheet(initial: initial), ); } class _WatermarkContentSheet extends StatefulWidget { const _WatermarkContentSheet({required this.initial}); final WatermarkData initial; @override State<_WatermarkContentSheet> createState() => _WatermarkContentSheetState(); } class _WatermarkContentSheetState extends State<_WatermarkContentSheet> { late final TextEditingController _address; late final TextEditingController _weather; late final TextEditingController _temperature; late final TextEditingController _remark; /// 时间可以改 —— 补加水印、或者当时手机时间不对时要靠它 late DateTime _time; /// 常用地址,从 LocalStorage 读(同步可读) late List _addresses; bool _managing = false; @override void initState() { super.initState(); _time = widget.initial.time; _addresses = List.from(LocalStorage.instance.getWatermarkAddresses()); _address = TextEditingController(text: widget.initial.address); _weather = TextEditingController(text: widget.initial.weather); _temperature = TextEditingController(text: widget.initial.temperature); _remark = TextEditingController(text: widget.initial.remark); } @override void dispose() { _address.dispose(); _weather.dispose(); _temperature.dispose(); _remark.dispose(); super.dispose(); } void _submit() { Navigator.of(context).pop( widget.initial.copyWith( time: _time, address: _address.text.trim(), weather: _weather.text.trim(), temperature: _temperature.text.trim(), remark: _remark.text.trim(), ), ); } // ---------------- 时间 ---------------- Future _pickTime() async { final date = await showDatePicker( context: context, initialDate: _time, firstDate: DateTime(2000), lastDate: DateTime(2100), ); if (date == null || !mounted) return; final time = await showTimePicker( context: context, initialTime: TimeOfDay.fromDateTime(_time), ); if (time == null || !mounted) return; setState(() { _time = DateTime(date.year, date.month, date.day, time.hour, time.minute); }); } // ---------------- 常用地址 ---------------- Future _addAddress() async { if (_addresses.length >= LocalStorage.watermarkAddressLimit) return; // 预填当前地址:常见的用法是「改一改然后存成常用」,省得再敲一遍 final text = await _promptAddress(initial: _address.text.trim()); if (text == null || !mounted) return; final next = [..._addresses, text]; await LocalStorage.instance.saveWatermarkAddresses(next); if (!mounted) return; setState(() => _addresses = next); } Future _removeAddress(int index) async { final next = [..._addresses]..removeAt(index); await LocalStorage.instance.saveWatermarkAddresses(next); if (!mounted) return; setState(() { _addresses = next; if (_addresses.isEmpty) _managing = false; }); } Future _promptAddress({String initial = ''}) { final controller = TextEditingController(text: initial); return showDialog( context: context, builder: (dialogContext) => AlertDialog( title: const Text('添加常用地址', style: TextStyle(fontSize: 16)), content: TextField( controller: controller, autofocus: true, maxLines: 2, minLines: 1, decoration: const InputDecoration( hintText: '例如:云南省昆明市五华区…', hintStyle: TextStyle(fontSize: 13, color: Color(0xFFD7CCC8)), ), style: const TextStyle(fontSize: 14), ), actions: [ TextButton( onPressed: () => Navigator.of(dialogContext).pop(), child: const Text('取消', style: TextStyle(color: Color(0xFF8D6E63))), ), TextButton( onPressed: () { final text = controller.text.trim(); Navigator.of(dialogContext).pop(text.isEmpty ? null : text); }, child: const Text('添加', style: TextStyle(color: Color(0xFFC8956E))), ), ], ), ).whenComplete(controller.dispose); } // ---------------- 构建 ---------------- @override Widget build(BuildContext context) { return Padding( // 键盘弹出时把内容顶上去,否则输入框会被挡住 padding: EdgeInsets.only(bottom: MediaQuery.viewInsetsOf(context).bottom), child: SafeArea( child: SingleChildScrollView( padding: const EdgeInsets.fromLTRB(20, 16, 20, 20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ const Center( child: Text( '编辑水印内容', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xFF5D4037), ), ), ), const SizedBox(height: 18), _timeRow(), const SizedBox(height: 16), _quickAddressSection(), const SizedBox(height: 16), _field(label: '地址', controller: _address, hint: '自动定位,也可手改'), _field(label: '天气', controller: _weather, hint: '如:晴'), _field(label: '温度', controller: _temperature, hint: '如:25℃'), _field(label: '备注', controller: _remark, hint: '想写点什么'), const SizedBox(height: 12), Row( children: [ Expanded( child: SizedBox( height: 46, child: OutlinedButton( onPressed: () => Navigator.of(context).pop(), style: OutlinedButton.styleFrom( foregroundColor: const Color(0xFFC8956E), side: const BorderSide(color: Color(0xFFC8956E)), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(23), ), ), child: const Text('取消'), ), ), ), const SizedBox(width: 12), Expanded( child: SizedBox( height: 46, child: FilledButton( onPressed: _submit, style: FilledButton.styleFrom( backgroundColor: const Color(0xFFC8956E), foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(23), ), ), child: const Text('确定'), ), ), ), ], ), ], ), ), ), ); } /// 时间行:点一下弹日期 + 时间选择器 Widget _timeRow() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('时间', style: TextStyle(fontSize: 13, color: Color(0xFF8D6E63))), const SizedBox(height: 6), InkWell( onTap: _pickTime, borderRadius: BorderRadius.circular(10), child: Container( width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 13), decoration: BoxDecoration( color: const Color(0xFFF7F4F1), borderRadius: BorderRadius.circular(10), ), child: Row( children: [ Expanded( child: Text( formatWatermarkTime(_time), style: const TextStyle(fontSize: 14, color: Color(0xFF5D4037)), ), ), const Icon(Icons.event, size: 17, color: Color(0xFFBCAAA4)), ], ), ), ), ], ); } Widget _quickAddressSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Text( '常用地址', style: TextStyle(fontSize: 13, color: Color(0xFF8D6E63)), ), const Spacer(), if (_addresses.isNotEmpty) GestureDetector( onTap: () => setState(() => _managing = !_managing), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2), child: Text( _managing ? '完成' : '管理', style: const TextStyle(fontSize: 12.5, color: Color(0xFFC8956E)), ), ), ), ], ), const SizedBox(height: 8), Wrap( spacing: 8, runSpacing: 8, children: [ for (var i = 0; i < _addresses.length; i++) _addressChip(i, _addresses[i]), if (!_managing && _addresses.length < LocalStorage.watermarkAddressLimit) _addChip(), ], ), if (_addresses.isEmpty && !_managing) const Padding( padding: EdgeInsets.only(top: 2), child: Text( '把常去的地点存下来,以后一键替换', style: TextStyle(fontSize: 11.5, color: Color(0xFFBCAAA4)), ), ), ], ); } Widget _addressChip(int index, String address) { return GestureDetector( // 管理模式下点整体是删除,正常模式点一下填进地址框 onTap: _managing ? () => _removeAddress(index) : () => setState(() => _address.text = address), child: Container( constraints: const BoxConstraints(maxWidth: 210), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 7), decoration: BoxDecoration( color: _managing ? const Color(0xFFFDECEA) : const Color(0xFFFFF3E6), borderRadius: BorderRadius.circular(12), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Flexible( child: Text( address, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 12.5, color: _managing ? const Color(0xFFE53935) : const Color(0xFF8D6E63), ), ), ), if (_managing) ...[ const SizedBox(width: 6), const Icon(Icons.close, size: 14, color: Color(0xFFE53935)), ], ], ), ), ); } Widget _addChip() { return GestureDetector( onTap: _addAddress, child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 7), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all(color: const Color(0xFFE0C9A6)), ), child: const Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.add, size: 14, color: Color(0xFFC8956E)), SizedBox(width: 4), Text( '添加', style: TextStyle(fontSize: 12.5, color: Color(0xFFC8956E)), ), ], ), ), ); } Widget _field({ required String label, required TextEditingController controller, required String hint, }) { return Padding( padding: const EdgeInsets.only(bottom: 14), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: const TextStyle(fontSize: 13, color: Color(0xFF8D6E63)), ), const SizedBox(height: 6), Container( padding: const EdgeInsets.symmetric(horizontal: 14), decoration: BoxDecoration( color: const Color(0xFFF7F4F1), borderRadius: BorderRadius.circular(10), ), child: TextField( controller: controller, style: const TextStyle(fontSize: 14, color: Color(0xFF5D4037)), decoration: InputDecoration( border: InputBorder.none, isDense: true, contentPadding: const EdgeInsets.symmetric(vertical: 13), hintText: hint, hintStyle: const TextStyle(fontSize: 14, color: Color(0xFFD7CCC8)), ), ), ), ], ), ); } }