π₯ Introducing the Mr Pixel Video Player Custom Widget for FlutterFlow! π¬
This custom code is based on the Better Player package, and I will begin the stage of creating a comprehensive video player because there is no such thing in Flutterflow.
This version is still in the development stage. This is the first version of it, and I will develop it more and more
In the future, I will use many features that will make this user not think about using any video player other than this one
Unlock the full potential of your video streaming experience with these key features:
πΊ Multiple Video Resolutions: Choose from SD, HD, FHD, and 4K video qualities.
π Multi Subtitles Support: Easily add up to four subtitle tracks for a more inclusive viewing experience.
π¨ Customizable Subtitles: Personalize the font size, border, color, and background of your subtitles.
π Dynamic Resolution Switching: Switch between different video resolutions for smooth playback based on network conditions.
Notes for beginners:
1- You must copy this name MrPixelVideoPlayer and paste it into the Widget name field.
2- Copy this better_player: ^0.0.84 and put it in pubspec dependencies
// Automatic FlutterFlow imports
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 '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom widget code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!
import '/custom_code/widgets/index.dart';
import 'package:better_player/better_player.dart';
class MrPixelVideoPlayer extends StatefulWidget {
const MrPixelVideoPlayer({
super.key,
this.width,
this.height,
required this.SD,
required this.HD,
required this.FHD,
required this.FOURK,
this.subtitleFontSize,
this.subtitleTextBorder,
this.subtitleColor,
this.subtitleBackground,
this.subtitleBorderColor,
this.subtitleName1,
this.subtitleLink1,
this.subtitleName2,
this.subtitleLink2,
this.subtitleName3,
this.subtitleLink3,
this.subtitleName4,
this.subtitleLink4,
});
final double? width;
final double? height;
final String SD;
final String HD;
final String FHD;
final String FOURK;
final double? subtitleFontSize;
final double? subtitleTextBorder;
final Color? subtitleColor;
final Color? subtitleBackground;
final Color? subtitleBorderColor;
final String? subtitleName1;
final String? subtitleLink1;
final String? subtitleName2;
final String? subtitleLink2;
final String? subtitleName3;
final String? subtitleLink3;
final String? subtitleName4;
final String? subtitleLink4;
@override
State<MrPixelVideoPlayer> createState() => _MrPixelVideoPlayerState();
}
class _MrPixelVideoPlayerState extends State<MrPixelVideoPlayer> {
late BetterPlayerController _betterPlayerController;
@override
void initState() {
super.initState();
_initializePlayer();
}
Future<void> _initializePlayer() async {
// Create a map of video resolutions
Map<String, String> resolutions = {
'SD': widget.SD,
'HD': widget.HD,
'FHD': widget.FHD,
'4K': widget.FOURK,
};
BetterPlayerSubtitlesConfiguration subtitlesConfig =
BetterPlayerSubtitlesConfiguration(
fontSize: widget.subtitleFontSize ?? 16,
outlineSize: widget.subtitleTextBorder ?? 4,
fontColor: widget.subtitleColor ?? Colors.white,
backgroundColor: widget.subtitleBackground ??
Colors.transparent, // No background if not provided
outlineColor: widget.subtitleBorderColor ?? Colors.black,
outlineEnabled: true,
);
List<BetterPlayerSubtitlesSource> subtitleSources = [];
if (widget.subtitleName1 != null && widget.subtitleLink1 != null) {
subtitleSources.add(BetterPlayerSubtitlesSource(
type: BetterPlayerSubtitlesSourceType.network,
urls: [widget.subtitleLink1!], // Use `urls` as a list
name: widget.subtitleName1!,
));
}
if (widget.subtitleName2 != null && widget.subtitleLink2 != null) {
subtitleSources.add(BetterPlayerSubtitlesSource(
type: BetterPlayerSubtitlesSourceType.network,
urls: [widget.subtitleLink2!], // Use `urls` as a list
name: widget.subtitleName2!,
));
}
if (widget.subtitleName3 != null && widget.subtitleLink3 != null) {
subtitleSources.add(BetterPlayerSubtitlesSource(
type: BetterPlayerSubtitlesSourceType.network,
urls: [widget.subtitleLink3!], // Use `urls` as a list
name: widget.subtitleName3!,
));
}
if (widget.subtitleName4 != null && widget.subtitleLink4 != null) {
subtitleSources.add(BetterPlayerSubtitlesSource(
type: BetterPlayerSubtitlesSourceType.network,
urls: [widget.subtitleLink4!], // Use `urls` as a list
name: widget.subtitleName4!,
));
}
// Create the data source with resolution options and subtitles
BetterPlayerDataSource dataSource = BetterPlayerDataSource(
BetterPlayerDataSourceType.network,
widget.HD, // Default video link (HD)
resolutions: resolutions,
subtitles: subtitleSources,
);
// Create BetterPlayer Configuration with aspect ratio and other settings
BetterPlayerConfiguration betterPlayerConfiguration =
BetterPlayerConfiguration(
aspectRatio: 16 / 9,
fit: BoxFit.contain,
autoPlay: true,
looping: false,
subtitlesConfiguration: subtitlesConfig,
);
// Initialize the BetterPlayerController
_betterPlayerController = BetterPlayerController(betterPlayerConfiguration);
await _betterPlayerController.setupDataSource(dataSource);
}
@override
void dispose() {
_betterPlayerController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final double width = widget.width ?? MediaQuery.of(context).size.width;
final double height = widget.height ?? width / (16 / 9);
return Container(
width: width,
height: height,
child: AspectRatio(
aspectRatio:
_betterPlayerController.betterPlayerConfiguration.aspectRatio ??
16 / 9,
child: BetterPlayer(controller: _betterPlayerController),
),
);
}