Files
MoneyMgr/moneymgr_mobile/lib/widgets/synchronize_button.dart
Pierre HUBERT 8db2cf3ece
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Show a message when expenses list is empty
2025-07-17 17:51:13 +02:00

88 lines
2.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:logging/logging.dart';
import 'package:moneymgr_mobile/services/api/api_client.dart';
import 'package:moneymgr_mobile/services/api/files_api.dart';
import 'package:moneymgr_mobile/services/api/inbox_api.dart';
import 'package:moneymgr_mobile/services/storage/expenses.dart';
import 'package:moneymgr_mobile/utils/extensions.dart';
import 'package:moneymgr_mobile/utils/hooks.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'synchronize_button.g.dart';
/// Synchronize expenses list with backend
@riverpod
Future<void> _performSynchronization(Ref ref) async {
final expenses = ref.watch(expensesProvider).requireValue;
final apiService = ref.watch(apiServiceProvider)!;
final list = await expenses.getList();
for (final exp in list) {
// First, upload file
final bytes = await expenses.loadFile(exp);
final file = await apiService.uploadFile(
filename: exp.localFileName,
mimeType: exp.mimeType,
bytes: bytes,
);
// Then, create the inbox entry
await apiService.createInboxEntry(
UpdateInboxEntryRequest(
file_id: file.id,
time: exp.time,
label: exp.label,
amount: -1 * exp.cost,
),
);
// Lastly delete the local expense
ref.watch(expensesProvider).requireValue.deleteExpense(exp);
}
ref.invalidate(expensesProvider);
}
class SynchronizeButton extends HookConsumerWidget {
const SynchronizeButton({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final (:pending, :snapshot, :hasError) = useAsyncTask();
handleSynchronize() async {
try {
await ref.watch(
_performSynchronizationProvider.selectAsync((it) => it),
);
} catch (e, s) {
Logger.root.warning("Failed to synchronize expenses! $e $s");
if (context.mounted) {
context.showTextSnackBar("Failed to synchronize expenses! $e");
}
}
}
return snapshot.connectionState == ConnectionState.waiting
? Padding(
padding: const EdgeInsets.all(12.0),
child: SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(strokeWidth: 2),
),
)
: IconButton(
onPressed: () => pending.value = handleSynchronize(),
style: ButtonStyle(
backgroundColor: hasError
? WidgetStatePropertyAll(Colors.red)
: null,
),
icon: Icon(Icons.sync_rounded),
);
}
}