mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2025-12-06 11:09:28 +00:00
intercept back button to minimize player first
and also navigate stack of branches like youtube
This commit is contained in:
parent
ed236ef117
commit
402e264137
4 changed files with 106 additions and 68 deletions
|
|
@ -58,10 +58,4 @@ double playerHeight(
|
||||||
return playerExpandProgress.value;
|
return playerExpandProgress.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// a final MiniplayerController controller = MiniplayerController();
|
final audioBookMiniplayerController = MiniplayerController();
|
||||||
@Riverpod(keepAlive: true)
|
|
||||||
Raw<MiniplayerController> miniplayerController(
|
|
||||||
MiniplayerControllerRef ref,
|
|
||||||
) {
|
|
||||||
return MiniplayerController();
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -38,22 +38,5 @@ final playerHeightProvider = Provider<double>.internal(
|
||||||
);
|
);
|
||||||
|
|
||||||
typedef PlayerHeightRef = ProviderRef<double>;
|
typedef PlayerHeightRef = ProviderRef<double>;
|
||||||
String _$miniplayerControllerHash() =>
|
|
||||||
r'a3677e63a9823881f45a12855e74bf558322e0ec';
|
|
||||||
|
|
||||||
/// See also [miniplayerController].
|
|
||||||
@ProviderFor(miniplayerController)
|
|
||||||
final miniplayerControllerProvider =
|
|
||||||
Provider<Raw<MiniplayerController>>.internal(
|
|
||||||
miniplayerController,
|
|
||||||
name: r'miniplayerControllerProvider',
|
|
||||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$miniplayerControllerHash,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef MiniplayerControllerRef = ProviderRef<Raw<MiniplayerController>>;
|
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ class AudiobookPlayer extends HookConsumerWidget {
|
||||||
minHeight: playerMinHeight,
|
minHeight: playerMinHeight,
|
||||||
// subtract the height of notches and other system UI
|
// subtract the height of notches and other system UI
|
||||||
maxHeight: playerMaxHeight,
|
maxHeight: playerMaxHeight,
|
||||||
controller: ref.watch(miniplayerControllerProvider),
|
controller: audioBookMiniplayerController,
|
||||||
elevation: 4,
|
elevation: 4,
|
||||||
onDismissed: () {
|
onDismissed: () {
|
||||||
// add a delay before closing the player
|
// add a delay before closing the player
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,16 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.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:miniplayer/miniplayer.dart';
|
||||||
import 'package:whispering_pages/features/explore/providers/search_controller.dart';
|
import 'package:whispering_pages/features/explore/providers/search_controller.dart';
|
||||||
import 'package:whispering_pages/features/player/providers/player_form.dart';
|
import 'package:whispering_pages/features/player/providers/player_form.dart';
|
||||||
import 'package:whispering_pages/features/player/view/audiobook_player.dart';
|
import 'package:whispering_pages/features/player/view/audiobook_player.dart';
|
||||||
|
|
||||||
|
// stack to track changes in navigationShell.currentIndex
|
||||||
|
// home is always at index 0 and at the start and should be the last before popping
|
||||||
|
// if stack is empty, push home, if already contains home, pop it
|
||||||
|
final Set<int> navigationShellStack = {};
|
||||||
|
|
||||||
/// Builds the "shell" for the app by building a Scaffold with a
|
/// Builds the "shell" for the app by building a Scaffold with a
|
||||||
/// BottomNavigationBar, where [child] is placed in the body of the Scaffold.
|
/// BottomNavigationBar, where [child] is placed in the body of the Scaffold.
|
||||||
class ScaffoldWithNavBar extends HookConsumerWidget {
|
class ScaffoldWithNavBar extends HookConsumerWidget {
|
||||||
|
|
@ -30,52 +36,100 @@ class ScaffoldWithNavBar extends HookConsumerWidget {
|
||||||
// Clamp the value between 0 and 1
|
// Clamp the value between 0 and 1
|
||||||
percentExpanded = percentExpanded.clamp(0.0, 1.0);
|
percentExpanded = percentExpanded.clamp(0.0, 1.0);
|
||||||
|
|
||||||
final SearchController searchController =
|
onBackButtonPressed() async {
|
||||||
ref.watch(globalSearchControllerProvider);
|
final isPlayerExpanded = playerProgress != playerMinHeight;
|
||||||
|
|
||||||
return Scaffold(
|
debugPrint(
|
||||||
body: Stack(
|
'BackButtonListener: Back button pressed, isPlayerExpanded: $isPlayerExpanded, stack: $navigationShellStack',
|
||||||
children: [
|
);
|
||||||
navigationShell,
|
// close miniplayer if it is open
|
||||||
const AudiobookPlayer(),
|
if (isPlayerExpanded) {
|
||||||
],
|
debugPrint(
|
||||||
),
|
'BackButtonListener: closing the player',
|
||||||
bottomNavigationBar: Opacity(
|
);
|
||||||
// Opacity is interpolated from 1 to 0 when player is expanded
|
audioBookMiniplayerController.animateToHeight(state: PanelState.MIN);
|
||||||
opacity: 1 - percentExpanded,
|
return true;
|
||||||
child: SizedBox(
|
}
|
||||||
// height is interpolated from 0 to 56 when player is expanded
|
|
||||||
height: 56 * (1 - percentExpanded),
|
|
||||||
|
|
||||||
child: BottomNavigationBar(
|
// do the the following only if the current branch has nothing to pop
|
||||||
elevation: 0.0,
|
final canPop = GoRouter.of(context).canPop();
|
||||||
landscapeLayout: BottomNavigationBarLandscapeLayout.centered,
|
|
||||||
selectedFontSize:
|
|
||||||
Theme.of(context).textTheme.labelMedium!.fontSize!,
|
|
||||||
unselectedFontSize:
|
|
||||||
Theme.of(context).textTheme.labelMedium!.fontSize!,
|
|
||||||
showUnselectedLabels: false,
|
|
||||||
fixedColor: Theme.of(context).colorScheme.onSurface,
|
|
||||||
enableFeedback: true,
|
|
||||||
type: BottomNavigationBarType.fixed,
|
|
||||||
|
|
||||||
// Here, the items of BottomNavigationBar are hard coded. In a real
|
if (canPop) {
|
||||||
// world scenario, the items would most likely be generated from the
|
debugPrint(
|
||||||
// branches of the shell route, which can be fetched using
|
'BackButtonListener: passing it to the router as canPop is true',
|
||||||
// `navigationShell.route.branches`.
|
);
|
||||||
items: _navigationItems
|
return false;
|
||||||
.map(
|
}
|
||||||
(item) => BottomNavigationBarItem(
|
|
||||||
icon: Icon(item.icon),
|
if (navigationShellStack.isNotEmpty) {
|
||||||
activeIcon: item.activeIcon != null
|
// pop the last index from the stack and navigate to it
|
||||||
? Icon(item.activeIcon)
|
final index = navigationShellStack.last;
|
||||||
: Icon(item.icon),
|
navigationShellStack.remove(index);
|
||||||
label: item.name,
|
debugPrint('BackButtonListener: popping the stack, index: $index');
|
||||||
),
|
|
||||||
)
|
// if the stack is empty, navigate to home else navigate to the last index
|
||||||
.toList(),
|
if (navigationShellStack.isNotEmpty) {
|
||||||
currentIndex: navigationShell.currentIndex,
|
navigationShell.goBranch(navigationShellStack.last);
|
||||||
onTap: (int index) => _onTap(context, index, ref),
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (navigationShell.currentIndex != 0) {
|
||||||
|
// if the stack is empty and the current branch is not home, navigate to home
|
||||||
|
debugPrint('BackButtonListener: navigating to home');
|
||||||
|
navigationShell.goBranch(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
debugPrint('BackButtonListener: passing it to the router');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BackButtonListener(
|
||||||
|
onBackButtonPressed: onBackButtonPressed,
|
||||||
|
child: Scaffold(
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
navigationShell,
|
||||||
|
const AudiobookPlayer(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
bottomNavigationBar: Opacity(
|
||||||
|
// Opacity is interpolated from 1 to 0 when player is expanded
|
||||||
|
opacity: 1 - percentExpanded,
|
||||||
|
child: SizedBox(
|
||||||
|
// height is interpolated from 0 to 56 when player is expanded
|
||||||
|
height: 56 * (1 - percentExpanded),
|
||||||
|
|
||||||
|
child: BottomNavigationBar(
|
||||||
|
elevation: 0.0,
|
||||||
|
landscapeLayout: BottomNavigationBarLandscapeLayout.centered,
|
||||||
|
selectedFontSize:
|
||||||
|
Theme.of(context).textTheme.labelMedium!.fontSize!,
|
||||||
|
unselectedFontSize:
|
||||||
|
Theme.of(context).textTheme.labelMedium!.fontSize!,
|
||||||
|
showUnselectedLabels: false,
|
||||||
|
fixedColor: Theme.of(context).colorScheme.onSurface,
|
||||||
|
enableFeedback: true,
|
||||||
|
type: BottomNavigationBarType.fixed,
|
||||||
|
|
||||||
|
// Here, the items of BottomNavigationBar are hard coded. In a real
|
||||||
|
// world scenario, the items would most likely be generated from the
|
||||||
|
// branches of the shell route, which can be fetched using
|
||||||
|
// `navigationShell.route.branches`.
|
||||||
|
items: _navigationItems
|
||||||
|
.map(
|
||||||
|
(item) => BottomNavigationBarItem(
|
||||||
|
icon: Icon(item.icon),
|
||||||
|
activeIcon: item.activeIcon != null
|
||||||
|
? Icon(item.activeIcon)
|
||||||
|
: Icon(item.icon),
|
||||||
|
label: item.name,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
currentIndex: navigationShell.currentIndex,
|
||||||
|
onTap: (int index) => _onTap(context, index, ref),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -97,6 +151,13 @@ class ScaffoldWithNavBar extends HookConsumerWidget {
|
||||||
initialLocation: index == navigationShell.currentIndex,
|
initialLocation: index == navigationShell.currentIndex,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// add the index to the stack but remove it if it is already there
|
||||||
|
if (navigationShellStack.contains(index)) {
|
||||||
|
navigationShellStack.remove(index);
|
||||||
|
}
|
||||||
|
navigationShellStack.add(index);
|
||||||
|
debugPrint('Tapped index: $index, stack: $navigationShellStack');
|
||||||
|
|
||||||
// Check if the current branch is the same as the branch that was tapped.
|
// Check if the current branch is the same as the branch that was tapped.
|
||||||
// If it is, debugPrint a message to the console.
|
// If it is, debugPrint a message to the console.
|
||||||
if (index == navigationShell.currentIndex) {
|
if (index == navigationShell.currentIndex) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue