Click here to Skip to main content
15,887,214 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hey, codeproject wonderful community!

I am trying to implement the Chewie Flutter package into my app as a custom widget and I got everything down and made it as customizable as possible. It complies well, but when I run it on the web, android, or any device possible all I get a white container with the loading indicator and the text "loading."
The good thing is, the code complies with no errors!

Here's my custom widget code, it's really simple. All I did was get Pubdev Chewie package code, add dependencies, add as many params as possible that will define the autoplay, looping, etc as per Chewie's documentation, and remove the unnecessary appbar and bottom texts in the pubdev code.

I also have videoPath and videosList just in case if the user would like to use a playlist or just one video path. The pubdev code uses a list, so I used a list and would check if the param is null, if so it'll use the videoPath singular link as the first index instead. I commented that code out and hardcoded a video link that I found on Chewie's Pubdev page and several other ones with no hope.

Dart
<pre>// Imports
import '/backend/backend.dart';
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/widgets/index.dart'; // Imports other custom widgets
import '/custom_code/actions/index.dart'; // Imports custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom widget code

import 'package:chewie/chewie.dart';
import 'package:video_player/video_player.dart';
import 'dart:io';

class ChewieVideoPlayer extends StatefulWidget {
  ChewieVideoPlayer({
    Key? key,
    this.width,
    this.height,
    this.videoPath,
    this.videosList,
    this.isAutoPlay,
    this.isLooping,
    this.hideControlsAfter,
    this.currentPlayIndex,
    this.startTime,
    this.videoPlatform,
    this.hideControls,
    this.aspectRatio,
    this.disableFullScreen,
    this.isLive,
    this.disableZoomAndPan,
    this.hideOptions,
    this.allowScreenSleep,
    this.disableMuting,
    this.disablePlaybackSpeedChanging,
    this.disableAutoInitialize,
    this.fullScreenByDefault,
    this.playbackSpeedList,
    this.progressIndicatorDelay,
    this.nonDraggableProgressBar,
  }) : super(key: key);

  final double? width;
  final double? height;
  final String? videoPath;
  final List<String>? videosList;
  final bool? isAutoPlay;
  final bool? isLooping;
  final int? hideControlsAfter;
  int? currentPlayIndex;
  final double? startTime;
  final String? videoPlatform;
  final bool? hideControls;
  final double? aspectRatio;
  final bool? disableFullScreen;
  final bool? isLive;
  final bool? disableZoomAndPan;
  final bool? hideOptions;
  final bool? allowScreenSleep;
  final bool? disableMuting;
  final bool? disablePlaybackSpeedChanging;
  final bool? disableAutoInitialize;
  final bool? fullScreenByDefault;
  final List<double>? playbackSpeedList;
  final int? progressIndicatorDelay;
  final bool? nonDraggableProgressBar;
  @override
  State<ChewieVideoPlayer> createState() => _ChewieVideoPlayerState();
}

class _ChewieVideoPlayerState extends State<ChewieVideoPlayer> {
  TargetPlatform? _platform;
  late VideoPlayerController _videoPlayerController1;
  late VideoPlayerController _videoPlayerController2;
  ChewieController? _chewieController;
  late List<String> srcs;

  //Initializing the widget state
  @override
  void initState() {
    super.initState();
    initializePlayer();
    /* srcs = widget.videosList ??
        [
          widget.videoPath ??
              'https://assets.mixkit.co/videos/preview/mixkit-daytime-city-traffic-aerial-view-56-large.mp4'
        ]; */
    srcs = [
      'https://assets.mixkit.co/videos/preview/mixkit-daytime-city-traffic-aerial-view-56-large.mp4'
    ];
  }

  //Function to clear the memory to avoid leaks
  @override
  void dispose() {
    _videoPlayerController1.dispose();
    _videoPlayerController2.dispose();
    _chewieController?.dispose();
    super.dispose();
  }

  //Function to initialize the player
  Future<void> initializePlayer() async {
    _videoPlayerController1 = VideoPlayerController.networkUrl(
        Uri.parse(srcs[widget.currentPlayIndex ?? 0]));
    _videoPlayerController2 = VideoPlayerController.networkUrl(
        Uri.parse(srcs[widget.currentPlayIndex ?? 0]));
    await Future.wait([
      _videoPlayerController1.initialize(),
      _videoPlayerController2.initialize()
    ]);

    _createChewieController();
    setState(() {});
  }

  //Function that creates ChewieController and custmoize it (e.g. set color, autoplay, looping, etc)
  void _createChewieController() {
    // Check if videoPlatform is provided and set the platform accordingly
    if (widget.videoPlatform != null) {
      switch (widget.videoPlatform) {
        case 'android':
          _platform = TargetPlatform.android;
          break;
        case 'ios':
          _platform = TargetPlatform.iOS;
          break;
        case 'windows':
          _platform = TargetPlatform.windows;
          break;
        default:
          // Handle other cases or leave platform as null
          break;
      }
    }
    final subtitles = [
      Subtitle(
        index: 0,
        start: Duration.zero,
        end: const Duration(seconds: 10),
        text: const TextSpan(
          children: [
            TextSpan(
              text: 'Hello',
              style: TextStyle(color: Colors.red, fontSize: 22),
            ),
            TextSpan(
              text: ' from ',
              style: TextStyle(color: Colors.green, fontSize: 20),
            ),
            TextSpan(
              text: 'subtitles',
              style: TextStyle(color: Colors.blue, fontSize: 18),
            )
          ],
        ),
      ),
      Subtitle(
        index: 0,
        start: const Duration(seconds: 10),
        end: const Duration(seconds: 20),
        text: 'Whats up? :)',
      ),
    ];

    _chewieController = ChewieController(
      videoPlayerController: _videoPlayerController1,
      autoPlay: widget.isAutoPlay ?? false,
      looping: widget.isLooping ?? false,
      hideControlsTimer: Duration(seconds: widget.hideControlsAfter ?? 3),
      showControls: widget.hideControls ?? true,
      startAt: widget.startTime != null
          ? Duration(milliseconds: (widget.startTime! * 1000).toInt())
          : null,
      aspectRatio: widget.aspectRatio ?? 1.7,
      allowFullScreen: !(widget.disableFullScreen ?? false),
      isLive: widget.isLive ?? false,
      zoomAndPan: !(widget.disableZoomAndPan ?? false),
      showOptions: !(widget.hideOptions ?? false),
      allowedScreenSleep: widget.allowScreenSleep ?? false,
      allowMuting: !(widget.disableMuting ?? false),
      allowPlaybackSpeedChanging:
          !(widget.disablePlaybackSpeedChanging ?? false),
      autoInitialize: !(widget.disableAutoInitialize ?? false),
      fullScreenByDefault: widget.fullScreenByDefault ?? false,
      draggableProgressBar: !(widget.nonDraggableProgressBar ?? false),
      playbackSpeeds:
          widget.playbackSpeedList ?? [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2],
      progressIndicatorDelay: widget.progressIndicatorDelay != null
          ? Duration(milliseconds: (widget.progressIndicatorDelay!))
          : null,
      additionalOptions: (context) {
        return <OptionItem>[
          OptionItem(
            onTap: toggleVideo,
            iconData: Icons.live_tv_sharp,
            title: 'Next Video',
          ),
        ];
      },
      subtitle: Subtitles(subtitles),
      subtitleBuilder: (context, dynamic subtitle) => Container(
        padding: const EdgeInsets.all(10.0),
        child: subtitle is InlineSpan
            ? RichText(
                text: subtitle,
              )
            : Text(
                subtitle.toString(),
                style: const TextStyle(color: Colors.black),
              ),
      ),
    );
  }

  //Function to switch to the next video in list
  Future<void> toggleVideo() async {
    await _videoPlayerController1.pause();
    widget.currentPlayIndex = (widget.currentPlayIndex ?? 0) + 1;
    if (widget.currentPlayIndex! >= srcs.length) {
      widget.currentPlayIndex = 0;
    }
    await initializePlayer();
  }

  //Building the widget
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: AppTheme.light.copyWith(
        platform: _platform ?? Theme.of(context).platform,
      ),
      home: Scaffold(
        body: Column(
          children: <Widget>[
            Expanded(
              child: Center(
                child: _chewieController != null &&
                        _chewieController!
                            .videoPlayerController.value.isInitialized
                    ? Chewie(
                        controller: _chewieController!,
                      )
                    : const Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          CircularProgressIndicator(),
                          SizedBox(height: 20),
                          Text('Loading'),
                        ],
                      ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

// Theme
class AppTheme {
  static final light = ThemeData(
    brightness: Brightness.light,
    useMaterial3: true,
    colorScheme: const ColorScheme.light(secondary: Colors.red),
    disabledColor: Colors.grey.shade400,
    visualDensity: VisualDensity.adaptivePlatformDensity,
  );

  static final dark = ThemeData(
    brightness: Brightness.dark,
    colorScheme: const ColorScheme.dark(secondary: Colors.red),
    disabledColor: Colors.grey.shade400,
    useMaterial3: true,
    visualDensity: VisualDensity.adaptivePlatformDensity,
  );
}




What I have tried:

So I tried to download the app, run it on the web, run it on Android Studio, etc with no hope. I was expecting to simply have the video player playing the videosList if it's not empty, and if it's empty then it'll instead use the videoPath as its first entry and play that video. I tried to remove all of that logic and instead hardcode the video and tried several different ones used in Chewie's official documentation with no hope.

If anyone can figure out what might be causing this problem I will greatly appreciate you.
Posted
Updated 1-Mar-24 21:25pm
Comments
Andre Oosthuizen 6-Mar-24 14:56pm    
You should maybe talk to the owners of the API, this is a lot of code on a control we do not know much about.
[no name] 8-Mar-24 13:28pm    
Get it working first; in the simplest way possible; using an "example" perhaps; (only) then "customize".

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900