Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Widgets): Add overlay widgets to trailer video player
Signed-off-by: arafaysaleem <a.rafaysaleem@gmail.com>
- Loading branch information
1 parent
d110b14
commit 190403f
Showing
4 changed files
with
332 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:better_player/better_player.dart'; | ||
import 'package:auto_route/auto_route.dart'; | ||
|
||
class OverlayBackButton extends StatefulWidget { | ||
final BetterPlayerController betterPlayerController; | ||
|
||
const OverlayBackButton({ | ||
Key? key, | ||
required this.betterPlayerController, | ||
}) : super(key: key); | ||
|
||
@override | ||
_OverlayBackButtonState createState() => _OverlayBackButtonState(); | ||
} | ||
|
||
class _OverlayBackButtonState extends State<OverlayBackButton> { | ||
bool _isVisible = false; | ||
|
||
BetterPlayerController get _betterPlayerController => widget.betterPlayerController; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
_betterPlayerController.addEventsListener(_handlePlayerEventChanges); | ||
} | ||
|
||
/// Listens to all events sent by [_betterPlayerController] | ||
/// and handles them with the appropriate response. | ||
void _handlePlayerEventChanges(BetterPlayerEvent event) { | ||
final eventType = event.betterPlayerEventType; | ||
//handle events if initialized | ||
final controlsVisible = eventType == BetterPlayerEventType.controlsVisible; | ||
final controlsHidden = eventType == BetterPlayerEventType.controlsHidden; | ||
if (controlsVisible || controlsHidden) { //if overlay controls toggled | ||
setState(() { | ||
_isVisible = controlsVisible; | ||
}); | ||
} | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
if (!_isVisible) { | ||
return const SizedBox.shrink(); | ||
} | ||
return InkWell( | ||
onTap: () => context.router.pop(), | ||
child: const Padding( | ||
padding: EdgeInsets.all(15), | ||
child: Icon( | ||
Icons.arrow_back_sharp, | ||
color: Colors.white, | ||
size: 28, | ||
), | ||
), | ||
); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
_betterPlayerController.removeEventsListener(_handlePlayerEventChanges); | ||
super.dispose(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:better_player/better_player.dart'; | ||
|
||
class OverlayBlackHeader extends StatefulWidget { | ||
final BetterPlayerController betterPlayerController; | ||
|
||
const OverlayBlackHeader({ | ||
Key? key, | ||
required this.betterPlayerController, | ||
}) : super(key: key); | ||
|
||
@override | ||
_OverlayBlackHeaderState createState() => _OverlayBlackHeaderState(); | ||
} | ||
|
||
class _OverlayBlackHeaderState extends State<OverlayBlackHeader> { | ||
bool _isVisible = false; | ||
|
||
BetterPlayerController get _betterPlayerController => widget.betterPlayerController; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
_betterPlayerController.addEventsListener(_handlePlayerEventChanges); | ||
} | ||
|
||
/// Listens to all events sent by [_betterPlayerController] | ||
/// and handles them with the appropriate response. | ||
void _handlePlayerEventChanges(BetterPlayerEvent event) { | ||
final eventType = event.betterPlayerEventType; | ||
//handle events if initialized | ||
final controlsVisible = eventType == BetterPlayerEventType.controlsVisible; | ||
final controlsHidden = eventType == BetterPlayerEventType.controlsHidden; | ||
if (controlsVisible || controlsHidden) { //if overlay controls toggled | ||
setState(() { | ||
_isVisible = controlsVisible; | ||
}); | ||
} | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
if (!_isVisible) { | ||
return const SizedBox.shrink(); | ||
} | ||
return const IgnorePointer( | ||
child: SizedBox( | ||
width: double.infinity, | ||
height: 55, | ||
child: ColoredBox( | ||
color: Colors.black54, | ||
), | ||
), | ||
); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
_betterPlayerController.removeEventsListener(_handlePlayerEventChanges); | ||
super.dispose(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import 'package:better_player/better_player.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_hooks/flutter_hooks.dart'; | ||
import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||
|
||
//Helpers | ||
import '../../../helper/extensions/context_extensions.dart'; | ||
|
||
//Providers | ||
import '../../../providers/movies_provider.dart'; | ||
|
||
class OverlayMovieTitle extends StatefulHookWidget { | ||
final BetterPlayerController betterPlayerController; | ||
|
||
const OverlayMovieTitle({ | ||
Key? key, | ||
required this.betterPlayerController, | ||
}) : super(key: key); | ||
|
||
@override | ||
_OverlayMovieTitleState createState() => _OverlayMovieTitleState(); | ||
} | ||
|
||
class _OverlayMovieTitleState extends State<OverlayMovieTitle> { | ||
bool _isVisible = false; | ||
|
||
BetterPlayerController get _betterPlayerController => widget.betterPlayerController; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
_betterPlayerController.addEventsListener(_handlePlayerEventChanges); | ||
} | ||
|
||
/// Listens to all events sent by [_betterPlayerController] | ||
/// and handles them with the appropriate response. | ||
void _handlePlayerEventChanges(BetterPlayerEvent event) { | ||
final eventType = event.betterPlayerEventType; | ||
//handle events if initialized | ||
final controlsVisible = eventType == BetterPlayerEventType.controlsVisible; | ||
final controlsHidden = eventType == BetterPlayerEventType.controlsHidden; | ||
if (controlsVisible || controlsHidden) { //if overlay controls toggled | ||
setState(() { | ||
_isVisible = controlsVisible; | ||
}); | ||
} | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
if (!_isVisible) { | ||
return const SizedBox.shrink(); | ||
} | ||
final title = useProvider(selectedMovieProvider.select( | ||
(value) => value.state.title, | ||
)); | ||
return Text( | ||
title, | ||
maxLines: 1, | ||
style: context.headline3.copyWith(fontSize: 22), | ||
); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
_betterPlayerController.removeEventsListener(_handlePlayerEventChanges); | ||
super.dispose(); | ||
} | ||
} |
136 changes: 136 additions & 0 deletions
136
lib/views/widgets/trailer/overlay_play_pause_button.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:better_player/better_player.dart'; | ||
|
||
class OverlayPlayPauseButton extends StatefulWidget { | ||
final BetterPlayerController betterPlayerController; | ||
|
||
const OverlayPlayPauseButton({ | ||
Key? key, | ||
required this.betterPlayerController, | ||
}) : super(key: key); | ||
|
||
@override | ||
_OverlayPlayPauseButtonState createState() => _OverlayPlayPauseButtonState(); | ||
} | ||
|
||
class _OverlayPlayPauseButtonState extends State<OverlayPlayPauseButton> | ||
with SingleTickerProviderStateMixin { | ||
late bool _initialized; | ||
bool _isVisible = false; | ||
late final AnimationController _animController; | ||
|
||
BetterPlayerController get _betterPlayerController => widget.betterPlayerController; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
/// Hide visibility if buffering or uninitialized | ||
_initialized = _betterPlayerController.isPlaying() ?? false; | ||
_betterPlayerController.addEventsListener(_handlePlayerEventChanges); | ||
_animController = AnimationController( | ||
vsync: this, | ||
duration: const Duration(milliseconds: 250), | ||
); | ||
} | ||
|
||
/// Checks and sets the initialization flag to true when the | ||
/// buffering is complete. | ||
/// | ||
/// All [BetterPlayerEventType] events are ignored until [_initialized] | ||
/// is set to true. | ||
void checkInitialization() { | ||
final bufferingComplete = _betterPlayerController.isPlaying()!; | ||
if (bufferingComplete) { | ||
setState(() { | ||
_initialized = bufferingComplete; | ||
}); | ||
} | ||
} | ||
|
||
/// Listens to all events sent by [_betterPlayerController] | ||
/// and handles them with the appropriate response. | ||
void _handlePlayerEventChanges(BetterPlayerEvent event) { | ||
final eventType = event.betterPlayerEventType; | ||
if (!_initialized) { | ||
//if not initialized | ||
checkInitialization(); | ||
} else if (eventType == BetterPlayerEventType.finished) { | ||
setState(() { | ||
_isVisible = false; | ||
_initialized = false; | ||
}); | ||
} else { | ||
//handle events if initialized | ||
final controlsVisible = | ||
eventType == BetterPlayerEventType.controlsVisible; | ||
final controlsHidden = eventType == BetterPlayerEventType.controlsHidden; | ||
if (controlsVisible || controlsHidden) { | ||
//if overlay controls toggled | ||
setState(() { | ||
_isVisible = controlsVisible; | ||
}); | ||
} else if (_isVisible) { | ||
//if other events, check control visibility | ||
_handlePlayPauseEvent(eventType); | ||
} | ||
} | ||
} | ||
|
||
/// Animates the overlay play icon to pause and vice versa. | ||
/// | ||
/// Called when the play/pause event is dispatched, that is, after the | ||
/// [_handlePlayPauseTap] is called. | ||
void _handlePlayPauseEvent(BetterPlayerEventType eventType) { | ||
final isPlay = eventType == BetterPlayerEventType.play; | ||
final isPause = eventType == BetterPlayerEventType.pause; | ||
if (isPlay) { | ||
_animController.reverse(); | ||
} else if (isPause) { | ||
_animController.forward(); | ||
} | ||
} | ||
|
||
/// Pauses or resumes the video using [_betterPlayerController]. | ||
/// | ||
/// Called when the play/pause overlay button is pressed. | ||
/// | ||
/// The controller's methods send a pause/play event to the | ||
/// listener [_handlePlayerEventChanges]. | ||
void _handlePlayPauseTap() { | ||
if (_betterPlayerController.isPlaying()!) { | ||
_betterPlayerController.pause(); | ||
} else { | ||
_betterPlayerController.play(); | ||
} | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
if (!_isVisible) { | ||
return const SizedBox.shrink(); | ||
} | ||
return InkWell( | ||
onTap: _handlePlayPauseTap, | ||
child: Container( | ||
padding: const EdgeInsets.all(15), | ||
decoration: const BoxDecoration( | ||
color: Colors.black54, | ||
shape: BoxShape.circle, | ||
), | ||
child: AnimatedIcon( | ||
icon: AnimatedIcons.pause_play, | ||
color: Colors.white, | ||
size: 32, | ||
progress: _animController, | ||
), | ||
), | ||
); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
_betterPlayerController.removeEventsListener(_handlePlayerEventChanges); | ||
_animController.dispose(); | ||
super.dispose(); | ||
} | ||
} |