fluttercommunity / chewie

The video player for Flutter with a heart of gold
MIT License
1.93k stars 989 forks source link

controller copyWith not effective in fullscreen #665

Open vincepunkrock opened 2 years ago

vincepunkrock commented 2 years ago

I am changing the overlay when the video is playing. I added a listener to my controller and in it, I check the isPlaying property. If the video is playing, I change the overlay by updating the controller using the copyWith method (in a setState). It works well when the video is not in fullscreen.

When in fullscreen, the overlay doesn't get changed, although isPlaying is true and the line where I update the controller gets executed.

diegotori commented 2 years ago

Can you please submit a example project demonstrating this issue? That way I can better diagnose it. Thanks.

vincepunkrock commented 2 years ago

This is my widget:

import 'package:cached_network_image/cached_network_image.dart';
...
import 'package:chewie/chewie.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:video_player/video_player.dart';

class MyVideoPlayer extends StatefulWidget {
  final Video video;
  final double height;
  final double width;
  MyVideoPlayer({required this.video, required this.height, required this.width});

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

class _MyVideoPlayerState extends State<MyVideoPlayer> {
  VideoPlayerController? _controller;
  ChewieController? _chewieController;
  bool _overlayRemoved = false;

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

  Future<void> initializePlayer() async {

    _controller = VideoPlayerController.network(widget.video.mp4);
    await Future.wait([
      _controller!.initialize()
    ]);
    _chewieController = ChewieController(
      videoPlayerController: _controller!,
      deviceOrientationsAfterFullScreen: [
        DeviceOrientation.portraitDown,
        DeviceOrientation.portraitUp
      ],
      deviceOrientationsOnEnterFullScreen: [
        DeviceOrientation.landscapeLeft,
        DeviceOrientation.landscapeRight
      ],
      autoPlay: false,
      looping: false,
      allowPlaybackSpeedChanging: false,
      allowMuting: false,
      autoInitialize: false,
      overlay: Center(child: CachedNetworkImage(imageUrl: widget.video.thumbnail)),
      placeholder: Center(child: CachedNetworkImage(imageUrl: widget.video.thumbnail, )),
      customControls: Theme.of(context).platform == TargetPlatform.iOS ? MyCupertinoControls(
        backgroundColor: const Color.fromRGBO(41, 41, 41, 0.7),
        iconColor: const Color.fromARGB(255, 200, 200, 200),
      ) : null
    );

    _controller?.addListener(_controllerListener);
    setState(() {});
  }

  void _controllerListener() {
    print("isFullScreen: ${_chewieController?.isFullScreen??false}");
    print("isPlaying: ${_chewieController?.isPlaying??false}");

    // as soon as we're playing or in fullscreen, remove the overlay thumbnail. If we then pause the video, do nothing
    if(!_overlayRemoved && ((_chewieController?.isPlaying??false) || (_chewieController?.isFullScreen??false))) {
      setState(() {
        _chewieController = _chewieController!.copyWith(overlay: Container());
        _overlayRemoved = true;
      });
    }

  }

  @override
  void dispose() {
    _controller?.dispose();
    _controller?.removeListener(_controllerListener);
    _chewieController?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: widget.width,
      height: widget.height,
      decoration: BoxDecoration(boxShadow: [
        const BoxShadow(
          color: Colors.grey,
          offset: const Offset(0.0, 1.0),
          blurRadius: 5.0,
        )
      ], 
      ),
      child: Container(
        decoration: BoxDecoration(
          color: Colors.black,
        ),
        child: ClipRRect(
          child: _chewieController != null ?
          Chewie(
            controller: _chewieController!,
          ) : Container(),
        ),
      ),
    );
  }
}
diegotori commented 2 years ago

Please post this in an example repo. This will help me point chewie into a local copy and debug the code very easily.

Also, based on my initial reading, the reason it might not be working is because the overlay Widget is final and when you enter full screen, it takes the existing ChewieController and passes it into another route displaying the video in Full Screen.

One possible solution is to create a builder function for generating the overlay widget that is a mutable member of ChewieController and whenever this function exists and is updated, it will call notifyListeners inside ChewieController, which will then rebuild the PlayerWithControls widget and thus rebuild the computed overlay.

Bottom line, you'll have to make a change to ChewieController to support a new builder function that has a setter that calls notifyListeners whenever the builder function reference changes. You'll also have to make a change to _buildPlayerWithControls in PlayerAndControls so that it computes the resulting overlay widget from the controller's function, otherwise it falls back to the controller's overlay widget. Then display that if it exists.

I can most certainly review any PR you submit to this effect.

murphycrosby commented 1 year ago

I needed the overlay to be updated based on if it was fullscreen or not. Added this PR #713