fix(discover): open server tasks with remote

close #1272
This commit is contained in:
edde746
2026-06-08 08:23:57 +02:00
parent 42d9168941
commit d44a8994ce
4 changed files with 87 additions and 5 deletions
+5 -1
View File
@@ -212,6 +212,7 @@ class _DiscoverScreenState extends State<DiscoverScreen>
// Hero and app bar focus
late FocusNode _heroFocusNode;
final _actionBarKey = GlobalKey<FocusableActionBarState>();
final _serverActivitiesButtonKey = GlobalKey<ServerActivitiesButtonState>();
final _userMenuKey = GlobalKey<AppMenuButtonState<String>>();
/// Backend-neutral hero client lookup. Returns the actual
@@ -1334,7 +1335,10 @@ class _DiscoverScreenState extends State<DiscoverScreen>
// a permanently empty popover.
if (PlatformDetector.isDesktop(context) &&
context.select<MultiServerProvider, bool>((p) => p.hasOnlinePlexServers))
const FocusableAction(child: ServerActivitiesButton()),
FocusableAction(
onPressed: () => _serverActivitiesButtonKey.currentState?.togglePanel(),
child: ServerActivitiesButton(key: _serverActivitiesButtonKey),
),
// User menu — profiles + sign out
_buildUserMenuAction(context),
],
+4 -4
View File
@@ -16,7 +16,7 @@ class ServerActivitiesButton extends StatefulWidget {
const ServerActivitiesButton({super.key});
@override
State<ServerActivitiesButton> createState() => _ServerActivitiesButtonState();
State<ServerActivitiesButton> createState() => ServerActivitiesButtonState();
}
enum _FetchState { loading, loaded, error }
@@ -38,7 +38,7 @@ class _PanelData {
static const loading = _PanelData(fetchState: _FetchState.loading, results: []);
}
class _ServerActivitiesButtonState extends State<ServerActivitiesButton> {
class ServerActivitiesButtonState extends State<ServerActivitiesButton> {
final _buttonKey = GlobalKey();
OverlayEntry? _overlayEntry;
final _panelNotifier = ValueNotifier<_PanelData>(_PanelData.loading);
@@ -64,7 +64,7 @@ class _ServerActivitiesButtonState extends State<ServerActivitiesButton> {
_overlayEntry = null;
}
void _togglePanel() {
void togglePanel() {
if (_overlayEntry != null) {
_removeOverlay();
return;
@@ -343,7 +343,7 @@ class _ServerActivitiesButtonState extends State<ServerActivitiesButton> {
return IconButton(
key: _buttonKey,
icon: const AppIcon(Symbols.monitor_heart_rounded, color: Colors.white),
onPressed: _togglePanel,
onPressed: togglePanel,
tooltip: t.serverTasks.title,
);
}
+28
View File
@@ -194,6 +194,34 @@ void main() {
expect(FocusManager.instance.primaryFocus?.debugLabel, 'left-target');
});
testWidgets('invokes custom child action on select', (tester) async {
final key = GlobalKey<FocusableActionBarState>();
var activations = 0;
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: FocusableActionBar(
key: key,
actions: [FocusableAction(onPressed: () => activations++, child: const SizedBox(width: 48, height: 48))],
),
),
),
);
await tester.pump();
key.currentState!.requestFocusOnFirst();
await tester.pump();
expect(FocusManager.instance.primaryFocus?.debugLabel, 'ActionBar[0]');
await tester.sendKeyDownEvent(LogicalKeyboardKey.select);
await tester.pump();
await tester.sendKeyUpEvent(LogicalKeyboardKey.select);
await tester.pump();
expect(activations, 1);
});
testWidgets('moves through detail actions when trailer is inserted before shuffle', (tester) async {
final play = FocusNode(debugLabel: 'detail_play');
final outside = FocusNode(debugLabel: 'outside');
@@ -0,0 +1,50 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:plezy/i18n/strings.g.dart';
import 'package:plezy/providers/multi_server_provider.dart';
import 'package:plezy/services/data_aggregation_service.dart';
import 'package:plezy/services/multi_server_manager.dart';
import 'package:plezy/widgets/server_activities_button.dart';
import 'package:provider/provider.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
setUp(() {
LocaleSettings.setLocaleSync(AppLocale.en);
});
testWidgets('togglePanel opens and closes the server activities overlay', (tester) async {
final manager = MultiServerManager();
final multiServerProvider = MultiServerProvider(manager, DataAggregationService(manager));
final buttonKey = GlobalKey<ServerActivitiesButtonState>();
addTearDown(() {
multiServerProvider.dispose();
manager.dispose();
});
await tester.pumpWidget(
TranslationProvider(
child: ChangeNotifierProvider<MultiServerProvider>.value(
value: multiServerProvider,
child: MaterialApp(
home: Scaffold(body: ServerActivitiesButton(key: buttonKey)),
),
),
),
);
buttonKey.currentState!.togglePanel();
await tester.pump();
await tester.pump();
expect(find.text(t.serverTasks.title), findsOneWidget);
expect(find.text(t.serverTasks.noTasks), findsOneWidget);
buttonKey.currentState!.togglePanel();
await tester.pump();
expect(find.text(t.serverTasks.title), findsNothing);
});
}