import 'package:flutter/material.dart'; import 'package:miaoji_zhang/shared/api/api_client.dart'; import 'package:miaoji_zhang/shared/api/business_api.dart'; import 'package:miaoji_zhang/shared/services/current_ledger_store.dart'; import 'package:miaoji_zhang/shared/services/transaction_events.dart'; import 'package:miaoji_zhang/shared/theme/app_theme.dart'; import 'package:miaoji_zhang/shared/widgets/category_icon.dart'; import 'package:miaoji_zhang/shared/widgets/app_controls.dart'; import 'package:miaoji_zhang/shared/widgets/backend_status_icon.dart'; class RecycleBinPage extends StatefulWidget { const RecycleBinPage({super.key}); @override State createState() => _RecycleBinPageState(); } class _RecycleBinPageState extends State { List _items = const []; bool _loading = true; int _loadRevision = 0; @override void initState() { super.initState(); _load(); } Future _load() async { final revision = ++_loadRevision; setState(() => _loading = true); try { await CurrentLedgerStore.instance.loadCached(); final cached = TxApi.recycleBinLocal(); if (mounted && revision == _loadRevision) { setState(() { _items = cached; _loading = false; }); } final remote = await TxApi.recycleBinRemote(); if (mounted && revision == _loadRevision) { setState(() => _items = remote); } } catch (error) { if (mounted && revision == _loadRevision && _loading) { setState(() => _loading = false); _showError(error); } } finally { if (mounted && revision == _loadRevision && _loading) { setState(() => _loading = false); } } } Future _restore(TxItem item) async { try { await TxApi.restore(item.id); TransactionEvents.notifyChanged(); await _load(); } catch (error) { if (mounted) _showError(error); } } Future _permanentDelete(TxItem item) async { if (ApiClient.availability.value != BackendAvailability.online) return; final confirmed = await _confirm('永久删除', '永久删除后无法恢复,聊天中的账单卡片会显示为已删除。'); if (!confirmed) return; try { await TxApi.permanentlyDelete(item.id); await _load(); } catch (error) { if (mounted) _showError(error); } } Future _clear() async { if (_items.isEmpty || ApiClient.availability.value != BackendAvailability.online) { return; } final confirmed = await _confirm('清空回收站', '将永久删除当前账本回收站中的全部账单,无法恢复。'); if (!confirmed) return; try { await TxApi.clearRecycleBin(); await _load(); } catch (error) { if (mounted) _showError(error); } } Future _confirm(String title, String message) => showJzConfirmSheet( context, title: title, message: message, confirmLabel: '永久删除', destructive: true, ); Future _showActions(TxItem item) async { final online = ApiClient.availability.value == BackendAvailability.online; final action = await showJzOptionSheet( context, title: item.note ?? item.categoryName, options: [ const JzOption(value: 'restore', label: '恢复账单'), if (online) const JzOption(value: 'delete', label: '永久删除', subtitle: '删除后无法恢复'), ], ); if (action == 'restore') await _restore(item); if (action == 'delete') await _permanentDelete(item); } void _showError(Object error) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text(apiErrorMessage(error)))); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('${CurrentLedgerStore.instance.currentName} · 回收站'), actions: [ BackendStatusIcon(onRetry: _load), ValueListenableBuilder( valueListenable: ApiClient.availability, builder: (context, availability, _) => TextButton( onPressed: _items.isEmpty || availability != BackendAvailability.online ? null : _clear, child: Text('清空'), ), ), ], ), body: _loading ? Center( child: CircularProgressIndicator( color: AppTheme.primary, strokeWidth: 2, ), ) : _items.isEmpty ? Center( child: Text( '回收站暂无账单\n删除的账单会保留 30 天', textAlign: TextAlign.center, style: TextStyle(color: context.jz.text3, height: 1.6), ), ) : ListView.builder( padding: const EdgeInsets.all(16), itemCount: _items.length, itemBuilder: (context, index) { final item = _items[index]; return Card( child: ListTile( leading: CategoryIconBox( iconKey: item.categoryIcon, colorKey: item.categoryColor, ), title: Text(item.note ?? item.categoryName), subtitle: Text( '${item.occurredAt.year}-${item.occurredAt.month.toString().padLeft(2, '0')}-${item.occurredAt.day.toString().padLeft(2, '0')}', ), trailing: IconButton( tooltip: '账单操作', onPressed: () => _showActions(item), icon: Icon(Icons.more_horiz_rounded), ), ), ); }, ), ); } }