sarbagyastha / youtube_player_flutter

Flutter plugin for playing or streaming YouTube videos inline using the official iFrame Player API. Supports both Android and iOS platforms.
BSD 3-Clause "New" or "Revised" License
682 stars 755 forks source link

No progress bar and No buttons on full screen[BUG] #853

Open alexaung opened 1 year ago

alexaung commented 1 year ago

Describe the bug When click full screen button, change to full screen mode. But there is no progress bar or button. Only show title and share button on top when touch the screen.

To Reproduce Steps to reproduce the behavior:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:youtube_player_iframe/youtube_player_iframe.dart' as yt;

void main() {
  runApp( MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const VideoScreen(),
    );
  }
}

class VideoScreen extends StatefulWidget {
  static const routeName = '/video';
  const VideoScreen({Key? key}) : super(key: key);

  @override
  State<VideoScreen> createState() => _VideoScreenState();
}

class _VideoScreenState extends State<VideoScreen> {
  bool _isFullScreen = false;
  late yt.YoutubePlayerController _controller;

  @override
  void initState() {
    super.initState();

    _controller = yt.YoutubePlayerController.fromVideoId(
      videoId: 'dQw4w9WgXcQ',
      autoPlay: false,
      params: const yt.YoutubePlayerParams(
        showControls: true,
        showFullscreenButton: true,
      ),
    );

    _controller.setFullScreenListener((isFullScreen) {
      if (isFullScreen) {
        SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
        SystemChrome.setPreferredOrientations([
          DeviceOrientation.landscapeLeft,
          DeviceOrientation.landscapeRight,
        ]);
      } else {
        SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
            overlays: SystemUiOverlay.values);
        SystemChrome.setPreferredOrientations([
          DeviceOrientation.portraitDown,
          DeviceOrientation.portraitUp,
        ]);
      }

      setState(() {
        _isFullScreen = isFullScreen;
      });
    });
  }

  @override
  void dispose() {
    _controller.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: _isFullScreen
          ? null
          : AppBar(
              centerTitle: true,
              title: const Text("Youtube Live"),
              leading: IconButton(
                onPressed: () {
                  Navigator.pop(context);
                },
                icon: const Icon(
                  Icons.arrow_back,
                ),
              ),
            ),
      body: yt.YoutubePlayerControllerProvider(
        controller: _controller,
        child: ListView(
          children: [
            yt.YoutubePlayer(
              controller: _controller,
              aspectRatio: 16 / 9,
            ),
            // ... Other children widgets ...
          ],
        ),
      ),
    );
  }
}

Expected behavior Should show the player like real youtube.

Screenshots If applicable, add screenshots to help explain your problem.

Technical Details:

Additional context Flutter (Channel stable, 3.10.5, on macOS 13.4.1 22F82 darwin-x64, locale en-GB) • Flutter version 3.10.5 on channel stable at /Users/aungmyooo/Development/flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision 796c8ef792 (4 weeks ago), 2023-06-13 15:51:02 -0700 • Engine revision 45f6e00911 • Dart version 3.0.5 • DevTools version 2.23.1

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0) • Android SDK at /Users/aungmyooo/Library/Android/sdk • Platform android-34, build-tools 33.0.0 • ANDROID_HOME = /Users/aungmyooo/Library/Android/sdk • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694) • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.3.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Build 14E300c • CocoaPods version 1.11.3

[✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.2) • Android Studio at /Applications/Android Studio.app/Contents • 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 • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)

[✓] VS Code (version 1.80.0) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.68.0

[✓] Connected device (4 available) • SM N975F (mobile) • RF8M82Y3K9A • android-arm64 • Android 12 (API 31) • Aung Myo’s iPhone (mobile) • 06e02964e429eeebf29550b03ef955abe09891ef • ios • iOS 16.5.1 20F75 • macOS (desktop) • macos • darwin-x64 • macOS 13.4.1 22F82 darwin-x64 • Chrome (web) • chrome • web-javascript • Google Chrome 114.0.5735.198

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

alexaung commented 1 year ago

youtube_player_iframe: ^2.3.0 is working perfect.

import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:thitsarparami/blocs/bloc.dart';
import 'package:thitsarparami/helper/constants.dart';
import 'package:thitsarparami/helper/enum.dart';
import 'package:thitsarparami/ui/error/something_went_wrong.dart';
import 'package:thitsarparami/widgets/circular_progress_indicator_widget.dart';
import 'package:transparent_image/transparent_image.dart';
import 'package:youtube_player_iframe/youtube_player_iframe.dart';

import '../../helper/ad_helper.dart';
import '../../widgets/native_template_ad.dart';

class VideoScreen extends StatefulWidget {
  static const routeName = '/video';
  //final Video video;
  const VideoScreen({Key? key}) : super(key: key);

  @override
  VideoScreenState createState() => VideoScreenState();
}

class VideoScreenState extends State<VideoScreen> {
  @override
  void initState() {
    super.initState();
    _loadYoutube();
  }

  _loadYoutube() async {
    List<String> codes = [
      systemDataCodeToString(SystemDataCode.youtube_live),
    ];
    BlocProvider.of<SystemDataBloc>(context).add(GetYoutubeLiveEvent(codes));
  }

  bool shouldPop = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        backgroundColor: Theme.of(context).scaffoldBackgroundColor,
        elevation: 0,
        title: AutoSizeText(
          kYouTubeChannel,
          style: Theme.of(context).appBarTheme.titleTextStyle,
        ),
        leading: IconButton(
          onPressed: () {
            Navigator.pop(context);
          },
          icon: Icon(
            Icons.arrow_back,
            color: Theme.of(context).primaryIconTheme.color!,
          ),
        ),
      ),
      body: BlocBuilder<SystemDataBloc, SystemDataState>(
        builder: (context, state) {
          if (state is SystemDataError) {
            return SomethingWentWrongScreen(
                error: state.error, screenName: 'Video Screen');
          } else if (state is YoutubeLiveDataLoaded) {
            return MyYoutubePlayer(
              videoId: state.systemData.youtubeLive!.videoId!,
              title: state.systemData.youtubeLive!.videoTitle!,
            );
          }
          return const CircularProgressIndicatorWidget();
        },
      ),
    );
  }
}

class MyYoutubePlayer extends StatefulWidget {
  final String videoId;
  final String title;
  const MyYoutubePlayer({Key? key, required this.videoId, required this.title})
      : super(key: key);

  @override
  State<MyYoutubePlayer> createState() => _MyYoutubePlayerState();
}

class _MyYoutubePlayerState extends State<MyYoutubePlayer> {
  late YoutubePlayerController _controller;

  @override
  void initState() {
    _controller = YoutubePlayerController(
      initialVideoId: widget.videoId,
      params: YoutubePlayerParams(
        playlist: [
          widget.videoId,
        ],
        showControls: true,
        showFullscreenButton: true,
        desktopMode: false,
        privacyEnhanced: true,
        useHybridComposition: true,
      ),
    );

    _controller.onEnterFullscreen = () {
      SystemChrome.setPreferredOrientations([
        DeviceOrientation.landscapeLeft,
        DeviceOrientation.landscapeRight,
      ]);
      //log('Entered Fullscreen');
    };
    _controller.onExitFullscreen = () {
      SystemChrome.setPreferredOrientations([
        DeviceOrientation.portraitDown,
        DeviceOrientation.portraitUp,
      ]);
      //log('Exited Fullscreen');
    };

    super.initState();
  }

  @override
  void dispose() {
    super.dispose();

    _controller.close();
  }

  @override
  Widget build(BuildContext context) {
    const player = YoutubePlayerIFrame();
    return YoutubePlayerControllerProvider(
      // Passing controller to widgets below.
      controller: _controller,
      child: LayoutBuilder(
        builder: (context, constraints) {
          return ListView(
            children: [
              Stack(
                children: [
                  player,
                  Positioned.fill(
                    child: YoutubeValueBuilder(
                      controller: _controller,
                      builder: (context, value) {
                        return AnimatedCrossFade(
                          firstChild: const SizedBox.shrink(),
                          secondChild: Material(
                            child: DecoratedBox(
                              decoration: BoxDecoration(
                                image: DecorationImage(
                                  image: FadeInImage.memoryNetwork(
                                    image: YoutubePlayerController.getThumbnail(
                                      videoId:
                                          _controller.params.playlist.first,
                                      quality: ThumbnailQuality.medium,
                                    ),
                                    placeholder: kTransparentImage,
                                    imageErrorBuilder:
                                        (context, error, stackTrace) {
                                      return Container(color: Colors.grey);
                                    },
                                  ).image,
                                  fit: BoxFit.fitWidth,
                                ),
                              ),
                              child: const Center(
                                child: CircularProgressIndicator(),
                              ),
                            ),
                          ),
                          crossFadeState: value.isReady
                              ? CrossFadeState.showFirst
                              : CrossFadeState.showSecond,
                          duration: const Duration(milliseconds: 300),
                        );
                      },
                    ),
                  ),
                ],
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Text(
                  widget.title,
                  style: const TextStyle(
                      color: Colors.black,
                      fontSize: 16.0,
                      fontWeight: FontWeight.bold),
                ),
              ),
              const SizedBox(
                height: 20,
              ),
              Container(
                padding: const EdgeInsets.all(10.0),
                child: NativeTemplateAd(
                  adUnitId: AdHelper.nativeAdUnitId,
                  templateType: TemplateType.medium,
                ),
              ),
            ],
          );
        },
      ),
    );
  }
}
alexaungmyooo commented 5 months ago

Finally I can upgrade to youtube_player_iframe: ^4.0.4. Below code is working with full screen.

import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:thitsarparami/helper/ad_helper.dart';
import 'package:thitsarparami/helper/constants.dart';
import 'package:thitsarparami/widgets/custom_app_bar.dart';
import 'package:thitsarparami/widgets/native_template_ad.dart';
import 'package:youtube_player_iframe/youtube_player_iframe.dart';

class MyYoutubePlayer extends StatefulWidget {
  final String videoId;
  final String title;
  const MyYoutubePlayer(
      {super.key, required this.videoId, required this.title});

  @override
  State<MyYoutubePlayer> createState() => _MyYoutubePlayerState();
}

class _MyYoutubePlayerState extends State<MyYoutubePlayer> {
  late YoutubePlayerController _controller;
  bool _isFullscreen = false;

  @override
  void initState() {
    super.initState();
    _initYoutubePlayer();
  }

  @override
  void dispose() {
    _controller.close();
    super.dispose();
  }

  void _initYoutubePlayer() {
    _controller = YoutubePlayerController.fromVideoId(
      videoId: widget.videoId,
      params: const YoutubePlayerParams(
        enableJavaScript: false,
        loop: false,
        mute: false,
        playsInline: true,
        showControls: true,
        showFullscreenButton: true,
        showVideoAnnotations: false,
      ),
    );

    _controller.setFullScreenListener((isFullScreen) {
      setState(() {
        _isFullscreen = isFullScreen;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: _isFullscreen
          ? null
          : CustomAppBar(
              title: kYouTubeChannel,
              onBackPressed: () {
                Navigator.pop(context);
              },
            ),
      body: YoutubePlayerScaffold(
        controller: _controller,
        builder: (context, player) {
          return Column(
            children: [
              player,
              Container(
                padding: const EdgeInsets.all(10.0),
                child: NativeTemplateAd(
                  adUnitId: AdHelper.nativeAdUnitId,
                  templateType: TemplateType.medium,
                ),
              )
            ],
          );
        },
      ),
    );
  }
}