Open RaphiTobi opened 3 weeks ago
I have the same issue.
If I downgrade version to ^8.1.2
it works fine. but from ^9.0.0
it throws same error.
The same issue
downgrade version to ^8.1.2.. this works completely fine. Once again thanks @hayatshin .
I can confirm this issue occurs whenever a parent widget calls Navigator.of(context).pop().
Fix #977 resolves the issue for me.
Setting the package version in flutter manually to 9.0.1 fixes the issue for now.
As a temporary solution, I resolved the issue by adding a check for didPop in my case.
youtube_player_flutter: ^9.0.3
Flutter 3.24.1 • channel stable • https://github.com/flutter/flutter.git Framework • revision 5874a72aa4 (2 weeks ago) • 2024-08-20 16:46:00 -0500 Engine • revision c9b9d5780d Tools • Dart 3.5.1 • DevTools 2.37.2
Is there an existing issue for this?
Package
youtube_player_flutter
What happened?
I used a YoutubePlayerBuilder on a ModalBottomSheet, this works like expected exept for when I close the Dialog, closing the dialog with
Navigator.pop(context);
causes the following error: ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════ The following assertion was thrown while handling a gesture: 'package:flutter/src/widgets/navigator.dart': Failed assertion: line 5350 pos 12: '!_debugLocked': is not true.Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause. In either case, please report this assertion by filing a bug on GitHub: https://github.com/flutter/flutter/issues/new?template=2_bug.yml
When the exception was thrown, this was the stack:
2 NavigatorState.pop (package:flutter/src/widgets/navigator.dart:5350:12)
3 Navigator.pop (package:flutter/src/widgets/navigator.dart:2665:27)
4 _YoutubePlayerBuilderState.build. (package:youtube_player_flutter/src/widgets/youtube_player_builder.dart:77:23)
5 PopScope._callPopInvoked (package:flutter/src/widgets/pop_scope.dart:140:19)
6 _PopScopeState.onPopInvokedWithResult (package:flutter/src/widgets/pop_scope.dart:172:12)
7 ModalRoute.onPopInvokedWithResult (package:flutter/src/widgets/routes.dart:1780:16)
8 _RouteEntry.handlePop (package:flutter/src/widgets/navigator.dart:3171:11)
9 NavigatorState._flushHistoryUpdates (package:flutter/src/widgets/navigator.dart:4340:22)
10 NavigatorState.pop (package:flutter/src/widgets/navigator.dart:5368:7)
11 Navigator.pop (package:flutter/src/widgets/navigator.dart:2665:27)
12 MainPage.build.... (package:ytplayertest/main.dart:68:56)
13 _InkResponseState.handleTap (package:flutter/src/material/ink_well.dart:1170:21)
14 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:351:24)
15 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:656:11)
16 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:313:5)
17 BaseTapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:283:7)
18 GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:169:27)
19 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:505:20)
20 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:481:22)
21 RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:450:11)
22 GestureBinding._handlePointerEventImmediately (package:flutter/src/gestures/binding.dart:426:7)
23 GestureBinding.handlePointerEvent (package:flutter/src/gestures/binding.dart:389:5)
24 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:336:7)
25 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:305:9)
26 _invoke1 (dart:ui/hooks.dart:328:13)
27 PlatformDispatcher._dispatchPointerDataPacket (dart:ui/platform_dispatcher.dart:442:7)
28 _dispatchPointerDataPacket (dart:ui/hooks.dart:262:31)
(elided 2 frames from class _AssertionError)
Handler: "onTap" Recognizer: TapGestureRecognizer#f4b36 ════════════════════════════════════════════════════════════════════════════════════════════════════
What is the expected behaviour?
The expected behavior is that the Dialog closes correcly without an error
How to reproduce?
I have modified the Example Application to reproduce the error: import 'dart:developer';
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:youtube_player_flutter/youtube_player_flutter.dart'; import 'package:ytplayertest/video_list.dart';
void main() { WidgetsFlutterBinding.ensureInitialized(); SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle( statusBarColor: Colors.blueAccent, ), ); runApp(const YoutubePlayerDemoApp()); } /// Creates [YoutubePlayerDemoApp] widget. class YoutubePlayerDemoApp extends StatelessWidget { const YoutubePlayerDemoApp({super.key});
@override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Youtube Player Flutter', theme: ThemeData( colorSchemeSeed: Colors.blue, appBarTheme: const AppBarTheme( color: Colors.blueAccent, titleTextStyle: TextStyle( color: Colors.white, fontWeight: FontWeight.w300, fontSize: 20, ), ), iconTheme: const IconThemeData( color: Colors.blueAccent, ), ), home: const MainPage(), ); } }
class MainPage extends StatelessWidget { const MainPage({super.key});
@override Widget build(BuildContext context) { return Center( child: TextButton( onPressed: () { showModalBottomSheet( context: context, isScrollControlled: true, builder: (_) { return DraggableScrollableSheet( expand: false, initialChildSize: 0.95, builder: (context, scrollController) { return Container( child: Column( children: [ Align( alignment: Alignment.center, child: IconButton( onPressed: () => Navigator.pop(context), icon: const Icon( Icons.expand_more_rounded, ), ) ), Flexible( child: ListView( children: const [ MyHomePage() ], ), ), ], ) ); } ); } ); }, child: const Text("Test in dialog") ) ); } }
/// Homepage class MyHomePage extends StatefulWidget { const MyHomePage({super.key});
@override State createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
late YoutubePlayerController _controller;
late TextEditingController _idController;
late TextEditingController _seekToController;
late PlayerState _playerState; late YoutubeMetaData _videoMetaData; double _volume = 100; bool _muted = false; bool _isPlayerReady = false;
final List _ids = [
'nPt8bK2gbaU',
'gQDByCdjUXw',
'iLnmTe5Q2Qw',
'_WoCV4c6XOE',
'KmzdUe0RSJo',
'6jZDSSZZxjQ',
'p2lYr3vM1w',
'7QUtEmBT-w',
'34_PXCzGw1M',
];
@override void initState() { super.initState(); _controller = YoutubePlayerController( initialVideoId: _ids.first, flags: const YoutubePlayerFlags( mute: false, autoPlay: true, disableDragSeek: false, loop: false, isLive: false, forceHD: false, enableCaption: true, ), )..addListener(listener); _idController = TextEditingController(); _seekToController = TextEditingController(); _videoMetaData = const YoutubeMetaData(); _playerState = PlayerState.unknown; }
void listener() { if (_isPlayerReady && mounted && !_controller.value.isFullScreen) { setState(() { _playerState = _controller.value.playerState; _videoMetaData = _controller.metadata; }); } }
@override void deactivate() { // Pauses video while navigating to next page. _controller.pause(); super.deactivate(); }
@override void dispose() { _controller.dispose(); _idController.dispose(); _seekToController.dispose(); super.dispose(); }
@override Widget build(BuildContext context) { return YoutubePlayerBuilder( onExitFullScreen: () { // The player forces portraitUp after exiting fullscreen. This overrides the behaviour. SystemChrome.setPreferredOrientations(DeviceOrientation.values); }, player: YoutubePlayer( controller: _controller, showVideoProgressIndicator: true, progressIndicatorColor: Colors.blueAccent, topActions:[
const SizedBox(width: 8.0),
Expanded(
child: Text(
_controller.metadata.title,
style: const TextStyle(
color: Colors.white,
fontSize: 18.0,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
IconButton(
icon: const Icon(
Icons.settings,
color: Colors.white,
size: 25.0,
),
onPressed: () {
log('Settings Tapped!');
},
),
],
onReady: () {
_isPlayerReady = true;
},
onEnded: (data) {
_controller
.load(_ids[(_ids.indexOf(data.videoId) + 1) % _ids.length]);
_showSnackBar('Next Video Started!');
},
),
builder: (context, player) => ListView(
shrinkWrap: true,
children: [
player,
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_space,
_text('Title', _videoMetaData.title),
_space,
_text('Channel', _videoMetaData.author),
_space,
_text('Video Id', _videoMetaData.videoId),
_space,
Row(
children: [
_text(
'Playback Quality',
_controller.value.playbackQuality ?? '',
),
const Spacer(),
_text(
'Playback Rate',
'${_controller.value.playbackRate}x ',
),
],
),
_space,
TextField(
enabled: _isPlayerReady,
controller: _idController,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter youtube
Widget _text(String title, String value) { return RichText( text: TextSpan( text: '$title : ', style: const TextStyle( color: Colors.blueAccent, fontWeight: FontWeight.bold, ), children: [ TextSpan( text: value, style: const TextStyle( color: Colors.blueAccent, fontWeight: FontWeight.w300, ), ), ], ), ); }
Color _getStateColor(PlayerState state) { switch (state) { case PlayerState.unknown: return Colors.grey[700]!; case PlayerState.unStarted: return Colors.pink; case PlayerState.ended: return Colors.red; case PlayerState.playing: return Colors.blueAccent; case PlayerState.paused: return Colors.orange; case PlayerState.buffering: return Colors.yellow; case PlayerState.cued: return Colors.blue[900]!; default: return Colors.blue; } }
Widget get _space => const SizedBox(height: 10);
Widget _loadCueButton(String action) { return Expanded( child: MaterialButton( color: Colors.blueAccent, onPressed: _isPlayerReady ? () { if (_idController.text.isNotEmpty) { var id = YoutubePlayer.convertUrlToId( _idController.text, ) ?? ''; if (action == 'LOAD') _controller.load(id); if (action == 'CUE') _controller.cue(id); FocusScope.of(context).requestFocus(FocusNode()); } else { _showSnackBar('Source can\'t be empty!'); } } : null, disabledColor: Colors.grey, disabledTextColor: Colors.black, child: Padding( padding: const EdgeInsets.symmetric(vertical: 14.0), child: Text( action, style: const TextStyle( fontSize: 18.0, color: Colors.white, fontWeight: FontWeight.w300, ), textAlign: TextAlign.center, ), ), ), ); }
void _showSnackBar(String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( message, textAlign: TextAlign.center, style: const TextStyle( fontWeight: FontWeight.w300, fontSize: 16.0, ), ), backgroundColor: Colors.blueAccent, behavior: SnackBarBehavior.floating, elevation: 1.0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(50.0), ), ), ); } }
Flutter Doctor Output