refactor(app,learn): people's files on the device shared in halkyon_app

ADR 0043's recommendation, for Todo's attachments: what Learn had for its
files on the device moves into halkyon_app, unchanged but for its names,
and Learn uses it from there.

- FileCache, DirectoryFileCache (Learn's AssetFileCache): the files by
  their SHA-256 in a folder of the person's, and which wait to be
  uploaded.
- FileServerGateway, ServerpodFileServerGateway (Learn's
  AssetServerGateway): halkyon_base's files endpoint, taking the module's
  caller rather than Learn's client; FileLimitReached, FileRoom.
- Their fakes in halkyon_app's testing: MemoryFileCache,
  FakeFileServerGateway, sha256Of.
- SealedFile: the format every app seals a file in (HLKF, version 1),
  sealing with halkyon_app's ContentCipher; Learn's Privacy seals and
  opens its files with it, for the same context as before, so every file
  sealed so far opens as it did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-11-11 01:17:22 +01:00
commit 5dd7575dd6
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
45 changed files with 272 additions and 235 deletions

View file

@ -3,13 +3,13 @@ import 'dart:developer';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
import 'package:halkyon_app/halkyon_app.dart'
show FileCache, FileLimitReached, FileRoom, FileServerGateway, isSha256;
import 'package:halkyon_core/halkyon_core.dart' import 'package:halkyon_core/halkyon_core.dart'
show CoalescingRunner, SerialQueue; show CoalescingRunner, SerialQueue;
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_file_cache.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_gateway.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_gateway.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_payload.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_payload.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_sealing.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_sealing.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_server_gateway.dart';
import 'package:halkyon_learn_flutter/src/core/asset/model/stored_file.dart'; import 'package:halkyon_learn_flutter/src/core/asset/model/stored_file.dart';
import 'package:halkyon_learn_flutter/src/core/privacy/data/tree_files.dart'; import 'package:halkyon_learn_flutter/src/core/privacy/data/tree_files.dart';
@ -33,8 +33,8 @@ import 'package:halkyon_learn_flutter/src/core/privacy/data/tree_files.dart';
/// trees, is a file per key. /// trees, is a file per key.
class AssetRepository( class AssetRepository(
final AssetGateway _rows, final AssetGateway _rows,
final AssetServerGateway _server, final FileServerGateway _server,
final AssetFileCache _files, final FileCache _files,
final AssetSealing _sealing, { final AssetSealing _sealing, {
Stream<void> uploadTriggers = const Stream.empty(), Stream<void> uploadTriggers = const Stream.empty(),

View file

@ -5,9 +5,7 @@ import 'package:flutter/widgets.dart';
import 'package:halkyon_app/halkyon_app.dart'; import 'package:halkyon_app/halkyon_app.dart';
import 'package:halkyon_learn_client/halkyon_learn_client.dart' import 'package:halkyon_learn_client/halkyon_learn_client.dart'
show Client, PublishRefusal, PublishRefusedException, UuidValue; show Client, PublishRefusal, PublishRefusedException, UuidValue;
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_file_cache.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/serverpod_asset_server_gateway.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/sound_player.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/sound_player.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/sync_asset_gateway.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/sync_asset_gateway.dart';
import 'package:halkyon_learn_flutter/src/core/dependencies/person_dependencies.dart'; import 'package:halkyon_learn_flutter/src/core/dependencies/person_dependencies.dart';
@ -541,8 +539,8 @@ Future<PersonDependencies> _openPersonData(
)..start(sync.synced); )..start(sync.synced);
final assets = AssetRepository( final assets = AssetRepository(
SyncAssetGateway(db, sync, privacy), SyncAssetGateway(db, sync, privacy),
ServerpodAssetServerGateway(client), ServerpodFileServerGateway(client.modules.base),
DirectoryAssetFileCache(Directory(p.join(folder.path, 'files'))), DirectoryFileCache(Directory(p.join(folder.path, 'files'))),
privacy, privacy,
uploadTriggers: sync.synced, uploadTriggers: sync.synced,
filesAllowed: () => sync.filesAllowed, filesAllowed: () => sync.filesAllowed,

View file

@ -2365,63 +2365,21 @@ class Privacy(
? utf8.decode(Uint8List.sublistView(envelope.payload)) ? utf8.decode(Uint8List.sublistView(envelope.payload))
: base64Encode(Uint8List.sublistView(envelope.payload)); : base64Encode(Uint8List.sublistView(envelope.payload));
/// What a sealed file starts with, and its format's version.
static final _fileMagic = utf8.encode('HLKF');
static const _fileVersion = 1;
@override @override
Uint8List sealFile( Uint8List sealFile(
Uint8List plain, { Uint8List plain, {
required String keyId, required String keyId,
required String assetId, required String assetId,
}) { }) => SealedFile.seal(
final sealed = keys.cipher.seal( keys.cipher,
plain, plain,
keyId: keyId, keyId: keyId,
context: _fileContext(assetId), context: _fileContext(assetId),
); );
final id = utf8.encode(keyId);
return Uint8List.fromList([
..._fileMagic,
_fileVersion,
id.length,
...id,
...sealed.nonce,
...sealed.payload,
]);
}
@override @override
Uint8List? openFile(Uint8List sealed, {required String assetId}) { Uint8List? openFile(Uint8List sealed, {required String assetId}) =>
final header = _fileMagic.length + 2; SealedFile.open(keys.cipher, sealed, context: _fileContext(assetId));
if (sealed.length < header ||
!_startsWith(sealed, _fileMagic) ||
sealed[_fileMagic.length] != _fileVersion) {
return null;
}
final idLength = sealed[_fileMagic.length + 1];
const nonceLength = 24;
if (sealed.length < header + idLength + nonceLength) {
return null;
}
final String keyId;
try {
keyId = utf8.decode(
Uint8List.sublistView(sealed, header, header + idLength),
);
} on FormatException {
return null;
}
final nonceAt = header + idLength;
return keys.cipher.unseal(
SealedPayload(
keyId: keyId,
nonce: Uint8List.sublistView(sealed, nonceAt, nonceAt + nonceLength),
payload: Uint8List.sublistView(sealed, nonceAt + nonceLength),
),
context: _fileContext(assetId),
);
}
static List<int> _fileContext(String assetId) => static List<int> _fileContext(String assetId) =>
utf8.encode('asset|$assetId|file'); utf8.encode('asset|$assetId|file');

View file

@ -2,26 +2,26 @@ import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/testing.dart'
show FakeFileServerGateway, MemoryFileCache, sha256Of;
import 'package:halkyon_learn_flutter/src/core/asset/bloc/sound_bloc.dart'; import 'package:halkyon_learn_flutter/src/core/asset/bloc/sound_bloc.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import '../../../support/fake_asset_gateway.dart'; import '../../../support/fake_asset_gateway.dart';
import '../../../support/fake_asset_sealing.dart'; import '../../../support/fake_asset_sealing.dart';
import '../../../support/fake_asset_server_gateway.dart';
import '../../../support/fake_sound_player.dart'; import '../../../support/fake_sound_player.dart';
import '../../../support/memory_asset_file_cache.dart';
void main() { void main() {
late MemoryAssetFileCache files; late MemoryFileCache files;
late AssetRepository assets; late AssetRepository assets;
late FakeSoundPlayer player; late FakeSoundPlayer player;
late String sound; late String sound;
setUp(() async { setUp(() async {
files = MemoryAssetFileCache(); files = MemoryFileCache();
assets = AssetRepository( assets = AssetRepository(
FakeAssetGateway(), FakeAssetGateway(),
FakeAssetServerGateway(), FakeFileServerGateway(),
files, files,
FakeAssetSealing(), FakeAssetSealing(),
); );

View file

@ -3,19 +3,19 @@ import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/testing.dart'
show FakeFileServerGateway, MemoryFileCache, sha256Of;
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_payload.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_payload.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import 'package:halkyon_learn_flutter/src/core/asset/model/stored_file.dart'; import 'package:halkyon_learn_flutter/src/core/asset/model/stored_file.dart';
import '../../../support/fake_asset_gateway.dart'; import '../../../support/fake_asset_gateway.dart';
import '../../../support/fake_asset_sealing.dart'; import '../../../support/fake_asset_sealing.dart';
import '../../../support/fake_asset_server_gateway.dart';
import '../../../support/memory_asset_file_cache.dart';
void main() { void main() {
late FakeAssetGateway rows; late FakeAssetGateway rows;
late FakeAssetServerGateway server; late FakeFileServerGateway server;
late MemoryAssetFileCache cache; late MemoryFileCache cache;
late StreamController<void> triggers; late StreamController<void> triggers;
late AssetRepository repository; late AssetRepository repository;
@ -26,8 +26,8 @@ void main() {
setUp(() { setUp(() {
rows = FakeAssetGateway(); rows = FakeAssetGateway();
server = FakeAssetServerGateway(); server = FakeFileServerGateway();
cache = MemoryAssetFileCache(); cache = MemoryFileCache();
triggers = StreamController<void>.broadcast(); triggers = StreamController<void>.broadcast();
filesAllowed = true; filesAllowed = true;
repository = AssetRepository( repository = AssetRepository(

View file

@ -2,19 +2,19 @@ import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/testing.dart'
show FakeFileServerGateway, MemoryFileCache, sha256Of;
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_payload.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_payload.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import '../../../support/fake_asset_gateway.dart'; import '../../../support/fake_asset_gateway.dart';
import '../../../support/fake_asset_sealing.dart'; import '../../../support/fake_asset_sealing.dart';
import '../../../support/fake_asset_server_gateway.dart';
import '../../../support/memory_asset_file_cache.dart';
/// A private studyset's files (ADR 0019, D5): sealed with its tree's key for /// A private studyset's files (ADR 0019, D5): sealed with its tree's key for
/// their row before they are hashed, uploaded and kept. /// their row before they are hashed, uploaded and kept.
void main() { void main() {
late FakeAssetGateway rows; late FakeAssetGateway rows;
late FakeAssetServerGateway server; late FakeFileServerGateway server;
late FakeAssetSealing sealing; late FakeAssetSealing sealing;
late AssetRepository device; late AssetRepository device;
final image = Uint8List.fromList(utf8.encode('a private picture')); final image = Uint8List.fromList(utf8.encode('a private picture'));
@ -26,7 +26,7 @@ void main() {
final repository = AssetRepository( final repository = AssetRepository(
rows, rows,
server, server,
MemoryAssetFileCache(), MemoryFileCache(),
keys, keys,
); );
addTearDown(repository.dispose); addTearDown(repository.dispose);
@ -35,7 +35,7 @@ void main() {
setUp(() { setUp(() {
rows = FakeAssetGateway(); rows = FakeAssetGateway();
server = FakeAssetServerGateway(); server = FakeFileServerGateway();
sealing = FakeAssetSealing(keys: {'diary': 'key-diary'}); sealing = FakeAssetSealing(keys: {'diary': 'key-diary'});
device = deviceWith(sealing); device = deviceWith(sealing);
}); });

View file

@ -15,7 +15,6 @@ import 'package:material_ui/material_ui.dart';
import '../../support/fake_asset_gateway.dart'; import '../../support/fake_asset_gateway.dart';
import '../../support/fake_note_gateway.dart'; import '../../support/fake_note_gateway.dart';
import '../../support/fake_studyset_gateway.dart'; import '../../support/fake_studyset_gateway.dart';
import '../../support/memory_asset_file_cache.dart';
import '../../support/pump_app.dart'; import '../../support/pump_app.dart';
import '../../support/test_dependencies.dart'; import '../../support/test_dependencies.dart';
@ -44,7 +43,7 @@ void main() {
noteGateway: FakeNoteGateway(), noteGateway: FakeNoteGateway(),
files: files, files: files,
assetGateway: assets, assetGateway: assets,
assetFiles: MemoryAssetFileCache(), assetFiles: MemoryFileCache(),
), ),
location: RoutePaths.newNote('japanese'), location: RoutePaths.newNote('japanese'),
); );

View file

@ -3,6 +3,8 @@ import 'dart:typed_data';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/testing.dart'
show FakeFileServerGateway, MemoryFileCache, sha256Of;
import 'package:halkyon_editor/halkyon_editor.dart'; import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_payload.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_payload.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
@ -17,11 +19,9 @@ import 'package:material_ui/material_ui.dart';
import '../../support/fake_asset_gateway.dart'; import '../../support/fake_asset_gateway.dart';
import '../../support/fake_asset_sealing.dart'; import '../../support/fake_asset_sealing.dart';
import '../../support/fake_asset_server_gateway.dart';
import '../../support/fake_card_gateway.dart'; import '../../support/fake_card_gateway.dart';
import '../../support/fake_sound_player.dart'; import '../../support/fake_sound_player.dart';
import '../../support/fake_studyset_gateway.dart'; import '../../support/fake_studyset_gateway.dart';
import '../../support/memory_asset_file_cache.dart';
import '../../support/pump_app.dart'; import '../../support/pump_app.dart';
import '../../support/test_dependencies.dart'; import '../../support/test_dependencies.dart';
@ -29,7 +29,7 @@ void main() {
late FakeCardGateway cardGateway; late FakeCardGateway cardGateway;
late CardRepository cards; late CardRepository cards;
late FakeAssetGateway assetGateway; late FakeAssetGateway assetGateway;
late MemoryAssetFileCache files; late MemoryFileCache files;
late AssetRepository assets; late AssetRepository assets;
late FakeSoundPlayer sounds; late FakeSoundPlayer sounds;
@ -37,10 +37,10 @@ void main() {
cardGateway = FakeCardGateway(); cardGateway = FakeCardGateway();
cards = CardRepository(cardGateway); cards = CardRepository(cardGateway);
assetGateway = FakeAssetGateway(); assetGateway = FakeAssetGateway();
files = MemoryAssetFileCache(); files = MemoryFileCache();
assets = AssetRepository( assets = AssetRepository(
assetGateway, assetGateway,
FakeAssetServerGateway(), FakeFileServerGateway(),
files, files,
FakeAssetSealing(), FakeAssetSealing(),
); );

View file

@ -1,6 +1,8 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/testing.dart'
show FakeFileServerGateway, MemoryFileCache;
import 'package:halkyon_editor/halkyon_editor.dart'; import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import 'package:halkyon_learn_flutter/src/core/work/work_progress.dart'; import 'package:halkyon_learn_flutter/src/core/work/work_progress.dart';
@ -22,7 +24,6 @@ import 'package:halkyon_learn_flutter/src/feature/tag/data/tag_repository.dart';
import '../../../support/fake_asset_gateway.dart'; import '../../../support/fake_asset_gateway.dart';
import '../../../support/fake_asset_sealing.dart'; import '../../../support/fake_asset_sealing.dart';
import '../../../support/fake_asset_server_gateway.dart';
import '../../../support/fake_card_gateway.dart'; import '../../../support/fake_card_gateway.dart';
import '../../../support/fake_learning_path_gateway.dart'; import '../../../support/fake_learning_path_gateway.dart';
import '../../../support/fake_note_gateway.dart'; import '../../../support/fake_note_gateway.dart';
@ -30,7 +31,6 @@ import '../../../support/fake_pdf_source_gateway.dart';
import '../../../support/fake_review_gateway.dart'; import '../../../support/fake_review_gateway.dart';
import '../../../support/fake_studyset_gateway.dart'; import '../../../support/fake_studyset_gateway.dart';
import '../../../support/fake_tag_gateway.dart'; import '../../../support/fake_tag_gateway.dart';
import '../../../support/memory_asset_file_cache.dart';
import 'anki_package_test.dart' show fixture; import 'anki_package_test.dart' show fixture;
void main() { void main() {
@ -55,8 +55,8 @@ void main() {
assetRows = FakeAssetGateway(); assetRows = FakeAssetGateway();
assets = AssetRepository( assets = AssetRepository(
assetRows, assetRows,
FakeAssetServerGateway(), FakeFileServerGateway(),
MemoryAssetFileCache(), MemoryFileCache(),
FakeAssetSealing(), FakeAssetSealing(),
); );
importer = AnkiImporter( importer = AnkiImporter(

View file

@ -15,7 +15,6 @@ import 'package:halkyon_learn_flutter/src/feature/studyset/data/studyset_reposit
import 'package:halkyon_learn_flutter/src/feature/studyset/model/studyset_content.dart'; import 'package:halkyon_learn_flutter/src/feature/studyset/model/studyset_content.dart';
import 'package:material_ui/material_ui.dart'; import 'package:material_ui/material_ui.dart';
import '../../../support/fake_asset_server_gateway.dart';
import '../../../support/fake_card_gateway.dart'; import '../../../support/fake_card_gateway.dart';
import '../../../support/fake_note_gateway.dart'; import '../../../support/fake_note_gateway.dart';
import '../../../support/fake_studyset_gateway.dart'; import '../../../support/fake_studyset_gateway.dart';
@ -26,13 +25,13 @@ import '../data/anki_package_test.dart' show fixture;
void main() { void main() {
late FakeCardGateway cardGateway; late FakeCardGateway cardGateway;
late FakeFilePicker files; late FakeFilePicker files;
late FakeAssetServerGateway server; late FakeFileServerGateway server;
late FakeNoteGateway noteGateway; late FakeNoteGateway noteGateway;
setUp(() { setUp(() {
cardGateway = FakeCardGateway(); cardGateway = FakeCardGateway();
files = FakeFilePicker(); files = FakeFilePicker();
server = FakeAssetServerGateway(); server = FakeFileServerGateway();
noteGateway = FakeNoteGateway(); noteGateway = FakeNoteGateway();
}); });

View file

@ -3,6 +3,8 @@ import 'dart:typed_data';
import 'package:clock/clock.dart'; import 'package:clock/clock.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/testing.dart'
show FakeFileServerGateway, MemoryFileCache;
import 'package:halkyon_editor/halkyon_editor.dart'; import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import 'package:halkyon_learn_flutter/src/core/asset/model/stored_file.dart'; import 'package:halkyon_learn_flutter/src/core/asset/model/stored_file.dart';
@ -40,7 +42,6 @@ import 'package:halkyon_ui/halkyon_ui.dart';
import '../../support/fake_asset_gateway.dart'; import '../../support/fake_asset_gateway.dart';
import '../../support/fake_asset_sealing.dart'; import '../../support/fake_asset_sealing.dart';
import '../../support/fake_asset_server_gateway.dart';
import '../../support/fake_card_gateway.dart'; import '../../support/fake_card_gateway.dart';
import '../../support/fake_device_dictionaries.dart'; import '../../support/fake_device_dictionaries.dart';
import '../../support/fake_dictionary_gateway.dart'; import '../../support/fake_dictionary_gateway.dart';
@ -51,7 +52,6 @@ import '../../support/fake_pdf_source_gateway.dart';
import '../../support/fake_review_gateway.dart'; import '../../support/fake_review_gateway.dart';
import '../../support/fake_studyset_gateway.dart'; import '../../support/fake_studyset_gateway.dart';
import '../../support/fake_tag_gateway.dart'; import '../../support/fake_tag_gateway.dart';
import '../../support/memory_asset_file_cache.dart';
/// One person's repositories, on fake gateways of their own. /// One person's repositories, on fake gateways of their own.
final class _Person() { final class _Person() {
@ -63,8 +63,8 @@ final class _Person() {
final reviews = ReviewRepository(FakeReviewGateway()); final reviews = ReviewRepository(FakeReviewGateway());
final assets = AssetRepository( final assets = AssetRepository(
FakeAssetGateway(), FakeAssetGateway(),
FakeAssetServerGateway(), FakeFileServerGateway(),
MemoryAssetFileCache(), MemoryFileCache(),
FakeAssetSealing(), FakeAssetSealing(),
); );
late final tags = TagRepository( late final tags = TagRepository(

View file

@ -4,6 +4,8 @@ import 'dart:typed_data';
import 'package:archive/archive.dart'; import 'package:archive/archive.dart';
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/testing.dart'
show FakeFileServerGateway, MemoryFileCache;
import 'package:halkyon_editor/halkyon_editor.dart'; import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import 'package:halkyon_learn_flutter/src/core/work/work_progress.dart'; import 'package:halkyon_learn_flutter/src/core/work/work_progress.dart';
@ -33,7 +35,6 @@ import 'package:halkyon_learn_flutter/src/feature/tag/data/tag_repository.dart';
import '../../support/fake_asset_gateway.dart'; import '../../support/fake_asset_gateway.dart';
import '../../support/fake_asset_sealing.dart'; import '../../support/fake_asset_sealing.dart';
import '../../support/fake_asset_server_gateway.dart';
import '../../support/fake_card_gateway.dart'; import '../../support/fake_card_gateway.dart';
import '../../support/fake_device_dictionaries.dart'; import '../../support/fake_device_dictionaries.dart';
import '../../support/fake_dictionary_gateway.dart'; import '../../support/fake_dictionary_gateway.dart';
@ -44,7 +45,6 @@ import '../../support/fake_pdf_source_gateway.dart';
import '../../support/fake_review_gateway.dart'; import '../../support/fake_review_gateway.dart';
import '../../support/fake_studyset_gateway.dart'; import '../../support/fake_studyset_gateway.dart';
import '../../support/fake_tag_gateway.dart'; import '../../support/fake_tag_gateway.dart';
import '../../support/memory_asset_file_cache.dart';
/// The JSON a synced [payload] holds. /// The JSON a synced [payload] holds.
Map<String, Object?> json(ByteData payload) => Map<String, Object?> json(ByteData payload) =>
@ -280,8 +280,8 @@ void main() {
assetRows = FakeAssetGateway(); assetRows = FakeAssetGateway();
assets = AssetRepository( assets = AssetRepository(
assetRows, assetRows,
FakeAssetServerGateway(), FakeFileServerGateway(),
MemoryAssetFileCache(), MemoryFileCache(),
FakeAssetSealing(), FakeAssetSealing(),
); );
pdfs = PdfSourceRepository(FakePdfSourceGateway(), assets); pdfs = PdfSourceRepository(FakePdfSourceGateway(), assets);

View file

@ -20,13 +20,11 @@ import 'package:material_ui/material_ui.dart' hide Card;
import '../../support/fake_asset_gateway.dart'; import '../../support/fake_asset_gateway.dart';
import '../../support/fake_asset_sealing.dart'; import '../../support/fake_asset_sealing.dart';
import '../../support/fake_asset_server_gateway.dart';
import '../../support/fake_card_gateway.dart'; import '../../support/fake_card_gateway.dart';
import '../../support/fake_note_gateway.dart'; import '../../support/fake_note_gateway.dart';
import '../../support/fake_pdf_engine.dart'; import '../../support/fake_pdf_engine.dart';
import '../../support/fake_pdf_source_gateway.dart'; import '../../support/fake_pdf_source_gateway.dart';
import '../../support/fake_studyset_gateway.dart'; import '../../support/fake_studyset_gateway.dart';
import '../../support/memory_asset_file_cache.dart';
import '../../support/pump_app.dart'; import '../../support/pump_app.dart';
import '../../support/test_dependencies.dart'; import '../../support/test_dependencies.dart';
@ -74,7 +72,7 @@ void main() {
late FakeNoteGateway noteGateway; late FakeNoteGateway noteGateway;
late FakePdfSourceGateway pdfGateway; late FakePdfSourceGateway pdfGateway;
late FakeAssetGateway assetGateway; late FakeAssetGateway assetGateway;
late MemoryAssetFileCache files; late MemoryFileCache files;
late FakePdfEngine engine; late FakePdfEngine engine;
setUp(() { setUp(() {
@ -95,7 +93,7 @@ void main() {
noteGateway = FakeNoteGateway(); noteGateway = FakeNoteGateway();
pdfGateway = FakePdfSourceGateway(); pdfGateway = FakePdfSourceGateway();
assetGateway = FakeAssetGateway(); assetGateway = FakeAssetGateway();
files = MemoryAssetFileCache(); files = MemoryFileCache();
engine = FakePdfEngine(); engine = FakePdfEngine();
}); });
@ -240,7 +238,7 @@ void main() {
'selected, tied to the page', (tester) async { 'selected, tied to the page', (tester) async {
final assets = AssetRepository( final assets = AssetRepository(
assetGateway, assetGateway,
FakeAssetServerGateway(), FakeFileServerGateway(),
files, files,
FakeAssetSealing(), FakeAssetSealing(),
); );

View file

@ -29,14 +29,12 @@ import 'package:material_ui/material_ui.dart';
import '../../support/fake_asset_gateway.dart'; import '../../support/fake_asset_gateway.dart';
import '../../support/fake_asset_sealing.dart'; import '../../support/fake_asset_sealing.dart';
import '../../support/fake_asset_server_gateway.dart';
import '../../support/fake_card_gateway.dart'; import '../../support/fake_card_gateway.dart';
import '../../support/fake_conversation_gateway.dart'; import '../../support/fake_conversation_gateway.dart';
import '../../support/fake_grammar_gateway.dart'; import '../../support/fake_grammar_gateway.dart';
import '../../support/fake_photo_picker.dart'; import '../../support/fake_photo_picker.dart';
import '../../support/fake_settings_gateway.dart'; import '../../support/fake_settings_gateway.dart';
import '../../support/fake_studyset_gateway.dart'; import '../../support/fake_studyset_gateway.dart';
import '../../support/memory_asset_file_cache.dart';
import '../../support/memory_device_settings_store.dart'; import '../../support/memory_device_settings_store.dart';
import '../../support/pump_app.dart'; import '../../support/pump_app.dart';
import '../../support/test_dependencies.dart'; import '../../support/test_dependencies.dart';
@ -123,7 +121,7 @@ void main() {
late MemoryDeviceSettingsStore store; late MemoryDeviceSettingsStore store;
late List<Uri> searched; late List<Uri> searched;
late FakeAssetGateway assetGateway; late FakeAssetGateway assetGateway;
late MemoryAssetFileCache assetFiles; late MemoryFileCache assetFiles;
late FakeGrammarGateway grammar; late FakeGrammarGateway grammar;
setUp(() { setUp(() {
@ -150,7 +148,7 @@ void main() {
speech = FakeSpeechInput(); speech = FakeSpeechInput();
searched = []; searched = [];
assetGateway = FakeAssetGateway(); assetGateway = FakeAssetGateway();
assetFiles = MemoryAssetFileCache(); assetFiles = MemoryFileCache();
grammar = FakeGrammarGateway( grammar = FakeGrammarGateway(
found: { found: {
'私はりんごは食べる': const [ '私はりんごは食べる': const [
@ -1469,7 +1467,7 @@ void main() {
Future<String> picturedCard() async { Future<String> picturedCard() async {
final assets = AssetRepository( final assets = AssetRepository(
assetGateway, assetGateway,
FakeAssetServerGateway(), FakeFileServerGateway(),
assetFiles, assetFiles,
FakeAssetSealing(), FakeAssetSealing(),
); );

View file

@ -3,15 +3,15 @@ import 'dart:typed_data';
import 'dart:ui' show Rect; import 'dart:ui' show Rect;
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/testing.dart'
show FakeFileServerGateway, MemoryFileCache;
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import 'package:halkyon_learn_flutter/src/feature/assistant/data/assistant_files.dart'; import 'package:halkyon_learn_flutter/src/feature/assistant/data/assistant_files.dart';
import 'package:halkyon_learn_flutter/src/feature/pdf_source/model/pdf_source.dart'; import 'package:halkyon_learn_flutter/src/feature/pdf_source/model/pdf_source.dart';
import '../../../support/fake_asset_gateway.dart'; import '../../../support/fake_asset_gateway.dart';
import '../../../support/fake_asset_sealing.dart'; import '../../../support/fake_asset_sealing.dart';
import '../../../support/fake_asset_server_gateway.dart';
import '../../../support/fake_pdf_engine.dart'; import '../../../support/fake_pdf_engine.dart';
import '../../../support/memory_asset_file_cache.dart';
// What a model is sent of the person's files (ADR 0021, D12): images every // What a model is sent of the person's files (ADR 0021, D12): images every
// provider reads, none larger than the smallest limit, and a PDF's pages // provider reads, none larger than the smallest limit, and a PDF's pages
@ -25,8 +25,8 @@ void main() {
setUp(() { setUp(() {
assets = AssetRepository( assets = AssetRepository(
FakeAssetGateway(), FakeAssetGateway(),
FakeAssetServerGateway(), FakeFileServerGateway(),
MemoryAssetFileCache(), MemoryFileCache(),
FakeAssetSealing(), FakeAssetSealing(),
); );
engine = FakePdfEngine(); engine = FakePdfEngine();

View file

@ -2,6 +2,8 @@ import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/testing.dart'
show FakeFileServerGateway, MemoryFileCache;
import 'package:halkyon_editor/halkyon_editor.dart'; import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import 'package:halkyon_learn_flutter/src/core/content/published_ref.dart'; import 'package:halkyon_learn_flutter/src/core/content/published_ref.dart';
@ -24,7 +26,6 @@ import 'package:material_ui/material_ui.dart' hide Card;
import '../../support/fake_asset_gateway.dart'; import '../../support/fake_asset_gateway.dart';
import '../../support/fake_asset_sealing.dart'; import '../../support/fake_asset_sealing.dart';
import '../../support/fake_asset_server_gateway.dart';
import '../../support/fake_card_gateway.dart'; import '../../support/fake_card_gateway.dart';
import '../../support/fake_explore_gateway.dart'; import '../../support/fake_explore_gateway.dart';
import '../../support/fake_learning_path_gateway.dart'; import '../../support/fake_learning_path_gateway.dart';
@ -32,7 +33,6 @@ import '../../support/fake_note_gateway.dart';
import '../../support/fake_pdf_source_gateway.dart'; import '../../support/fake_pdf_source_gateway.dart';
import '../../support/fake_studyset_gateway.dart'; import '../../support/fake_studyset_gateway.dart';
import '../../support/fake_tag_gateway.dart'; import '../../support/fake_tag_gateway.dart';
import '../../support/memory_asset_file_cache.dart';
import '../../support/pump_app.dart'; import '../../support/pump_app.dart';
import '../../support/test_dependencies.dart'; import '../../support/test_dependencies.dart';
@ -95,8 +95,8 @@ void main() {
final paths = LearningPathRepository(FakeLearningPathGateway()); final paths = LearningPathRepository(FakeLearningPathGateway());
final assets = AssetRepository( final assets = AssetRepository(
FakeAssetGateway(), FakeAssetGateway(),
FakeAssetServerGateway(), FakeFileServerGateway(),
MemoryAssetFileCache(), MemoryFileCache(),
FakeAssetSealing(), FakeAssetSealing(),
); );
// The person added release 1 to their library before. // The person added release 1 to their library before.

View file

@ -3,6 +3,8 @@ import 'dart:typed_data';
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/testing.dart'
show FakeFileServerGateway, MemoryFileCache;
import 'package:halkyon_editor/halkyon_editor.dart'; import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_payload.dart'; import 'package:halkyon_learn_flutter/src/feature/card/data/card_payload.dart';
@ -25,14 +27,12 @@ import 'package:halkyon_learn_flutter/src/feature/tag/data/tag_repository.dart';
import '../../support/fake_asset_gateway.dart'; import '../../support/fake_asset_gateway.dart';
import '../../support/fake_asset_sealing.dart'; import '../../support/fake_asset_sealing.dart';
import '../../support/fake_asset_server_gateway.dart';
import '../../support/fake_card_gateway.dart'; import '../../support/fake_card_gateway.dart';
import '../../support/fake_learning_path_gateway.dart'; import '../../support/fake_learning_path_gateway.dart';
import '../../support/fake_note_gateway.dart'; import '../../support/fake_note_gateway.dart';
import '../../support/fake_pdf_source_gateway.dart'; import '../../support/fake_pdf_source_gateway.dart';
import '../../support/fake_studyset_gateway.dart'; import '../../support/fake_studyset_gateway.dart';
import '../../support/fake_tag_gateway.dart'; import '../../support/fake_tag_gateway.dart';
import '../../support/memory_asset_file_cache.dart';
/// The JSON a synced [payload] holds. /// The JSON a synced [payload] holds.
Map<String, Object?> json(ByteData payload) => Map<String, Object?> json(ByteData payload) =>
@ -180,8 +180,8 @@ void main() {
); );
final assets = AssetRepository( final assets = AssetRepository(
FakeAssetGateway(), FakeAssetGateway(),
FakeAssetServerGateway(), FakeFileServerGateway(),
MemoryAssetFileCache(), MemoryFileCache(),
FakeAssetSealing(), FakeAssetSealing(),
); );
pdfs = PdfSourceRepository(FakePdfSourceGateway(), assets); pdfs = PdfSourceRepository(FakePdfSourceGateway(), assets);

View file

@ -2,6 +2,8 @@ import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/testing.dart'
show FakeFileServerGateway, MemoryFileCache;
import 'package:halkyon_editor/halkyon_editor.dart'; import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import 'package:halkyon_learn_flutter/src/core/content/published_ref.dart'; import 'package:halkyon_learn_flutter/src/core/content/published_ref.dart';
@ -30,14 +32,12 @@ import 'package:halkyon_learn_flutter/src/feature/tag/data/tag_repository.dart';
import '../../support/fake_asset_gateway.dart'; import '../../support/fake_asset_gateway.dart';
import '../../support/fake_asset_sealing.dart'; import '../../support/fake_asset_sealing.dart';
import '../../support/fake_asset_server_gateway.dart';
import '../../support/fake_card_gateway.dart'; import '../../support/fake_card_gateway.dart';
import '../../support/fake_learning_path_gateway.dart'; import '../../support/fake_learning_path_gateway.dart';
import '../../support/fake_note_gateway.dart'; import '../../support/fake_note_gateway.dart';
import '../../support/fake_pdf_source_gateway.dart'; import '../../support/fake_pdf_source_gateway.dart';
import '../../support/fake_studyset_gateway.dart'; import '../../support/fake_studyset_gateway.dart';
import '../../support/fake_tag_gateway.dart'; import '../../support/fake_tag_gateway.dart';
import '../../support/memory_asset_file_cache.dart';
/// The JSON a synced [payload] holds. /// The JSON a synced [payload] holds.
Map<String, Object?> json(ByteData payload) => Map<String, Object?> json(ByteData payload) =>
@ -89,8 +89,8 @@ void main() {
); );
assets = AssetRepository( assets = AssetRepository(
FakeAssetGateway(), FakeAssetGateway(),
FakeAssetServerGateway(), FakeFileServerGateway(),
MemoryAssetFileCache(), MemoryFileCache(),
FakeAssetSealing(), FakeAssetSealing(),
); );
pdfs = PdfSourceRepository(FakePdfSourceGateway(), assets); pdfs = PdfSourceRepository(FakePdfSourceGateway(), assets);

View file

@ -2,6 +2,8 @@ import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/testing.dart'
show FakeFileServerGateway, MemoryFileCache;
import 'package:halkyon_editor/halkyon_editor.dart'; import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import 'package:halkyon_learn_flutter/src/core/citation/model/citation.dart'; import 'package:halkyon_learn_flutter/src/core/citation/model/citation.dart';
@ -23,13 +25,11 @@ import 'package:halkyon_learn_flutter/src/feature/studyset/model/studyset_conten
import '../../../support/fake_asset_gateway.dart'; import '../../../support/fake_asset_gateway.dart';
import '../../../support/fake_asset_sealing.dart'; import '../../../support/fake_asset_sealing.dart';
import '../../../support/fake_asset_server_gateway.dart';
import '../../../support/fake_card_gateway.dart'; import '../../../support/fake_card_gateway.dart';
import '../../../support/fake_learning_path_gateway.dart'; import '../../../support/fake_learning_path_gateway.dart';
import '../../../support/fake_note_gateway.dart'; import '../../../support/fake_note_gateway.dart';
import '../../../support/fake_pdf_source_gateway.dart'; import '../../../support/fake_pdf_source_gateway.dart';
import '../../../support/fake_studyset_gateway.dart'; import '../../../support/fake_studyset_gateway.dart';
import '../../../support/memory_asset_file_cache.dart';
void main() { void main() {
late FakeStudysetGateway studysetGateway; late FakeStudysetGateway studysetGateway;
@ -49,8 +49,8 @@ void main() {
paths = LearningPathRepository(FakeLearningPathGateway()); paths = LearningPathRepository(FakeLearningPathGateway());
assets = AssetRepository( assets = AssetRepository(
FakeAssetGateway(), FakeAssetGateway(),
FakeAssetServerGateway(), FakeFileServerGateway(),
MemoryAssetFileCache(), MemoryFileCache(),
FakeAssetSealing(), FakeAssetSealing(),
); );
pdfs = PdfSourceRepository(FakePdfSourceGateway(), assets); pdfs = PdfSourceRepository(FakePdfSourceGateway(), assets);

View file

@ -4,6 +4,8 @@ import 'dart:typed_data';
import 'package:archive/archive.dart'; import 'package:archive/archive.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/testing.dart'
show FakeFileServerGateway, MemoryFileCache;
import 'package:halkyon_editor/halkyon_editor.dart'; import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_payload.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_payload.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart'; import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
@ -22,12 +24,10 @@ import 'package:material_ui/material_ui.dart';
import '../../../support/fake_asset_gateway.dart'; import '../../../support/fake_asset_gateway.dart';
import '../../../support/fake_asset_sealing.dart'; import '../../../support/fake_asset_sealing.dart';
import '../../../support/fake_asset_server_gateway.dart';
import '../../../support/fake_card_gateway.dart'; import '../../../support/fake_card_gateway.dart';
import '../../../support/fake_file_saver.dart'; import '../../../support/fake_file_saver.dart';
import '../../../support/fake_review_gateway.dart'; import '../../../support/fake_review_gateway.dart';
import '../../../support/fake_studyset_gateway.dart'; import '../../../support/fake_studyset_gateway.dart';
import '../../../support/memory_asset_file_cache.dart';
import '../../../support/pump_app.dart'; import '../../../support/pump_app.dart';
import '../../../support/test_dependencies.dart'; import '../../../support/test_dependencies.dart';
@ -35,7 +35,7 @@ void main() {
late FakeStudysetGateway studysets; late FakeStudysetGateway studysets;
late FakeCardGateway cardGateway; late FakeCardGateway cardGateway;
late FakeAssetGateway assetGateway; late FakeAssetGateway assetGateway;
late MemoryAssetFileCache cache; late MemoryFileCache cache;
late FakeFileSaver saver; late FakeFileSaver saver;
late FakeReviewGateway reviewGateway; late FakeReviewGateway reviewGateway;
late _HeldExportArchiver archiver; late _HeldExportArchiver archiver;
@ -48,7 +48,7 @@ void main() {
); );
cardGateway = FakeCardGateway(); cardGateway = FakeCardGateway();
assetGateway = FakeAssetGateway(); assetGateway = FakeAssetGateway();
cache = MemoryAssetFileCache(); cache = MemoryFileCache();
saver = FakeFileSaver(); saver = FakeFileSaver();
reviewGateway = FakeReviewGateway(); reviewGateway = FakeReviewGateway();
archiver = _HeldExportArchiver(); archiver = _HeldExportArchiver();
@ -256,7 +256,7 @@ void main() {
'links to', (tester) async { 'links to', (tester) async {
final assets = AssetRepository( final assets = AssetRepository(
assetGateway, assetGateway,
FakeAssetServerGateway(), FakeFileServerGateway(),
cache, cache,
FakeAssetSealing(), FakeAssetSealing(),
); );

Some files were not shown because too many files have changed in this diff Show more