Switch newly added default Sources on once (#1)

The app now remembers which curated Sources it has seen. A Source that is on
by default is enabled the first time it appears, also on installs with saved
toggles; Sources seen before keep the user's choice. Installs from before this
change count the current catalog as seen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
CedricandClaude Opus 5.5 committed 2026-10-16 15:35:36 +02:00
1 parent f35ac9b806
commit ea37a23c08
4 files changed
+135 -5

No files matched your search

+9
View File
@@ -185,3 +185,12 @@ const defaultSources = <NewsSource>[
description: 'Security and malware news',
),
];
/// The curated sources before the app remembered which ones it had seen.
/// Installs from then count these as seen, so switched-off ones stay off.
const legacySeenSourceIds = {
'heise', 'golem', 't3n', 'computerbase', 'spiegel-netzwelt', 'zeit-digital',
'netzpolitik', 'heise-security', 'heise-developer', 'caschy', 'derstandard-web',
'borncity', 'verge', 'arstechnica', 'techcrunch', 'hackernews', 'mit-tr', 'wired',
'engadget', 'theregister', 'bleepingcomputer',
};
+7
View File
@@ -74,6 +74,13 @@ class Storage {
Future<void> saveEnabledSourceIds(Set<String> ids) =>
_prefs.setStringList('enabled_sources', ids.toList());
/// Curated sources the app has already offered, so each one that is on by
/// default switches on only once. Null means "never saved".
Set<String>? loadSeenSourceIds() => _prefs.getStringList('seen_sources')?.toSet();
Future<void> saveSeenSourceIds(Set<String> ids) =>
_prefs.setStringList('seen_sources', ids.toList());
List<NewsSource> loadCustomSources() {
final raw = _prefs.getString('custom_sources');
if (raw == null) return [];
+30 -5
View File
@@ -29,8 +29,13 @@ class SummaryState {
}
class AppState extends ChangeNotifier {
AppState(this._storage, {FeedService? feedService, ArticleExtractor? extractor})
: _feeds = feedService ?? FeedService(),
AppState(
this._storage, {
FeedService? feedService,
ArticleExtractor? extractor,
List<NewsSource> curatedSources = defaultSources,
}) : _feeds = feedService ?? FeedService(),
_curated = curatedSources,
consent = ConsentService(),
paywall = PaywallService(_storage) {
_extractor = extractor ?? ArticleExtractor(consent: consent);
@@ -38,6 +43,9 @@ class AppState extends ChangeNotifier {
final Storage _storage;
final FeedService _feeds;
/// The curated catalog; [defaultSources] outside of tests.
final List<NewsSource> _curated;
late final ArticleExtractor _extractor;
final PaywallService paywall;
@@ -74,7 +82,7 @@ class AppState extends ChangeNotifier {
int get hiddenCount => articles.where(_isHidden).length;
List<NewsSource> get allSources => [...defaultSources, ...customSources];
List<NewsSource> get allSources => [..._curated, ...customSources];
List<NewsSource> get enabledSources =>
allSources.where((s) => enabledSourceIds.contains(s.id)).toList();
@@ -82,8 +90,7 @@ class AppState extends ChangeNotifier {
Future<void> init() async {
settings = await _storage.loadSettings();
customSources = _storage.loadCustomSources();
enabledSourceIds = _storage.loadEnabledSourceIds() ??
defaultSources.where((s) => s.enabledByDefault).map((s) => s.id).toSet();
await _enableNewDefaultSources();
briefings = await _storage.loadBriefingHistory();
notifyListeners();
await refresh();
@@ -111,6 +118,24 @@ class AppState extends ChangeNotifier {
// --- Sources -------------------------------------------------------------
/// Switches on curated sources that are on by default the first time the
/// app sees them, so they also reach installs with saved toggles. Sources
/// seen before keep whatever the user chose.
Future<void> _enableNewDefaultSources() async {
final saved = _storage.loadEnabledSourceIds();
final seen = _storage.loadSeenSourceIds() ??
(saved == null ? const <String>{} : legacySeenSourceIds);
final unseen = _curated.where((s) => !seen.contains(s.id)).toList();
enabledSourceIds = {
...?saved,
for (final s in unseen)
if (s.enabledByDefault) s.id,
};
if (unseen.isEmpty) return;
await _storage.saveSeenSourceIds({...seen, ...unseen.map((s) => s.id)});
await _storage.saveEnabledSourceIds(enabledSourceIds);
}
Future<void> setSourceEnabled(NewsSource source, bool enabled) async {
enabled ? enabledSourceIds.add(source.id) : enabledSourceIds.remove(source.id);
notifyListeners();