fix(android): pressing back while the player is open doesn't take to previous page

#1388
This commit is contained in:
Kingkor Roy Tirtho 2024-09-15 14:53:41 +06:00
parent 9cb828bb55
commit 5ff36a8643
5 changed files with 123 additions and 13 deletions

View File

@ -0,0 +1,104 @@
import 'dart:io';
import 'package:flutter/material.dart';
/// A temporary workaround for [WillPopScope] and [PopScope] not working in GoRouter
/// https://github.com/flutter/flutter/issues/140869#issuecomment-2247181468
class AppPopScope extends StatefulWidget {
final Widget child;
final PopInvokedCallback? onPopInvoked;
final bool canPop;
const AppPopScope({
super.key,
required this.child,
this.canPop = true,
this.onPopInvoked,
});
@override
State<AppPopScope> createState() => _AppPopScopeState();
}
class _AppPopScopeState extends State<AppPopScope> {
final bool _enable = Platform.isAndroid;
ModalRoute? _route;
BackButtonDispatcher? _parentBackBtnDispatcher;
ChildBackButtonDispatcher? _backBtnDispatcher;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_route = ModalRoute.of(context);
_updateBackButtonDispatcher();
}
@override
void activate() {
super.activate();
_updateBackButtonDispatcher();
}
@override
void deactivate() {
super.deactivate();
_disposeBackBtnDispatcher();
}
@override
void dispose() {
_disposeBackBtnDispatcher();
super.dispose();
}
@override
Widget build(BuildContext context) {
return PopScope(
canPop: widget.canPop,
onPopInvoked: widget.onPopInvoked,
child: widget.child,
);
}
void _updateBackButtonDispatcher() {
if (!_enable) return;
var dispatcher = Router.maybeOf(context)?.backButtonDispatcher;
if (dispatcher != _parentBackBtnDispatcher) {
_disposeBackBtnDispatcher();
_parentBackBtnDispatcher = dispatcher;
if (dispatcher is BackButtonDispatcher &&
dispatcher is! ChildBackButtonDispatcher) {
dispatcher = dispatcher.createChildBackButtonDispatcher();
}
_backBtnDispatcher = dispatcher as ChildBackButtonDispatcher;
}
_backBtnDispatcher?.removeCallback(_handleBackButton);
_backBtnDispatcher?.addCallback(_handleBackButton);
_backBtnDispatcher?.takePriority();
}
void _disposeBackBtnDispatcher() {
_backBtnDispatcher?.removeCallback(_handleBackButton);
if (_backBtnDispatcher is ChildBackButtonDispatcher) {
final child = _backBtnDispatcher as ChildBackButtonDispatcher;
_parentBackBtnDispatcher?.forget(child);
}
_backBtnDispatcher = null;
_parentBackBtnDispatcher = null;
}
bool get _onlyRoute => _route != null && _route!.isFirst && _route!.isCurrent;
Future<bool> _handleBackButton() async {
if (_onlyRoute) {
widget.onPopInvoked?.call(widget.canPop);
if (!widget.canPop) {
return true;
}
}
return false;
}
}

View File

@ -6,6 +6,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/assets.gen.dart';
import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/components/framework/app_pop_scope.dart';
import 'package:spotube/modules/player/player_actions.dart'; import 'package:spotube/modules/player/player_actions.dart';
import 'package:spotube/modules/player/player_controls.dart'; import 'package:spotube/modules/player/player_controls.dart';
import 'package:spotube/modules/player/player_queue.dart'; import 'package:spotube/modules/player/player_queue.dart';
@ -100,11 +101,11 @@ class PlayerView extends HookConsumerWidget {
final topPadding = MediaQueryData.fromView(View.of(context)).padding.top; final topPadding = MediaQueryData.fromView(View.of(context)).padding.top;
// ignore: deprecated_member_use return AppPopScope(
return WillPopScope( canPop: context.canPop(),
onWillPop: () async { onPopInvoked: (didPop) async {
if (didPop) return;
await panelController.close(); await panelController.close();
return false;
}, },
child: IconTheme( child: IconTheme(
data: theme.iconTheme.copyWith(color: bodyTextColor), data: theme.iconTheme.copyWith(color: bodyTextColor),

View File

@ -6,6 +6,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/components/framework/app_pop_scope.dart';
import 'package:spotube/modules/player/player_queue.dart'; import 'package:spotube/modules/player/player_queue.dart';
import 'package:spotube/components/dialogs/replace_downloaded_dialog.dart'; import 'package:spotube/components/dialogs/replace_downloaded_dialog.dart';
import 'package:spotube/modules/root/bottom_player.dart'; import 'package:spotube/modules/root/bottom_player.dart';
@ -30,10 +31,12 @@ class RootApp extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final theme = Theme.of(context);
final routerState = GoRouterState.of(context);
final showingDialogCompleter = useRef(Completer()..complete()); final showingDialogCompleter = useRef(Completer()..complete());
final downloader = ref.watch(downloadManagerProvider); final downloader = ref.watch(downloadManagerProvider);
final scaffoldMessenger = ScaffoldMessenger.of(context); final scaffoldMessenger = ScaffoldMessenger.of(context);
final theme = Theme.of(context);
final connectRoutes = ref.watch(serverConnectRoutesProvider); final connectRoutes = ref.watch(serverConnectRoutesProvider);
useEffect(() { useEffect(() {
@ -164,15 +167,17 @@ class RootApp extends HookConsumerWidget {
return null; return null;
}, [backgroundColor]); }, [backgroundColor]);
// ignore: deprecated_member_use return AppPopScope(
return WillPopScope( // Only allow to pop when in root screen
onWillPop: () async { canPop: routerState.namedLocation(HomePage.name) ==
routerState.matchedLocation,
onPopInvoked: (didPop) async {
if (didPop) return;
final routerState = GoRouterState.of(context); final routerState = GoRouterState.of(context);
if (routerState.matchedLocation != "/") { if (routerState.matchedLocation != "/") {
context.goNamed(HomePage.name); context.goNamed(HomePage.name);
return false;
} }
return true;
}, },
child: Scaffold( child: Scaffold(
body: Sidebar(child: child), body: Sidebar(child: child),

View File

@ -1006,10 +1006,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: go_router name: go_router
sha256: c5fa45fa502ee880839e3b2152d987c44abae26d064a2376d4aad434cf0f7b15 sha256: "2ddb88e9ad56ae15ee144ed10e33886777eb5ca2509a914850a5faa7b52ff459"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "12.1.3" version: "14.2.7"
google_fonts: google_fonts:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -51,7 +51,6 @@ dependencies:
flutter_svg: ^1.1.6 flutter_svg: ^1.1.6
form_validator: ^2.1.1 form_validator: ^2.1.1
fuzzywuzzy: ^1.1.6 fuzzywuzzy: ^1.1.6
go_router: 12.1.3 # Stuck on this https://github.com/flutter/flutter/issues/140869
google_fonts: ^6.2.1 google_fonts: ^6.2.1
hive: ^2.2.3 hive: ^2.2.3
hive_flutter: ^1.1.0 hive_flutter: ^1.1.0
@ -135,6 +134,7 @@ dependencies:
sqlite3_flutter_libs: ^0.5.23 sqlite3_flutter_libs: ^0.5.23
sqlite3: ^2.4.3 sqlite3: ^2.4.3
encrypt: ^5.0.3 encrypt: ^5.0.3
go_router: ^14.2.7
dev_dependencies: dev_dependencies:
build_runner: ^2.4.9 build_runner: ^2.4.9