import '../database/database.dart'; import 'controllers/bookmarks_controller.dart'; import 'controllers/reader_settings_controller.dart' show ReaderSettingsController; import 'controllers/subscriptions_controller.dart'; import 'pages/mews_urls.dart'; /// Applies the change an action address encodes, e.g. mews:do/set-theme. /// Returns whether anything changed, so the navigator can skip a rerender that /// would show the same page. /// /// An unknown verb or a missing argument does nothing and reports nothing: the /// only links carrying these addresses are the ones the client builds, so a /// miss is a bug rather than something to explain to the reader. class InternalActions { InternalActions({ required MewsDatabase db, required Future Function() applyLanguage, required ReaderSettingsController settings, required BookmarksController bookmarks, required SubscriptionsController subscriptions, }) : _db = db, _applyLanguage = applyLanguage, _settings = settings, _bookmarks = bookmarks, _subscriptions = subscriptions; final MewsDatabase _db; final Future Function() _applyLanguage; final ReaderSettingsController _settings; final BookmarksController _bookmarks; final SubscriptionsController _subscriptions; Future apply(String url) async { final verb = MewsUrls.verbOf(url); if (verb == null) return false; final args = Uri.parse(url).queryParameters; return switch (verb) { 'set-font' => _settings.setFont(args['value'] ?? ''), 'set-size' => _setSize(args['step']), 'set-theme' => _settings.setThemeMode(args['value'] ?? ''), 'set-colors' => _settings.setVariant(args['value'] ?? ''), 'set-language' => _setLanguage(args['value']), 'mark-read' => _markRead(args, read: true), 'mark-unread' => _markRead(args, read: false), 'refresh-subscriptions' => _refreshAll(), 'refresh-subscription' => _refreshOne(args['url']), 'remove-bookmark' => _withUrl(args, _bookmarks.remove), 'unsubscribe' => _withUrl(args, _subscriptions.remove), 'forget-page' => _withUrl(args, _db.forgetPage), 'clear-history' => _clearHistory(), 'add-tag' => _changeTag(args, add: true), 'remove-tag' => _changeTag(args, add: false), 'delete-tag' => _deleteTag(args['tag']), _ => false, }; } /// Changing the language has to load its messages before the page is built /// again, or the rerender would still read the old ones. Future _setLanguage(String? tag) async { if (tag == null || tag.isEmpty) return false; if (!await _settings.setLanguage(tag)) return false; await _applyLanguage(); return true; } Future _setSize(String? step) => switch (step) { 'up' => _settings.increaseSize(), 'down' => _settings.decreaseSize(), _ => Future.value(false), }; /// Runs [change] on the address the action names, if it names one. Future _withUrl( Map args, Future Function(String) change) async { final url = args['url']; if (url == null || url.isEmpty) return false; await change(url); return true; } /// Adds or removes one tag. An empty name is refused, so submitting an /// empty box does nothing. Future _changeTag(Map args, {required bool add}) async { final kind = switch (args['kind']) { 'bookmark' => TagKind.bookmark, 'subscription' => TagKind.subscription, _ => null, }; final url = args['url']; final tag = args['tag']?.trim(); if (kind == null || url == null || url.isEmpty) return false; if (tag == null || tag.isEmpty) return false; if (add) { await _db.addTag(kind, url, tag); } else { await _db.removeTag(kind, url, tag); } return true; } Future _deleteTag(String? tag) async { if (tag == null || tag.isEmpty) return false; await _db.deleteTag(tag); return true; } Future _clearHistory() async { await _db.clearHistory(); return true; } Future _markRead(Map args, {required bool read}) async { final url = args['url']; if (url == null || url.isEmpty) return false; final site = args['site']; if (read) { await _subscriptions.markRead(url, siteUrl: site); } else { await _subscriptions.markUnread(url, siteUrl: site); } return true; } /// The check redraws the page itself as it runs, so the caller need not. Future _refreshAll() async { await _subscriptions.refreshAll(); return false; } Future _refreshOne(String? siteUrl) async { if (siteUrl == null || siteUrl.isEmpty) return false; await _subscriptions.refreshOne(siteUrl); return false; } }