feat: add a hub for the client's own pages and gate mews:do action links

This commit is contained in:
randogoth 2026-10-11 13:05:07 +03:00
parent df705d831f
commit b311b9f7dd
21 changed files with 966 additions and 404 deletions

View file

@ -5,6 +5,7 @@ import 'package:signals/signals_flutter.dart' show SignalBuilder;
import '../application/actors/fetch_actor.dart';
import '../application/controllers/browser_controller.dart';
import '../application/controllers/reader_settings_controller.dart';
import '../application/internal_actions.dart';
import '../application/internal_pages.dart';
import '../database/database.dart';
import '../l10n/strings.dart';
@ -26,7 +27,13 @@ class AppDependencies {
library = LibraryController(db);
internalPages = InternalPages(
db: db, library: library, settings: settings, strings: this.strings);
browser = BrowserController(db: db, fetch: this.fetch, internalPages: internalPages);
internalActions = InternalActions(settings: settings);
browser = BrowserController(
db: db,
fetch: this.fetch,
internalPages: internalPages,
internalActions: internalActions,
);
}
/// Localized strings, also used to title the internal pages.
@ -38,6 +45,7 @@ class AppDependencies {
late final ReaderSettingsController settings;
late final LibraryController library;
late final InternalPages internalPages;
late final InternalActions internalActions;
Future<void> start() async {
await settings.load();

View file

@ -2,13 +2,13 @@ import 'package:flutter/foundation.dart' show defaultTargetPlatform, TargetPlatf
import 'package:flutter/material.dart';
import 'package:signals/signals_flutter.dart' show SignalBuilder;
import '../../application/internal_pages.dart';
import '../../application/pages/mews_urls.dart';
import '../app.dart';
/// The single-field address bar. The left icon opens the settings page and,
/// on pointer platforms, carries the back and forward buttons; the right
/// icons reload, subscribe (only when the page offers something to subscribe
/// to) and bookmark the current page.
/// The single-field address bar. The left icon opens the hub and, on pointer
/// platforms, carries the back and forward buttons; the right icons reload,
/// subscribe (only when the page offers something to subscribe to) and
/// bookmark the current page.
class AddressBar extends StatefulWidget {
const AddressBar({super.key});
@ -65,10 +65,17 @@ class _AddressBarState extends State<AddressBar> {
// Only pages with dated entry links or an Atom feed can be subscribed
// to (mews spec, section 6).
final canSubscribe = page != null &&
!InternalPages.isInternal(page.url) &&
!MewsUrls.isInternal(page.url) &&
(page.atomFeedHref != null || page.entries.isNotEmpty);
final canBookmark =
page != null && !InternalPages.isInternal(page.url);
final canBookmark = page != null && !MewsUrls.isInternal(page.url);
// One button, two layouts: on pointer platforms it sits beside the
// back and forward buttons.
final hubButton = IconButton(
icon: const Icon(Icons.menu),
tooltip: strings.t('reader-open-hub'),
onPressed: () => deps.browser.open(MewsUrls.hub),
);
return Padding(
padding: const EdgeInsets.fromLTRB(8, 8, 8, 4),
@ -93,12 +100,7 @@ class _AddressBarState extends State<AddressBar> {
? Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.tune),
tooltip: strings.t('reader-open-settings'),
onPressed: () =>
deps.browser.open(InternalPages.settingsUrl),
),
hubButton,
IconButton(
icon: const Icon(Icons.arrow_back),
tooltip: strings.t('reader-back'),
@ -115,12 +117,7 @@ class _AddressBarState extends State<AddressBar> {
),
],
)
: IconButton(
icon: const Icon(Icons.tune),
tooltip: strings.t('reader-open-settings'),
onPressed: () =>
deps.browser.open(InternalPages.settingsUrl),
),
: hubButton,
prefixIconConstraints: hasButtons
? const BoxConstraints(minWidth: 138, minHeight: 48)
: null,
@ -140,8 +137,8 @@ class _AddressBarState extends State<AddressBar> {
: Icons.notifications_outlined,
),
tooltip: deps.library.isSubscribed(page.url)
? strings.t('settings-unsubscribe')
: strings.t('settings-subscribe'),
? strings.t('reader-unsubscribe')
: strings.t('reader-subscribe'),
onPressed: () => deps.library
.toggleSubscription(page.url, page.title, page.entries),
),
@ -153,8 +150,8 @@ class _AddressBarState extends State<AddressBar> {
: Icons.star_border,
),
tooltip: deps.library.isBookmarked(page.url)
? strings.t('settings-bookmark-remove')
: strings.t('settings-bookmark-add'),
? strings.t('reader-bookmark-remove')
: strings.t('reader-bookmark-add'),
onPressed: () =>
deps.library.toggleBookmark(page.url, page.title),
),