Add backup and restore functionality for rental data in settings

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-03-20 09:32:02 +01:00
parent df7705a224
commit 477ca0ee07
5 changed files with 155 additions and 12 deletions
+62 -5
View File
@@ -5,7 +5,6 @@ import 'package:flutter/foundation.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';
import 'package:path_provider/path_provider.dart';
import 'package:rental_income_tracker/models/app_settings.dart';
import 'package:rental_income_tracker/models/monthly_rent_record.dart';
import 'package:rental_income_tracker/services/notification_service.dart';
@@ -417,7 +416,7 @@ class RentController extends ChangeNotifier {
}
}
Future<String> exportJson() async {
String _buildBackupJson() {
final records = _records.values.toList()
..sort((a, b) {
final byYear = a.year.compareTo(b.year);
@@ -433,14 +432,72 @@ class RentController extends ChangeNotifier {
'records': records.map((e) => e.toJson()).toList(),
};
final jsonString = const JsonEncoder.withIndent(' ').convert(payload);
final dir = await getApplicationDocumentsDirectory();
return const JsonEncoder.withIndent(' ').convert(payload);
}
Future<String> exportBackupToDirectory(String directoryPath) async {
final jsonString = _buildBackupJson();
final timestamp = DateFormat('yyyyMMdd_HHmmss').format(DateTime.now());
final file = File('${dir.path}/rent_tracker_export_$timestamp.json');
final normalizedDirectory = directoryPath.endsWith(Platform.pathSeparator)
? directoryPath.substring(0, directoryPath.length - 1)
: directoryPath;
final file = File(
'$normalizedDirectory${Platform.pathSeparator}rent_tracker_backup_$timestamp.json',
);
await file.writeAsString(jsonString);
return file.path;
}
Future<void> _restoreFromPayload(Map<String, dynamic> payload) async {
final settingsJson = payload['settings'] as Map<String, dynamic>?;
final recordsJson = payload['records'] as List<dynamic>?;
if (settingsJson == null || recordsJson == null) {
throw StateError('Backup file is missing settings or records.');
}
_settings = AppSettings.fromJson(settingsJson);
final restoredRecords = <String, MonthlyRentRecord>{};
for (final item in recordsJson) {
final record = MonthlyRentRecord.fromJson(item as Map<String, dynamic>);
restoredRecords[record.key] = record;
}
_records = restoredRecords;
await _storageService.saveSettings(_settings);
await _storageService.saveRecords(_records);
await _notificationService.cancelAll();
await _syncNotificationScheduleForCurrentMonth();
notifyListeners();
}
Future<String> importBackupFromFile(String filePath) async {
_errorMessage = null;
_setLoading(true);
try {
final file = File(filePath);
if (!await file.exists()) {
throw StateError('Selected backup file could not be found.');
}
final raw = await file.readAsString();
final payload = jsonDecode(raw) as Map<String, dynamic>;
await _restoreFromPayload(payload);
return file.path;
} catch (err, stackTrace) {
if (kDebugMode) {
debugPrint('[RentController] importBackupFromFile failed: $err');
debugPrint(stackTrace.toString());
}
_errorMessage = err.toString();
rethrow;
} finally {
_setLoading(false);
}
}
List<RentTableRow> buildRowsForSelectedYear() {
final now = DateTime.now();
final maxMonth = _selectedYear < now.year