Feeds List having text, image and video with auto Play/Pause on Scroll in Flutter

75 Views Asked by At

I want to Implement a Feeds List like Facebook in Flutter. The feed list can have text, images, and video on each item. The text and images are working perfectly.

The important thing is, I want to play/pause video on scroll and play only one video at a time.

I tried different things but nothing is appropriately working.

import 'dart:async';

import 'package:cached_video_player/cached_video_player.dart';

import 'package:flutter/cupertino.dart';

import 'package:flutter/material.dart';

import 'package:visibility_detector/visibility_detector.dart';

CachedVideoPlayerController? activeController;

class VideoPlayer extends StatefulWidget {
  final String videoUrl;

  const VideoPlayer({
    Key? key,
    required this.videoUrl,
  }) : super(key: key);

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

class _VideoPlayerState extends State<VideoPlayer> {
  CachedVideoPlayerController? _videoController;

  final UniqueKey stickyKey = UniqueKey();

  bool isControllerReady = false;

  bool isPlaying = false;

  Completer videoPlayerInitializedCompleter = Completer();

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

  @override
  void dispose() async {
    if (_videoController != null)
      await _videoController?.dispose()?.then((_) {
        isControllerReady = false;

        _videoController = null;

        videoPlayerInitializedCompleter = Completer(); // resets the Completer
      });

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.symmetric(vertical: 20.0),
      child: VisibilityDetector(
        key: stickyKey,
        onVisibilityChanged: (VisibilityInfo info) async {
          if (info.visibleFraction > 0.70) {
            if (_videoController == null) {
              _videoController =
                  CachedVideoPlayerController.network(widget.videoUrl);

              _videoController!.initialize().then((_) async {
                videoPlayerInitializedCompleter.complete(true);

                setState(() {
                  isControllerReady = true;
                });

                _videoController!.setLooping(true);
              });
            }
          } else if (info.visibleFraction < 0.30) {
            setState(() {
              isControllerReady = false;
            });

            _videoController?.pause();

            setState(() {
              isPlaying = false;
            });

            WidgetsBinding.instance!.addPostFrameCallback((_) {
              if (activeController == _videoController) {
                activeController = null;
              }

              _videoController?.dispose()?.then((_) {
                setState(() {
                  _videoController = null;

                  videoPlayerInitializedCompleter =
                      Completer(); // resets the Completer
                });
              });
            });
          }
        },
        child: FutureBuilder(
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.done &&
                _videoController != null &&
                isControllerReady) {
              // should also check that the video has not been disposed

              return GestureDetector(
                  onTap: () async {
                    setState(() {
                      if (_videoController!.value.isPlaying) {
                        _videoController?.pause();

                        setState(() {
                          isPlaying = false;
                        });
                      } else {
                        if (activeController != null) {
                          setState(() {
                            activeController!.pause();
                          });
                        }

                        activeController = _videoController;

                        _videoController?.play();

                        setState(() {
                          isPlaying = true;
                        });
                      }
                    });
                  },
                  child: Stack(
                    alignment: AlignmentDirectional.center,
                    children: [
                      AspectRatio(
                          aspectRatio: 4 / 3,
                          child: CachedVideoPlayer(_videoController!)),
                      !isPlaying
                          ? Icon(
                              CupertinoIcons.play_arrow_solid,
                              color: Colors.white70,
                              size: 54,
                            )
                          : Container(
                              height: 0.0,
                            ),
                    ],
                  )); // display the video
            }

            return AspectRatio(
              aspectRatio: 4 / 3,
              child: Container(
                color: Colors.black,
                child: Center(
                  child: CircularProgressIndicator(),
                ),
              ),
            );
          },
          future: videoPlayerInitializedCompleter.future,
        ),
      ),
    );
  }
}

The only issue with this code is that it deletes video from memory on a scroll and loads video from scratch when coming back. I want that, I should keep the video in the cache and play from the same position where I left it last time.

Any help or suggestion will be appreciated.

0

There are 0 best solutions below