feat: make core pages local-first offline
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:miaoji_zhang/shared/api/api_client.dart';
|
||||
@@ -10,6 +12,7 @@ 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_icons.dart';
|
||||
import 'package:miaoji_zhang/shared/widgets/async_error_view.dart';
|
||||
import 'package:miaoji_zhang/shared/widgets/backend_status_icon.dart';
|
||||
import 'package:miaoji_zhang/features/home/pages/tx_detail_page.dart';
|
||||
import 'package:miaoji_zhang/features/home/pages/ledger_sheet.dart';
|
||||
import 'package:miaoji_zhang/shared/services/shanghai_time.dart';
|
||||
@@ -28,6 +31,7 @@ class HomePageState extends State<HomePage> {
|
||||
bool _loading = true;
|
||||
String? _error;
|
||||
late DateTime _month;
|
||||
int _loadRevision = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -36,7 +40,7 @@ class HomePageState extends State<HomePage> {
|
||||
PublicConfigApi.companionNotifier.addListener(_refreshCompanion);
|
||||
TransactionEvents.revision.addListener(_refreshTransactions);
|
||||
CurrentLedgerStore.instance.addListener(_refreshLedger);
|
||||
refresh();
|
||||
unawaited(refresh());
|
||||
}
|
||||
|
||||
void _refreshCompanion() {
|
||||
@@ -60,33 +64,56 @@ class HomePageState extends State<HomePage> {
|
||||
}
|
||||
|
||||
Future<void> refresh() async {
|
||||
final revision = ++_loadRevision;
|
||||
setState(() {
|
||||
_loading = true;
|
||||
_error = null;
|
||||
});
|
||||
try {
|
||||
await CurrentLedgerStore.instance.ensureLoaded();
|
||||
final results = await Future.wait<dynamic>([
|
||||
TxApi.month(_month.year, _month.month),
|
||||
BudgetApi.get(_month.year, _month.month),
|
||||
]);
|
||||
if (mounted) {
|
||||
await CurrentLedgerStore.instance.loadCached();
|
||||
final localSummary = TxApi.monthLocal(_month.year, _month.month);
|
||||
final localBudgets = BudgetApi.getLocal(_month.year, _month.month);
|
||||
if (mounted && revision == _loadRevision) {
|
||||
setState(() {
|
||||
_summary = results[0] as MonthSummary;
|
||||
_budgets = results[1] as BudgetsData;
|
||||
_summary = localSummary;
|
||||
_budgets = localBudgets;
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
try {
|
||||
final summary = await TxApi.month(_month.year, _month.month);
|
||||
if (mounted) setState(() => _summary = summary);
|
||||
} catch (fallbackError) {
|
||||
if (mounted) {
|
||||
setState(() => _error = apiErrorMessage(fallbackError));
|
||||
}
|
||||
if (mounted && revision == _loadRevision) {
|
||||
setState(() {
|
||||
_error = apiErrorMessage(error);
|
||||
_loading = false;
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
if (mounted) setState(() => _loading = false);
|
||||
return;
|
||||
}
|
||||
|
||||
await Future.wait([
|
||||
() async {
|
||||
try {
|
||||
await CurrentLedgerStore.instance.refreshRemote();
|
||||
} catch (_) {}
|
||||
}(),
|
||||
() async {
|
||||
try {
|
||||
final summary = await TxApi.monthRemote(_month.year, _month.month);
|
||||
if (mounted && revision == _loadRevision) {
|
||||
setState(() => _summary = summary);
|
||||
}
|
||||
} catch (_) {}
|
||||
}(),
|
||||
() async {
|
||||
try {
|
||||
final budgets = await BudgetApi.getRemote(_month.year, _month.month);
|
||||
if (mounted && revision == _loadRevision) {
|
||||
setState(() => _budgets = budgets);
|
||||
}
|
||||
} catch (_) {}
|
||||
}(),
|
||||
]);
|
||||
if (mounted && revision == _loadRevision) {
|
||||
setState(() => _loading = false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,6 +202,7 @@ class HomePageState extends State<HomePage> {
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
BackendStatusIcon(onRetry: refresh),
|
||||
IconButton(
|
||||
icon: AppIcons.icon(
|
||||
AppIcons.search,
|
||||
|
||||
Reference in New Issue
Block a user