Files
Ensemble/lib/screens/home_screen.dart
Your NameandClaude Opus 4.5 01ea21917a Fix Android back button to close queue panel before collapsing player
The back button handling in home_screen.dart was checking for expanded
player but not for queue panel. Since home_screen's PopScope intercepts
all back presses (canPop: false), the expandable_player's PopScope was
never reached.

Added:
- closeQueuePanel() method to ExpandablePlayerState
- isQueuePanelOpen and closeQueuePanel() static accessors to GlobalPlayerOverlay
- Queue panel check in home_screen.dart back button handler (before player check)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 20:58:35 +00:00

135 lines
4.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import '../l10n/app_localizations.dart';
import '../providers/navigation_provider.dart';
import '../widgets/global_player_overlay.dart';
import 'new_home_screen.dart';
import 'new_library_screen.dart';
import 'search_screen.dart';
import 'settings_screen.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final GlobalKey<SearchScreenState> _searchScreenKey = GlobalKey<SearchScreenState>();
DateTime? _lastBackPress;
@override
void initState() {
super.initState();
// Register search focus callback with navigation provider
navigationProvider.onSearchTabSelected = () {
_searchScreenKey.currentState?.requestFocus();
};
}
@override
void dispose() {
// Clean up callback
navigationProvider.onSearchTabSelected = null;
super.dispose();
}
void _showExitSnackBar() {
ScaffoldMessenger.of(context).clearSnackBars();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(S.of(context)!.pressBackToMinimize),
duration: const Duration(seconds: 2),
behavior: SnackBarBehavior.floating,
margin: const EdgeInsets.only(bottom: 80, left: 16, right: 16),
),
);
}
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return ListenableBuilder(
listenable: navigationProvider,
builder: (context, _) {
final selectedIndex = navigationProvider.selectedIndex;
return PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, result) {
if (didPop) return;
// If player reveal (device list) is visible, dismiss it first (with animation)
if (GlobalPlayerOverlay.isPlayerRevealVisible) {
GlobalPlayerOverlay.dismissPlayerReveal();
return;
}
// If queue panel is open, close it first (before collapsing player)
if (GlobalPlayerOverlay.isQueuePanelOpen) {
GlobalPlayerOverlay.closeQueuePanel();
return;
}
// If global player is expanded, collapse it first
if (GlobalPlayerOverlay.isPlayerExpanded) {
GlobalPlayerOverlay.collapsePlayer();
return;
}
// If not on home tab, navigate to home
if (selectedIndex != 0) {
// If leaving Settings, show player again
if (selectedIndex == 3) {
GlobalPlayerOverlay.showPlayer();
}
navigationProvider.setSelectedIndex(0);
return;
}
// On home tab - check for double press to minimize
final now = DateTime.now();
if (_lastBackPress != null &&
now.difference(_lastBackPress!) < const Duration(seconds: 2)) {
// Double press detected - minimize app (move to background)
// This keeps the app running and connection alive
SystemNavigator.pop();
} else {
// First press, show message
_lastBackPress = now;
_showExitSnackBar();
}
},
child: Scaffold(
backgroundColor: colorScheme.surface,
// No bottomNavigationBar here - it's now in GlobalPlayerOverlay
body: Stack(
children: [
// Home and Library use IndexedStack for state preservation
Offstage(
offstage: selectedIndex > 1,
child: IndexedStack(
index: selectedIndex.clamp(0, 1),
children: const [
NewHomeScreen(),
NewLibraryScreen(),
],
),
),
// Search and Settings are conditionally rendered (removed from tree when not visible)
if (selectedIndex == 2)
SearchScreen(key: _searchScreenKey),
if (selectedIndex == 3)
const SettingsScreen(),
],
),
),
);
},
);
}
}