- 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>
89 lines
2.5 KiB
Dart
89 lines
2.5 KiB
Dart
enum SourceLanguage {
|
|
de('Deutsch', '🇩🇪'),
|
|
en('English', '🇬🇧');
|
|
|
|
const SourceLanguage(this.label, this.flag);
|
|
|
|
final String label;
|
|
final String flag;
|
|
}
|
|
|
|
/// What a Source's articles are for; see GLOSSARY.md. Each kind has its own
|
|
/// section in the app and its own time window.
|
|
enum SourceKind {
|
|
news('News', feedsBriefing: true),
|
|
learning('Learning', fixedWindow: Duration(days: 14)),
|
|
fun('Fun', fixedWindow: Duration(days: 3), pictureLed: true);
|
|
|
|
const SourceKind(
|
|
this.label, {
|
|
this.feedsBriefing = false,
|
|
this.fixedWindow,
|
|
this.pictureLed = false,
|
|
});
|
|
|
|
final String label;
|
|
|
|
/// Only News sources feed the Briefing.
|
|
final bool feedsBriefing;
|
|
|
|
/// How far back articles reach; null where the user sets it (News).
|
|
final Duration? fixedWindow;
|
|
|
|
/// Comics and memes are the picture: the reader shows it whole in the body
|
|
/// rather than as a cropped banner.
|
|
final bool pictureLed;
|
|
}
|
|
|
|
/// A Source of any [kind]; see GLOSSARY.md.
|
|
class Source {
|
|
const Source({
|
|
required this.id,
|
|
required this.name,
|
|
required this.feedUrl,
|
|
required this.homepage,
|
|
required this.language,
|
|
this.kind = SourceKind.news,
|
|
this.description = '',
|
|
this.enabledByDefault = false,
|
|
this.isCustom = false,
|
|
this.checkPaywallOnPage = false,
|
|
});
|
|
|
|
final String id;
|
|
final String name;
|
|
final String feedUrl;
|
|
final String homepage;
|
|
final SourceLanguage language;
|
|
final SourceKind kind;
|
|
final String description;
|
|
final bool enabledByDefault;
|
|
final bool isCustom;
|
|
|
|
/// Paid articles are only marked inside the page (schema.org), not in the
|
|
/// feed, so each new article page is checked once.
|
|
final bool checkPaywallOnPage;
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'id': id,
|
|
'name': name,
|
|
'feedUrl': feedUrl,
|
|
'homepage': homepage,
|
|
'language': language.name,
|
|
'kind': kind.name,
|
|
'description': description,
|
|
};
|
|
|
|
factory Source.custom(Map<String, dynamic> json) => Source(
|
|
id: json['id'] as String,
|
|
name: json['name'] as String,
|
|
feedUrl: json['feedUrl'] as String,
|
|
homepage: json['homepage'] as String? ?? '',
|
|
language: SourceLanguage.values.byName(json['language'] as String? ?? 'en'),
|
|
// Custom sources saved before kinds existed are News sources.
|
|
kind: SourceKind.values.asNameMap()[json['kind']] ?? SourceKind.news,
|
|
description: json['description'] as String? ?? '',
|
|
isCustom: true,
|
|
);
|
|
}
|