One app menu style for every picker; links go Through me by default

- AppSelect / AppMenuButton (widgets/app_menu.dart): glass menu anchored
  to its button, check on the current item, keyboard and Esc; replaces
  the Material dropdowns in Settings, player settings, Jellyfin and the
  member menu. Material menus elsewhere get the same surface by theme.
- Link page: Through me is the main choice (you can't know which sites
  need cookies); Everyone / Server fetches it sit under "Other ways".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
foxyzandClaude Opus 5.5 committed 2026-10-11 05:58:18 +03:00
1 parent 2a7b553597
commit 95cd668cfb
17 files changed
+630 -125

No files matched your search

+1 -1
View File
@@ -87,7 +87,7 @@ void main() {
expect(c.source, MediaKind.jellyfin);
c.pasteText(' https://example.com/a.mkv ');
expect(c.source, MediaKind.link);
expect(c.selection, const LinkMedia('https://example.com/a.mkv'));
expect(c.selection, const LinkMedia('https://example.com/a.mkv', relay: LinkRelay.me));
c.pasteText('/home/me/b.mkv');
expect(c.source, MediaKind.file);
expect(c.selection, const FileMedia('/home/me/b.mkv'));
@@ -307,7 +307,7 @@ void main() {
final c = MediaPickerController();
expect(c.selection, isNull);
c.pasteText('https://example.com/a.mkv');
expect(c.selection, const LinkMedia('https://example.com/a.mkv'));
expect(c.selection, const LinkMedia('https://example.com/a.mkv', relay: LinkRelay.me));
c.pasteText('/home/me/b.mkv');
expect(c.selection, const FileMedia('/home/me/b.mkv'));
c.source = MediaKind.jellyfin;
+9
View File
@@ -281,9 +281,18 @@ void main() {
expect(find.descendant(of: find.byKey(const ValueKey('link-preview')), matching: find.text('A video')),
findsOneWidget);
expect(find.text('youtube.com · Chan'), findsOneWidget);
// Through me by default; the other two behind "Other ways".
expect(h.controller.linkRelay, LinkRelay.me);
expect(find.byKey(const ValueKey('link-mode-direct')), findsNothing);
await tester.tap(find.byKey(const ValueKey('link-other-ways')));
await settle(tester);
await tester.tap(find.byKey(const ValueKey('link-mode-server')));
await settle(tester);
expect(h.controller.linkRelay, LinkRelay.server);
await tester.tap(find.byKey(const ValueKey('link-mode-me')));
await settle(tester);
expect(h.controller.linkRelay, LinkRelay.me);
expect(find.byKey(const ValueKey('link-mode-direct')), findsOneWidget, reason: 'stays open until closed');
expect(find.text(linkRelayHelp(LinkRelay.me)), findsOneWidget);
await tester.tap(find.byKey(const ValueKey('link-put-up')));
await settle(tester, 10);
+3 -2
View File
@@ -16,6 +16,7 @@ import 'package:watch_together/src/shaders/shader_presets.dart';
import 'package:watch_together/src/shell/settings_tab.dart';
import 'package:watch_together/src/state/settings.dart';
import 'package:watch_together/src/update/update_controller.dart';
import 'package:watch_together/src/widgets/app_menu.dart';
// The experimental mpv-style (uosc) controls, piece by piece (never the
// session screen or a media_kit `Video`).
@@ -466,12 +467,12 @@ void main() {
));
final design = find.byKey(const ValueKey('player-design'));
expect(find.text('Player design'), findsOneWidget);
expect(tester.widget<DropdownButton<bool>>(design).value, isFalse);
expect(tester.widget<AppSelect<bool>>(design).value, isFalse);
await tester.tap(design);
await tester.pumpAndSettle();
await tester.tap(find.text('uosc').last);
await tester.pumpAndSettle();
expect(s.mpvControls.value, isTrue);
expect(tester.widget<DropdownButton<bool>>(design).value, isTrue);
expect(tester.widget<AppSelect<bool>>(design).value, isTrue);
});
}