Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import 'package:appinio_video_player/src/custom_video_player_controller.dart';
import 'package:flutter/material.dart';
import 'package:appinio_video_player/src/controls/custom_muted_button.dart';
import 'package:appinio_video_player/src/controls/fullscreen_button.dart';
import 'package:appinio_video_player/src/controls/play_button.dart';
import 'package:appinio_video_player/src/controls/progress_bar.dart';
import 'package:appinio_video_player/src/custom_video_player_controller.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class CustomVideoPlayerControlBar extends StatelessWidget {
final CustomVideoPlayerController customVideoPlayerController;
final Function updateVideoState;
final Function fadeOutOnPlay;

const CustomVideoPlayerControlBar({
Key? key,
required this.customVideoPlayerController,
Expand Down Expand Up @@ -78,6 +80,11 @@ class CustomVideoPlayerControlBar extends StatelessWidget {
}),
),
),
if (customVideoPlayerController
.customVideoPlayerSettings.showMutedButton)
CustomMutedButton(
customVideoPlayerController: customVideoPlayerController,
),
if (customVideoPlayerController
.customVideoPlayerSettings.showFullscreenButton)
CustomVideoPlayerFullscreenButton(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import 'package:appinio_video_player/src/custom_video_player_controller.dart';
import 'package:flutter/material.dart';

class CustomMutedButton extends StatelessWidget {
final CustomVideoPlayerController customVideoPlayerController;

CustomMutedButton({
Key? key,
required this.customVideoPlayerController,
}) : super(key: key);

bool isMuted = false;

@override
Widget build(BuildContext context) {
return StatefulBuilder(builder: (context, localState) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () async {
localState(() {
customVideoPlayerController.setVolumeMutedUnMuted();
});
},
child: customVideoPlayerController.isMuted
? customVideoPlayerController
.customVideoPlayerSettings.customMutedButton
: customVideoPlayerController
.customVideoPlayerSettings.customUnMutedButton,
);
});
}
}

class CustomVideoPlayerMutedButton extends StatelessWidget {
const CustomVideoPlayerMutedButton({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return const Padding(
padding: EdgeInsets.fromLTRB(0, 5, 5, 5),
child: Icon(
Icons.volume_off,
color: Colors.white,
),
);
}
}

class CustomVideoPlayerUnMutedButton extends StatelessWidget {
const CustomVideoPlayerUnMutedButton({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return const Padding(
padding: EdgeInsets.fromLTRB(0, 5, 5, 5),
child: Icon(
Icons.volume_up,
color: Colors.white,
),
);
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
import 'dart:async';

import 'package:appinio_video_player/src/fullscreen_video_player.dart';
import 'package:appinio_video_player/src/models/custom_video_player_settings.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:video_player/video_player.dart';
import 'package:appinio_video_player/src/models/custom_video_player_settings.dart';

/// The extension on the class is able to call private methods
/// only the package can use these methods and not the public beacuse of the hide keyword in the package exports
extension ProtectedCustomVideoPlayerController on CustomVideoPlayerController {
Future<void> Function(String) get switchVideoSource => _switchVideoSource;

ValueNotifier<Duration> get videoProgressNotifier => _videoProgressNotifier;

ValueNotifier<double> get playbackSpeedNotifier => _playbackSpeedNotifier;

ValueNotifier<bool> get isPlayingNotifier => _isPlayingNotifier;

bool get isFullscreen => _isFullscreen;

bool get isMuted => _isMuted;

set updateViewAfterFullscreen(Function updateViewAfterFullscreen) =>
_updateViewAfterFullscreen = updateViewAfterFullscreen;
}
Expand All @@ -23,12 +31,14 @@ class CustomVideoPlayerController {
VideoPlayerController videoPlayerController;
final CustomVideoPlayerSettings customVideoPlayerSettings;
final Map<String, VideoPlayerController>? additionalVideoSources;
final bool isAlwaysLandscapeOnFullscreen;

CustomVideoPlayerController({
required this.context,
required this.videoPlayerController,
this.customVideoPlayerSettings = const CustomVideoPlayerSettings(),
this.additionalVideoSources,
this.isAlwaysLandscapeOnFullscreen = false,
}) {
videoPlayerController.addListener(_videoListeners);
}
Expand Down Expand Up @@ -56,6 +66,7 @@ class CustomVideoPlayerController {
Function? _updateViewAfterFullscreen;

bool _isFullscreen = false;
bool _isMuted = false;
Timer? _timer;
final ValueNotifier<Duration> _videoProgressNotifier =
ValueNotifier(Duration.zero);
Expand Down Expand Up @@ -100,7 +111,9 @@ class CustomVideoPlayerController {
final bool isPortraitVideo = videoWidth < videoHeight;

/// if video has more width than height set landscape orientation
if (isLandscapeVideo) {
/// or is isAlwaysLandscapeOnFullscreen set with true then fullscreen mode will
/// always on landscape mode
if (isLandscapeVideo || isAlwaysLandscapeOnFullscreen) {
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
Expand Down Expand Up @@ -222,6 +235,16 @@ class CustomVideoPlayerController {
_playbackSpeedNotifier.value = videoPlayerController.value.playbackSpeed;
}

void setVolumeMutedUnMuted() {
if (videoPlayerController.value.volume == 0) {
videoPlayerController.setVolume(1.0);
_isMuted = false;
} else {
videoPlayerController.setVolume(0.0);
_isMuted = true;
}
}

/// call dispose on the dispose method in your parent widget to be sure that every values is disposed
void dispose() {
videoPlayerController.removeListener(_videoListeners);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import 'dart:ui';

import 'package:appinio_video_player/src/controls/custom_muted_button.dart';
import 'package:appinio_video_player/src/controls/fullscreen_button.dart';
import 'package:appinio_video_player/src/controls/play_button.dart';
import 'package:appinio_video_player/src/controls/video_settings_button.dart';
Expand Down Expand Up @@ -110,6 +112,15 @@ class CustomVideoPlayerSettings {
/// UI settings for the video settings popup.
final CustomVideoPlayerPopupSettings customVideoPlayerPopupSettings;

/// UI settings for the video to show muted volume button.
final bool showMutedButton;

/// Define the muted button appearance.
final Widget customMutedButton;

/// Define the un-muted button appearance.
final Widget customUnMutedButton;

const CustomVideoPlayerSettings({
this.customAspectRatio,
this.placeholderWidget,
Expand Down Expand Up @@ -163,5 +174,8 @@ class CustomVideoPlayerSettings {
),
this.customVideoPlayerPopupSettings =
const CustomVideoPlayerPopupSettings(),
this.showMutedButton = false,
this.customMutedButton = const CustomVideoPlayerMutedButton(),
this.customUnMutedButton = const CustomVideoPlayerUnMutedButton(),
});
}