3 Commits

Author SHA1 Message Date
8db2cf3ece Show a message when expenses list is empty
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-07-17 17:51:13 +02:00
e45648e038 Fix: reset editor screen between captures 2025-07-17 17:49:01 +02:00
55144da943 Can upload expenses to server 2025-07-17 17:44:36 +02:00
4 changed files with 53 additions and 2 deletions

View File

@@ -48,6 +48,12 @@ class _ExpensesList extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (list.isEmpty) {
return const Center(
child: Text("There is no entry waiting for upload (yet)"),
);
}
return ListView.builder( return ListView.builder(
itemBuilder: (context, entryNum) { itemBuilder: (context, entryNum) {
final expense = list[entryNum]; final expense = list[entryNum];

View File

@@ -0,0 +1,27 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'api_client.dart';
part 'inbox_api.freezed.dart';
part 'inbox_api.g.dart';
@freezed
abstract class UpdateInboxEntryRequest with _$UpdateInboxEntryRequest {
const factory UpdateInboxEntryRequest({
// ignore: non_constant_identifier_names
required int file_id,
required int time,
required String? label,
required double? amount,
}) = _UpdateInboxEntryRequest;
factory UpdateInboxEntryRequest.fromJson(Map<String, dynamic> json) =>
_$UpdateInboxEntryRequestFromJson(json);
}
extension InboxApi on ApiClient {
/// Create a new inbox entry
Future<void> createInboxEntry(UpdateInboxEntryRequest entry) async {
await execute("/inbox", method: "POST", data: entry.toJson());
}
}

View File

@@ -65,6 +65,11 @@ class ExpenseEditor extends HookConsumerWidget {
time: timeController.value, time: timeController.value,
), ),
); );
// Reset screen after a scan
await pending.value;
labelController.text = "";
costController.text = "";
} }
// Cancel operation // Cancel operation

View File

@@ -3,6 +3,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:moneymgr_mobile/services/api/api_client.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/files_api.dart';
import 'package:moneymgr_mobile/services/api/inbox_api.dart';
import 'package:moneymgr_mobile/services/storage/expenses.dart'; import 'package:moneymgr_mobile/services/storage/expenses.dart';
import 'package:moneymgr_mobile/utils/extensions.dart'; import 'package:moneymgr_mobile/utils/extensions.dart';
import 'package:moneymgr_mobile/utils/hooks.dart'; import 'package:moneymgr_mobile/utils/hooks.dart';
@@ -27,9 +28,21 @@ Future<void> _performSynchronization(Ref ref) async {
bytes: bytes, bytes: bytes,
); );
// TODO continue // Then, create the inbox entry
break; 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 { class SynchronizeButton extends HookConsumerWidget {