@@ -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),
|
||||
],
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user