Keep per-kind facts on SourceKind and the Briefing's input in one place (review items 4, 5, 6, 7)

- SourceKind carries whether it feeds the Briefing, its fixed time window
  (Learning, Fun) and whether reading is picture-led (Fun); windowOf and
  the reader read from it.
- AppState.briefingArticles is the one place that says only News sources
  feed the Briefing; generateBriefing and the Briefing tab use it.
- articlesOf, hiddenCountOf and briefingArticles share one filter.
- FeedService.fetchAll takes windowOf: like AppState.windowOf.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
CedricandClaude Opus 5.5 committed 2026-10-16 16:07:37 +02:00
1 parent 49982c5467
commit 246564f1d9
8 files changed
+80 -30

No files matched your search

+34
View File
@@ -1,10 +1,13 @@
import 'dart:convert';
import 'package:daily_tech_news/data/default_sources.dart';
import 'package:daily_tech_news/models/app_settings.dart';
import 'package:daily_tech_news/models/article.dart';
import 'package:daily_tech_news/models/briefing.dart';
import 'package:daily_tech_news/models/source.dart';
import 'package:daily_tech_news/services/summarizer.dart';
import 'package:daily_tech_news/ui/briefing_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart';
@@ -62,6 +65,37 @@ void main() {
expect(_titles(summarizer.briefingInput!), ['News from this morning']);
});
test('the Briefing reads the shown News articles, not Learning, Fun or hidden ones', () async {
final xkcd = testSource('xkcd', SourceKind.fun);
final state = await launchApp([verge, bytebytego, xkcd], feeds: {
verge.feedUrl: [('News from this morning', const Duration(hours: 2)),
('Sponsored: Buy our phone', const Duration(hours: 3))],
bytebytego.feedUrl: [('Explainer from today', const Duration(hours: 1))],
xkcd.feedUrl: [('Comic from today', const Duration(hours: 1))],
});
expect(_titles(state.briefingArticles), ['News from this morning']);
});
testWidgets('the Briefing tab counts only the articles the Briefing is made from',
(tester) async {
final state = (await tester.runAsync(() async {
final state = await launchApp([verge, bytebytego], feeds: {
verge.feedUrl: [('News from this morning', const Duration(hours: 2))],
bytebytego.feedUrl: [('Explainer from today', const Duration(hours: 1)),
('Explainer from yesterday', const Duration(days: 1))],
});
await state.updateSettings(
state.settings.copyWith(aiProvider: AiProvider.claude, claudeApiKey: 'key'));
return state;
}))!;
await tester.pumpWidget(
MaterialApp(home: BriefingScreen(state: state, openSettings: () {})));
expect(find.text('Generate from 1 articles'), findsOneWidget);
});
test('News follows the window setting', () async {
SharedPreferences.setMockInitialValues({'max_age_hours': 48});
final state = await launchApp([verge], feeds: {
+1 -1
View File
@@ -10,7 +10,7 @@ import 'package:shared_preferences/shared_preferences.dart';
class _NoFeeds extends FeedService {
@override
Future<FeedResult> fetchAll(List<Source> sources,
{required Duration Function(Source source) maxAgeOf, String corsProxy = ''}) async =>
{required Duration Function(Source source) windowOf, String corsProxy = ''}) async =>
const FeedResult([], {});
}
+2 -2
View File
@@ -19,9 +19,9 @@ class FakeFeeds extends FeedService {
@override
Future<FeedResult> fetchAll(List<Source> sources,
{required Duration Function(Source source) maxAgeOf, String corsProxy = ''}) {
{required Duration Function(Source source) windowOf, String corsProxy = ''}) {
refreshes++;
return super.fetchAll(sources, maxAgeOf: maxAgeOf, corsProxy: corsProxy);
return super.fetchAll(sources, windowOf: windowOf, corsProxy: corsProxy);
}
@override