the-mews/app/lib/application/internal_actions.dart

125 lines
4.2 KiB
Dart
Raw Normal View History

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 ReaderSettingsController settings,
required BookmarksController bookmarks,
required SubscriptionsController subscriptions,
}) : _db = db,
_settings = settings,
_bookmarks = bookmarks,
_subscriptions = subscriptions;
final MewsDatabase _db;
final ReaderSettingsController _settings;
final BookmarksController _bookmarks;
final SubscriptionsController _subscriptions;
Future<bool> 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'] ?? ''),
'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,
};
}
Future<bool> _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<bool> _withUrl(
Map<String, String> args, Future<void> 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<bool> _changeTag(Map<String, String> 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<bool> _deleteTag(String? tag) async {
if (tag == null || tag.isEmpty) return false;
await _db.deleteTag(tag);
return true;
}
Future<bool> _clearHistory() async {
await _db.clearHistory();
return true;
}
Future<bool> _markRead(Map<String, String> 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<bool> _refreshAll() async {
await _subscriptions.refreshAll();
return false;
}
Future<bool> _refreshOne(String? siteUrl) async {
if (siteUrl == null || siteUrl.isEmpty) return false;
await _subscriptions.refreshOne(siteUrl);
return false;
}
}