sarbagyastha / youtube_player_flutter

A Flutter plugin for inline playback or streaming of YouTube videos using the official iFrame Player API.
https://youtube.sarbagyastha.com.np
BSD 3-Clause "New" or "Revised" License
693 stars 786 forks source link

[BUG] Back navigation error 'package:flutter/src/widgets/navigator.dart': Failed assertion: line 5350 pos 12: '!_debugLocked' when video is opened in Dialog #976

Open RaphiTobi opened 3 weeks ago

RaphiTobi commented 3 weeks ago

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?

  1. Use a YoutubePlayerBuilder inside a showModalBottomSheet
  2. Start the App, open The Dialog
  3. Close the dialog

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

[√] Flutter (Channel stable, 3.24.0, on Microsoft Windows [Version 10.0.22631.4037], locale de-DE)
    • Flutter version 3.24.0 on channel stable at C:\Users\Rapha\AppData\Roaming\flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 80c2e84975 (3 weeks ago), 2024-07-30 23:06:49 +0700
    • Engine revision b8800d88be
    • Dart version 3.5.0
    • DevTools version 2.37.2

[√] Windows Version (Installed version of Windows is version 10 or higher)

[√] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at C:\Users\Rapha\AppData\Local\Android\sdk
    • Platform android-34, build-tools 34.0.0
    • Java binary at: C:\Program Files\Android\Android Studio1\jbr\bin\java
    • Java version OpenJDK Runtime Environment (build 17.0.9+0--11185874)
    • All Android licenses accepted.

[√] Chrome - develop for the web
    • Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe

[√] Visual Studio - develop Windows apps (Visual Studio Community 2019 16.11.21)
    • Visual Studio at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community
    • Visual Studio Community 2019 version 16.11.33027.164
    • Windows 10 SDK version 10.0.19041.0

[√] Android Studio (version 2023.2)
    • Android Studio at C:\Program Files\Android\Android Studio1
    • Flutter plugin can be installed from:
       https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
       https://plugins.jetbrains.com/plugin/6351-dart
    • android-studio-dir = C:\Program Files\Android\Android Studio1
    • Java version OpenJDK Runtime Environment (build 17.0.9+0--11185874)

[√] IntelliJ IDEA Community Edition (version 2022.1)
    • IntelliJ at C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2022.1.1
    • Flutter plugin can be installed from:
       https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
       https://plugins.jetbrains.com/plugin/6351-dart

[√] VS Code (version 1.92.0)
    • VS Code at C:\Users\Rapha\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.94.0

[√] Connected device (4 available)
    • sdk gphone x86 (mobile) • emulator-5554 • android-x86    • Android 11 (API 30) (emulator)
    • Windows (desktop)       • windows       • windows-x64    • Microsoft Windows [Version 10.0.22631.4037]
    • Chrome (web)            • chrome        • web-javascript • Google Chrome 127.0.6533.120
    • Edge (web)              • edge          • web-javascript • Microsoft Edge 126.0.2592.56

[√] Network resources
    • All expected network resources are available.

• No issues found!
hayatshin commented 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.

Malte311 commented 3 weeks ago

Same issue here. This PR seems to fix it for me.

DoanTienNamAnh commented 2 weeks ago

The same issue

PoojithPriyavas commented 2 weeks ago

downgrade version to ^8.1.2.. this works completely fine. Once again thanks @hayatshin .

joshuazbeck commented 1 week ago

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.

sunbowkh commented 1 week ago

스크린샷 2024-09-04 13 46 33

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