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:
1 parent
f35ac9b806
commit
ea37a23c08
4 files changed
+135
-5
No files matched your search
@@ -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',
|
||||
};
|
||||
@@ -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 [];
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in new issue
Block a user