feat: build v1 Mews client: reader UI, gestures, Drift store, fetch actor
This commit is contained in:
parent
d5a0fcbf48
commit
01a36e8aee
56 changed files with 7287 additions and 2 deletions
116
app/test/controllers_test.dart
Normal file
116
app/test/controllers_test.dart
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
import 'package:drift/drift.dart' show Value;
|
||||
import 'package:drift/native.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:mews/application/controllers/reader_settings_controller.dart';
|
||||
import 'package:mews/database/database.dart';
|
||||
import 'package:mews/mews/document.dart';
|
||||
|
||||
void main() {
|
||||
late MewsDatabase db;
|
||||
|
||||
setUp(() {
|
||||
db = MewsDatabase.test(NativeDatabase.memory());
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
await db.close();
|
||||
});
|
||||
|
||||
test('settings round-trip through the database', () async {
|
||||
final settings = ReaderSettingsController(db);
|
||||
await settings.setFont('Atkinson Hyperlegible');
|
||||
await settings.increaseSize();
|
||||
await settings.setThemeMode('dark');
|
||||
await settings.setVariant('warm');
|
||||
|
||||
final reloaded = ReaderSettingsController(db);
|
||||
await reloaded.load();
|
||||
expect(reloaded.font.value, 'Atkinson Hyperlegible');
|
||||
expect(reloaded.fontScale.value, 1.125);
|
||||
expect(reloaded.themeMode.value, 'dark');
|
||||
expect(reloaded.variant.value, 'warm');
|
||||
});
|
||||
|
||||
test('text size stays within its limits', () async {
|
||||
final settings = ReaderSettingsController(db);
|
||||
for (var i = 0; i < 30; i++) {
|
||||
await settings.increaseSize();
|
||||
}
|
||||
expect(settings.fontScale.value, ReaderSettingsController.maxScale);
|
||||
for (var i = 0; i < 40; i++) {
|
||||
await settings.decreaseSize();
|
||||
}
|
||||
expect(settings.fontScale.value, ReaderSettingsController.minScale);
|
||||
});
|
||||
|
||||
test('bookmarks toggle and persist', () async {
|
||||
final library = LibraryController(db);
|
||||
await library.load();
|
||||
await library.toggleBookmark('https://example.com/', 'Example');
|
||||
expect(library.isBookmarked('https://example.com/'), isTrue);
|
||||
|
||||
final reloaded = LibraryController(db);
|
||||
await reloaded.load();
|
||||
expect(reloaded.isBookmarked('https://example.com/'), isTrue);
|
||||
|
||||
await reloaded.toggleBookmark('https://example.com/', 'Example');
|
||||
expect(reloaded.isBookmarked('https://example.com/'), isFalse);
|
||||
});
|
||||
|
||||
test('subscription refresh reports only unseen entries', () async {
|
||||
final library = LibraryController(db);
|
||||
await library.load();
|
||||
|
||||
final firstPost = MewsEntry(
|
||||
url: 'https://example.com/a.html', date: DateTime(2026, 9, 21), title: 'First post');
|
||||
await library.toggleSubscription(
|
||||
'https://example.com/', 'Example', [firstPost]);
|
||||
expect(library.isSubscribed('https://example.com/'), isTrue);
|
||||
|
||||
// Nothing new yet.
|
||||
await library.refreshSubscription(_page('https://example.com/', [firstPost]));
|
||||
expect(library.newEntries.value['https://example.com/'], isNull);
|
||||
|
||||
// A new post appears.
|
||||
final newPost = MewsEntry(
|
||||
url: 'https://example.com/b.html', date: DateTime(2026, 10, 8), title: 'Second post');
|
||||
await library.refreshSubscription(_page('https://example.com/', [newPost, firstPost]));
|
||||
final fresh = library.newEntries.value['https://example.com/']!;
|
||||
expect(fresh, hasLength(1));
|
||||
expect(fresh.single.url, 'https://example.com/b.html');
|
||||
|
||||
// The refresh stored it; a repeat refresh reports nothing.
|
||||
await library.refreshSubscription(_page('https://example.com/', [newPost, firstPost]));
|
||||
expect(library.newEntries.value['https://example.com/'], isNull);
|
||||
});
|
||||
|
||||
test('caches pages for offline reopening', () async {
|
||||
await db.saveCachedPage(CachedPagesCompanion.insert(
|
||||
url: 'https://example.com/page.html',
|
||||
source: 'html',
|
||||
title: const Value('Page'),
|
||||
etag: const Value('"v1"'),
|
||||
));
|
||||
final cached = await db.cachedPage('https://example.com/page.html');
|
||||
expect(cached!.source, 'html');
|
||||
expect(cached.etag, '"v1"');
|
||||
expect(cached.title, 'Page');
|
||||
});
|
||||
|
||||
test('records history and returns the last visited page', () async {
|
||||
await db.recordVisit('https://a.example/', 'A');
|
||||
await db.recordVisit('https://b.example/', 'B');
|
||||
expect(await db.lastVisitedUrl(), 'https://b.example/');
|
||||
});
|
||||
}
|
||||
|
||||
MewsPage _page(String url, List<MewsEntry> entries) => MewsPage(
|
||||
url: url,
|
||||
body: const [],
|
||||
lang: 'en',
|
||||
direction: TextDirection.ltr,
|
||||
variant: MewsVariant.plain,
|
||||
entries: entries,
|
||||
specVersion: '0.1',
|
||||
);
|
||||
Loading…
Add table
Add a link
Reference in a new issue