fix(tvos): dismiss overlays with back

This commit is contained in:
edde746
2026-05-03 01:50:26 +02:00
parent 876a44b244
commit 20953152b6
3 changed files with 109 additions and 97 deletions
+3
View File
@@ -836,6 +836,9 @@ class _MainAppState extends State<MainApp> with WidgetsBindingObserver {
...WidgetsApp.defaultShortcuts,
const SingleActivator(LogicalKeyboardKey.select): const ActivateIntent(),
const SingleActivator(LogicalKeyboardKey.gameButtonA): const ActivateIntent(),
const SingleActivator(LogicalKeyboardKey.goBack): const DismissIntent(),
const SingleActivator(LogicalKeyboardKey.browserBack): const DismissIntent(),
const SingleActivator(LogicalKeyboardKey.gameButtonB): const DismissIntent(),
},
builder: (context, child) => ScaffoldMessenger(
key: rootScaffoldMessengerKey,
+4
View File
@@ -893,6 +893,10 @@ class _MainScreenState extends State<MainScreen> with RouteAware, WindowListener
bool _suppressBackAfterPop = false;
KeyEventResult _handleBackKey(KeyEvent event) {
if (ModalRoute.of(context)?.isCurrent != true) {
return KeyEventResult.ignored;
}
if (_suppressBackAfterPop && event.logicalKey.isBackKey) {
if (event is KeyUpEvent) _suppressBackAfterPop = false;
return KeyEventResult.handled;
@@ -9,6 +9,7 @@ import '../../profiles/plex_home_service.dart';
import '../../profiles/profile_connection_registry.dart';
import '../../providers/companion_remote_provider.dart';
import '../../focus/focusable_button.dart';
import '../../focus/key_event_utils.dart';
import '../../utils/app_logger.dart';
class RemoteSessionDialog extends StatefulWidget {
@@ -99,109 +100,113 @@ class _RemoteSessionDialogState extends State<RemoteSessionDialog> {
@override
Widget build(BuildContext context) {
return Consumer<CompanionRemoteProvider>(
builder: (context, provider, child) {
if (_isStarting) {
return Dialog(
child: Padding(
padding: const EdgeInsets.all(32.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(),
const SizedBox(height: 16),
Text(t.companionRemote.session.startingServer, style: Theme.of(context).textTheme.titleMedium),
],
),
),
);
}
if (_errorMessage != null) {
return AlertDialog(
title: Text(t.common.error),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(t.companionRemote.session.failedToCreate),
const SizedBox(height: 8),
Text(_errorMessage!, style: const TextStyle(fontFamily: 'monospace')),
],
),
actions: [
TextButton(onPressed: () => Navigator.of(context).pop(), child: Text(t.common.close)),
TextButton(onPressed: _ensureServerRunning, child: Text(t.common.retry)),
],
);
}
return Dialog(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 500),
child: SingleChildScrollView(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
children: [
const Icon(Icons.phone_android, size: 32),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(t.companionRemote.title, style: Theme.of(context).textTheme.headlineSmall),
const SizedBox(height: 4),
_buildStatusLine(context, provider),
],
),
),
IconButton(icon: const Icon(Icons.close), onPressed: () => Navigator.of(context).pop()),
],
),
const SizedBox(height: 24),
// Server status card
_buildServerStatus(context, provider),
// Connected device info
if (provider.connectedDevice != null) ...[
return Focus(
autofocus: true,
onKeyEvent: (node, event) => handleBackKeyNavigation(context, event),
child: Consumer<CompanionRemoteProvider>(
builder: (context, provider, child) {
if (_isStarting) {
return Dialog(
child: Padding(
padding: const EdgeInsets.all(32.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(),
const SizedBox(height: 16),
_buildConnectedDevice(context, provider),
Text(t.companionRemote.session.startingServer, style: Theme.of(context).textTheme.titleMedium),
],
),
),
);
}
const SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton.icon(
onPressed: _toggleServer,
icon: Icon(provider.isHostServerRunning ? Icons.stop : Icons.play_arrow),
label: Text(
provider.isHostServerRunning
? t.companionRemote.session.stopServer
: t.companionRemote.session.startServer,
),
),
const SizedBox(width: 8),
FocusableButton(
onPressed: () => Navigator.of(context).pop(),
child: FilledButton(
onPressed: () => Navigator.of(context).pop(),
child: Text(t.companionRemote.session.minimize),
),
),
],
),
if (_errorMessage != null) {
return AlertDialog(
title: Text(t.common.error),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(t.companionRemote.session.failedToCreate),
const SizedBox(height: 8),
Text(_errorMessage!, style: const TextStyle(fontFamily: 'monospace')),
],
),
actions: [
TextButton(onPressed: () => Navigator.of(context).pop(), child: Text(t.common.close)),
TextButton(onPressed: _ensureServerRunning, child: Text(t.common.retry)),
],
);
}
return Dialog(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 500),
child: SingleChildScrollView(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
children: [
const Icon(Icons.phone_android, size: 32),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(t.companionRemote.title, style: Theme.of(context).textTheme.headlineSmall),
const SizedBox(height: 4),
_buildStatusLine(context, provider),
],
),
),
IconButton(icon: const Icon(Icons.close), onPressed: () => Navigator.of(context).pop()),
],
),
const SizedBox(height: 24),
// Server status card
_buildServerStatus(context, provider),
// Connected device info
if (provider.connectedDevice != null) ...[
const SizedBox(height: 16),
_buildConnectedDevice(context, provider),
],
const SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton.icon(
onPressed: _toggleServer,
icon: Icon(provider.isHostServerRunning ? Icons.stop : Icons.play_arrow),
label: Text(
provider.isHostServerRunning
? t.companionRemote.session.stopServer
: t.companionRemote.session.startServer,
),
),
const SizedBox(width: 8),
FocusableButton(
onPressed: () => Navigator.of(context).pop(),
child: FilledButton(
onPressed: () => Navigator.of(context).pop(),
child: Text(t.companionRemote.session.minimize),
),
),
],
),
],
),
),
),
),
);
},
);
},
),
);
}