ExpandedControl: stub ad skip handling

This commit is contained in:
gianlucaparadise 2022-01-03 11:44:48 +01:00
parent 6a1ec6c906
commit 0ddfa046b9
2 changed files with 144 additions and 12 deletions

View file

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_cast_framework/src/cast/widgets/expanded_controls/ExpandedControlsAdSkipBox.dart';
import '../../../../cast.dart';
import 'ExpandedControlsBasicButton.dart';
import 'ExpandedControlsConnectedDeviceLabel.dart';
import 'ExpandedControlsHighlightedText.dart';
import 'ExpandedControlsInfoTextBox.dart';
@ -34,16 +34,28 @@ const _bottomUpBlackGradient = BoxDecoration(
class ExpandedControls extends StatefulWidget {
final FlutterCastFramework castFramework;
/// Label to introduce cast device. Default is "Casting to {{device_name}}", where {{device_name}} is replaced with the device name
/// Label to introduce cast device. Default is "Casting to {{cast_device_name}}", where {{cast_device_name}} is replaced with the device name
/// {{cast_device_name}} can be found in the constant CAST_DEVICE_NAME_PLACEHOLDER.
final String? castingToText;
/// Label to indicate remaining time for ad. Default is "You can skip this ad in {{skip_remaining_time}}...",
/// where {{skip_remaining_time}} is replaced with the remaining time.
/// {{skip_remaining_time}} can be found in the constant SKIP_AD_TIMER_PLACEHOLDER.
final String? skipAdTimerText;
/// Label for the Skip Ad button. Default is "Skip Ad".
final String? skipAdButtonText;
/// This is called when the back button is tapped or when the session is closed
final VoidCallback? onCloseRequested;
final controller = ExpandedControlsProgressController();
final progressController = ExpandedControlsProgressController();
final adSkipBoxController = ExpandedControlsAdSkipBoxController();
ExpandedControls({
required this.castFramework,
this.castingToText,
this.skipAdTimerText,
this.skipAdButtonText,
this.onCloseRequested,
});
@ -74,7 +86,7 @@ class _ExpandedControlsState extends State<ExpandedControls> {
sessionManager.remoteMediaClient.onProgressUpdated = null;
sessionManager.remoteMediaClient.onAdBreakClipProgressUpdated = null;
widget.controller.dispose();
widget.progressController.dispose();
super.dispose();
}
@ -107,7 +119,7 @@ class _ExpandedControlsState extends State<ExpandedControls> {
}
void _onProgressUpdated(int progress, int duration) {
widget.controller.updateProgress(progress, duration);
widget.progressController.updateProgress(progress, duration);
}
void _onAdBreakClipProgressUpdated(
@ -117,9 +129,8 @@ class _ExpandedControlsState extends State<ExpandedControls> {
int durationMs,
int whenSkippableMs,
) {
debugPrint(
"adBreakId: $adBreakId adBreakClipId: $adBreakClipId progress: $progressMs duration: $durationMs whenSkip: $whenSkippableMs");
widget.controller.updateProgress(progressMs, durationMs);
widget.adSkipBoxController
.updateProgress(progressMs, durationMs, whenSkippableMs);
}
Widget _getDecoratedToolbar(MediaInfo? mediaInfo) {
@ -155,7 +166,7 @@ class _ExpandedControlsState extends State<ExpandedControls> {
Padding(
padding: const EdgeInsets.all(8.0),
child: ExpandedControlsProgress(
controller: widget.controller,
controller: widget.progressController,
),
),
Padding(
@ -202,9 +213,11 @@ class _ExpandedControlsState extends State<ExpandedControls> {
),
),
const Spacer(flex: 1),
ExpandedControlsBasicButton(
text: "Skip Ad", // TODO: localize label
onPressed: () {/* TODO: skip ad */},
ExpandedControlsAdSkipBox(
controller: widget.adSkipBoxController,
skipAdButtonText: widget.skipAdButtonText,
skipAdTimerText: widget.skipAdTimerText,
onSkipPressed: () {/* TODO: skip ad */},
),
];
}

View file

@ -0,0 +1,119 @@
import 'package:flutter/material.dart';
import 'ExpandedControlsBasicButton.dart';
class ExpandedControlsAdSkipBoxController extends ChangeNotifier {
int progress = 0;
int duration = 0;
int whenSkippable = 0;
void updateProgress(int progress, int duration, int whenSkippable) {
this.progress = progress;
this.duration = duration;
this.whenSkippable = whenSkippable;
notifyListeners();
}
}
/// Placeholder to be used for the castingToText of ExpandedControlsConnectedDeviceLabel
const SKIP_AD_TIMER_PLACEHOLDER = "{{skip_remaining_time}}";
class ExpandedControlsAdSkipBox extends StatefulWidget {
final ExpandedControlsAdSkipBoxController controller;
final _defaultSkipAdTimerText =
"You can skip this ad in $SKIP_AD_TIMER_PLACEHOLDER...";
final _defaultSkipAdButtonText = "Skip Ad";
/// Label to indicate remaining time for ad. Default is "You can skip this ad in {{skip_remaining_time}}...",
/// where {{skip_remaining_time}} is replaced with the remaining time.
/// {{skip_remaining_time}} can be found in the constant SKIP_AD_TIMER_PLACEHOLDER.
final String? skipAdTimerText;
/// Label for the Skip Ad button. Default is "Skip Ad".
final String? skipAdButtonText;
final VoidCallback? onSkipPressed;
const ExpandedControlsAdSkipBox({
Key? key,
required this.controller,
this.skipAdButtonText,
this.skipAdTimerText,
this.onSkipPressed,
}) : super(key: key);
@override
State<ExpandedControlsAdSkipBox> createState() =>
_ExpandedControlsAdSkipBoxState();
}
class _ExpandedControlsAdSkipBoxState extends State<ExpandedControlsAdSkipBox> {
int progress = 0;
int duration = 0;
int whenSkippable = 5000;
@override
void initState() {
widget.controller.addListener(_onProgressUpdated);
super.initState();
}
@override
void dispose() {
widget.controller.removeListener(_onProgressUpdated);
super.dispose();
}
void _onProgressUpdated() {
setState(() {
if (!mounted) return;
this.progress = widget.controller.progress;
this.duration = widget.controller.duration;
this.whenSkippable = widget.controller.whenSkippable;
});
}
String _replaceRemainingTime(
String textWithPlaceholder, String remainingTime) {
return textWithPlaceholder.replaceAll(
SKIP_AD_TIMER_PLACEHOLDER, remainingTime);
}
@override
Widget build(BuildContext context) {
final canSkip = progress > whenSkippable;
if (canSkip) {
return ExpandedControlsBasicButton(
text: widget.skipAdButtonText ?? widget._defaultSkipAdButtonText,
onPressed: widget.onSkipPressed,
);
}
final remainingTimeMs = this.whenSkippable - this.progress;
final remainingTimeD = Duration(milliseconds: remainingTimeMs);
final durationD = Duration(milliseconds: this.duration);
final remainingTime = _positionToString(remainingTimeD, durationD);
final baseLabel = widget.skipAdTimerText ?? widget._defaultSkipAdTimerText;
final label = _replaceRemainingTime(baseLabel, remainingTime);
return Text(
label,
style: TextStyle(color: Colors.white),
);
}
}
String _positionToString(Duration d, Duration total) {
String twoDigits(int n) => n.toString().padLeft(2, "0");
if (total.inSeconds <= 60) {
// This is less than a minute, I display only seconds
return "${d.inSeconds}";
}
if (total.inMinutes <= 60) {
// This is less than a hour, I display only minutes and seconds
return "${twoDigits(d.inMinutes)}:${twoDigits(d.inSeconds.remainder(60))}";
}
return "${twoDigits(d.inHours)}:${twoDigits(d.inMinutes.remainder(60))}:${twoDigits(d.inSeconds.remainder(60))}";
}