feat: make core pages local-first offline
This commit is contained in:
@@ -6,6 +6,7 @@ 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});
|
||||
@@ -17,6 +18,7 @@ class RecycleBinPage extends StatefulWidget {
|
||||
class _RecycleBinPageState extends State<RecycleBinPage> {
|
||||
List<TxItem> _items = const [];
|
||||
bool _loading = true;
|
||||
int _loadRevision = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -25,15 +27,30 @@ class _RecycleBinPageState extends State<RecycleBinPage> {
|
||||
}
|
||||
|
||||
Future<void> _load() async {
|
||||
final revision = ++_loadRevision;
|
||||
setState(() => _loading = true);
|
||||
try {
|
||||
await CurrentLedgerStore.instance.ensureLoaded();
|
||||
final items = await TxApi.recycleBin();
|
||||
if (mounted) setState(() => _items = items);
|
||||
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) _showError(error);
|
||||
if (mounted && revision == _loadRevision && _loading) {
|
||||
setState(() => _loading = false);
|
||||
_showError(error);
|
||||
}
|
||||
} finally {
|
||||
if (mounted) setState(() => _loading = false);
|
||||
if (mounted && revision == _loadRevision && _loading) {
|
||||
setState(() => _loading = false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +65,7 @@ class _RecycleBinPageState extends State<RecycleBinPage> {
|
||||
}
|
||||
|
||||
Future<void> _permanentDelete(TxItem item) async {
|
||||
if (ApiClient.availability.value != BackendAvailability.online) return;
|
||||
final confirmed = await _confirm('永久删除', '永久删除后无法恢复,聊天中的账单卡片会显示为已删除。');
|
||||
if (!confirmed) return;
|
||||
try {
|
||||
@@ -59,7 +77,10 @@ class _RecycleBinPageState extends State<RecycleBinPage> {
|
||||
}
|
||||
|
||||
Future<void> _clear() async {
|
||||
if (_items.isEmpty) return;
|
||||
if (_items.isEmpty ||
|
||||
ApiClient.availability.value != BackendAvailability.online) {
|
||||
return;
|
||||
}
|
||||
final confirmed = await _confirm('清空回收站', '将永久删除当前账本回收站中的全部账单,无法恢复。');
|
||||
if (!confirmed) return;
|
||||
try {
|
||||
@@ -79,12 +100,14 @@ class _RecycleBinPageState extends State<RecycleBinPage> {
|
||||
);
|
||||
|
||||
Future<void> _showActions(TxItem item) async {
|
||||
final online = ApiClient.availability.value == BackendAvailability.online;
|
||||
final action = await showJzOptionSheet<String>(
|
||||
context,
|
||||
title: item.note ?? item.categoryName,
|
||||
options: const [
|
||||
JzOption(value: 'restore', label: '恢复账单'),
|
||||
JzOption(value: 'delete', label: '永久删除', subtitle: '删除后无法恢复'),
|
||||
options: [
|
||||
const JzOption(value: 'restore', label: '恢复账单'),
|
||||
if (online)
|
||||
const JzOption(value: 'delete', label: '永久删除', subtitle: '删除后无法恢复'),
|
||||
],
|
||||
);
|
||||
if (action == 'restore') await _restore(item);
|
||||
@@ -103,9 +126,16 @@ class _RecycleBinPageState extends State<RecycleBinPage> {
|
||||
appBar: AppBar(
|
||||
title: Text('${CurrentLedgerStore.instance.currentName} · 回收站'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: _items.isEmpty ? null : _clear,
|
||||
child: Text('清空'),
|
||||
BackendStatusIcon(onRetry: _load),
|
||||
ValueListenableBuilder<BackendAvailability>(
|
||||
valueListenable: ApiClient.availability,
|
||||
builder: (context, availability, _) => TextButton(
|
||||
onPressed:
|
||||
_items.isEmpty || availability != BackendAvailability.online
|
||||
? null
|
||||
: _clear,
|
||||
child: Text('清空'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user