mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-10 19:27:16 +01:00
sync_settings_ui 0.5.0: BackupSlot.json on data_transfer
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WzxdWXTUM9dpnCS2wtFkx4
This commit is contained in:
parent
254c8ce240
commit
f9899b9c56
1
sync_settings_ui/.gitignore
vendored
1
sync_settings_ui/.gitignore
vendored
@ -4,3 +4,4 @@ build/
|
||||
pubspec.lock
|
||||
coverage/
|
||||
*.iml
|
||||
pubspec_overrides.yaml
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
import 'package:data_transfer_flutter/data_transfer_flutter.dart';
|
||||
|
||||
/// An injectable local export/import delegate for [SyncSettingsScreen]'s
|
||||
/// optional "Backup" section.
|
||||
///
|
||||
/// Deliberately not a shared implementation: the actual export/import format
|
||||
/// differs per app (todo: Markdown notes; home_inventory: inventory export;
|
||||
/// workout_app: a permission-gated `BackupService`), so this package only
|
||||
/// carries the label and the two callbacks. Passing `null` for
|
||||
/// `SyncSettingsScreen.backup` omits the section entirely (diet_guard,
|
||||
/// wake_alarm have no local backup at all).
|
||||
/// The export/import CONTENT differs per app (todo: Markdown notes;
|
||||
/// home_inventory: inventory export; workout_app: a permission-gated
|
||||
/// `BackupService`), so the default constructor only carries the label and
|
||||
/// the two callbacks. Apps whose backup is a JSON file use [BackupSlot.json],
|
||||
/// which adds the shared file plumbing (`data_transfer_flutter`). Passing
|
||||
/// `null` for `SyncSettingsScreen.backup` omits the section entirely
|
||||
/// (diet_guard, wake_alarm have no local backup at all).
|
||||
class BackupSlot {
|
||||
/// Creates a [BackupSlot] labelled [label] (e.g. `'notes'`,
|
||||
/// `'inventory'`), backed by [export] and [import].
|
||||
@ -16,6 +19,28 @@ class BackupSlot {
|
||||
required this.import,
|
||||
});
|
||||
|
||||
/// A slot whose backup is a JSON file, using `data_transfer_flutter`.
|
||||
///
|
||||
/// Export saves `build()` as [fileName] to device storage (system Save-as
|
||||
/// on Android/iOS, a save dialog on desktop, a download on web). Import
|
||||
/// lets the user pick a JSON file and hands the decoded object to
|
||||
/// [restore]; a cancelled picker restores nothing.
|
||||
factory BackupSlot.json({
|
||||
required String label,
|
||||
required String fileName,
|
||||
required Future<Map<String, Object?>> Function() build,
|
||||
required Future<void> Function(Map<String, Object?> json) restore,
|
||||
}) => BackupSlot(
|
||||
label: label,
|
||||
export: () async {
|
||||
await exportJson(fileName: fileName, json: await build());
|
||||
},
|
||||
import: () async {
|
||||
final json = await pickJson();
|
||||
if (json != null) await restore(json);
|
||||
},
|
||||
);
|
||||
|
||||
/// Noun describing what this exports/imports, used in the section's
|
||||
/// button text ("Export $label" / "Import $label").
|
||||
final String label;
|
||||
|
||||
@ -5,7 +5,7 @@ description: >-
|
||||
injected closures -- no keystore or platform plugin access lives in this
|
||||
package itself.
|
||||
publish_to: 'none'
|
||||
version: 0.4.3
|
||||
version: 0.5.0
|
||||
|
||||
environment:
|
||||
sdk: ^3.12.2
|
||||
@ -16,6 +16,11 @@ dependencies:
|
||||
url: https://github.com/kuhyx/utils
|
||||
ref: crdt_sync_dart-v0.11.3
|
||||
path: crdt_sync_dart
|
||||
data_transfer_flutter:
|
||||
git:
|
||||
url: https://github.com/kuhyx/utils
|
||||
ref: data_transfer_flutter-v0.1.0
|
||||
path: data_transfer_flutter
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:data_transfer_flutter/data_transfer_flutter.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:sync_settings_ui/sync_settings_ui.dart';
|
||||
|
||||
@ -16,4 +19,83 @@ void main() {
|
||||
expect(exported, isTrue);
|
||||
expect(imported, isTrue);
|
||||
});
|
||||
|
||||
group('BackupSlot.json', () {
|
||||
late _FakePlatform fake;
|
||||
late DataTransferPlatform original;
|
||||
|
||||
setUp(() {
|
||||
original = DataTransfer.platform;
|
||||
fake = _FakePlatform();
|
||||
DataTransfer.platform = fake;
|
||||
});
|
||||
|
||||
tearDown(() => DataTransfer.platform = original);
|
||||
|
||||
test('export saves the built map under fileName', () async {
|
||||
final slot = BackupSlot.json(
|
||||
label: 'inventory',
|
||||
fileName: 'inv.json',
|
||||
build: () async => {'items': 3},
|
||||
restore: (_) async {},
|
||||
);
|
||||
|
||||
await slot.export();
|
||||
|
||||
expect(fake.saved.single.$1, 'inv.json');
|
||||
expect(jsonDecode(fake.saved.single.$2), {'items': 3});
|
||||
});
|
||||
|
||||
test('import hands the picked map to restore', () async {
|
||||
fake.picked = '{"items":3}';
|
||||
Map<String, Object?>? restored;
|
||||
final slot = BackupSlot.json(
|
||||
label: 'inventory',
|
||||
fileName: 'inv.json',
|
||||
build: () async => {},
|
||||
restore: (json) async => restored = json,
|
||||
);
|
||||
|
||||
await slot.import();
|
||||
|
||||
expect(restored, {'items': 3});
|
||||
});
|
||||
|
||||
test('a cancelled picker restores nothing', () async {
|
||||
var called = false;
|
||||
final slot = BackupSlot.json(
|
||||
label: 'inventory',
|
||||
fileName: 'inv.json',
|
||||
build: () async => {},
|
||||
restore: (_) async => called = true,
|
||||
);
|
||||
|
||||
await slot.import();
|
||||
|
||||
expect(called, isFalse);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class _FakePlatform implements DataTransferPlatform {
|
||||
String? picked;
|
||||
final saved = <(String, String)>[];
|
||||
|
||||
@override
|
||||
Future<bool> saveText({
|
||||
required String fileName,
|
||||
required String text,
|
||||
}) async {
|
||||
saved.add((fileName, text));
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> shareText({
|
||||
required String fileName,
|
||||
required String text,
|
||||
}) async => true;
|
||||
|
||||
@override
|
||||
Future<String?> pickText() async => picked;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user