feat: store subscription posts with a read mark and split the library controller

This commit is contained in:
randogoth 2026-10-11 13:12:48 +03:00
parent b311b9f7dd
commit 953ae798eb
15 changed files with 1787 additions and 386 deletions

View file

@ -312,13 +312,13 @@ void main() {
expect(find.byIcon(Icons.notifications_outlined), findsOneWidget);
await tester.tap(find.byIcon(Icons.notifications_outlined));
await tester.pumpAndSettle();
expect(deps.library.isSubscribed('https://example.com/index.html'), isTrue);
expect(deps.subscriptions.isSubscribed('https://example.com/index.html'), isTrue);
expect(find.byIcon(Icons.notifications_active), findsOneWidget);
expect(find.byIcon(Icons.star_border), findsOneWidget);
await tester.tap(find.byIcon(Icons.star_border));
await tester.pumpAndSettle();
expect(deps.library.isBookmarked('https://example.com/index.html'), isTrue);
expect(deps.bookmarks.isBookmarked('https://example.com/index.html'), isTrue);
expect(find.byIcon(Icons.star), findsOneWidget);
// Pages with neither Atom feed nor dated links offer no subscription.
@ -464,10 +464,12 @@ void main() {
expect(stubDeps.browser.currentPage.value?.url, 'https://example.com/a.html');
// Bookmarks and subscriptions get the same treatment.
await stubDeps.library.load();
await stubDeps.library.toggleBookmark('https://example.com/b.html', 'Page B');
await stubDeps.library.toggleSubscription(
'https://example.com/a.html', 'Page A', const []);
await stubDeps.bookmarks.load();
await stubDeps.subscriptions.load();
await stubDeps.bookmarks.toggle('https://example.com/b.html', 'Page B');
await stubDeps.subscriptions.toggle(parseSource(
_page('Page A', '<h1>Page A</h1><p>The first page.</p>'),
'https://example.com/a.html'));
await stubDeps.browser.open('mews:bookmarks');
await tester.pumpAndSettle();
expect(find.text('Bookmarks'), findsOneWidget);
@ -518,23 +520,37 @@ void main() {
debugDefaultTargetPlatformOverride = null;
});
testWidgets('reports new posts once per page', (tester) async {
testWidgets('new posts are counted on the subscriptions page',
(tester) async {
await pumpApp(tester);
// Subscribing takes on what is already published without flagging it.
final page = parseSource(pageSource, 'https://example.com/index.html');
deps.library.subscribedUrls.value = {'https://example.com/index.html'};
deps.library.newEntries.value = {
'https://example.com/index.html': [
MewsEntry(
url: 'https://example.com/2026-10-08-retro.html',
date: DateTime(2026, 10, 8),
title: 'Collecting retro phones'),
],
};
deps.browser.currentPage.value = page;
await deps.subscriptions.toggle(page);
await deps.browser.open(MewsUrls.subscriptions);
await tester.pumpAndSettle();
expect(find.textContaining('unread post'), findsNothing);
expect(find.textContaining('1 new post'), findsOneWidget);
// Opening the page later, with a post that was not there before, counts
// it; the count comes from the database, so it outlives the session.
const laterSource = '''
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Signal Bars</title><meta name="mews-profile" content="0.1" /></head>
<body>
<h1>Signal Bars</h1>
<ul>
<li><a href="2026-10-09-new.html">2026-10-09 A newer post</a></li>
<li><a href="2026-10-08-retro.html">2026-10-08 Collecting retro phones</a></li>
</ul>
</body>
</html>
''';
await deps.subscriptions
.refreshSite(parseSource(laterSource, 'https://example.com/index.html'));
await deps.browser.open(MewsUrls.subscriptions);
await tester.pumpAndSettle();
expect(find.textContaining('1 unread post'), findsOneWidget);
});
}