Initial commit
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../core/infra/player_engine/player_engine.dart';
|
||||
import '../../../shared/utils/format_utils.dart';
|
||||
|
||||
class PlayerPositionIndicator extends StatefulWidget {
|
||||
final PlayerEngine player;
|
||||
|
||||
|
||||
final ValueNotifier<Duration?>? seekPreview;
|
||||
|
||||
const PlayerPositionIndicator({
|
||||
super.key,
|
||||
required this.player,
|
||||
this.seekPreview,
|
||||
});
|
||||
|
||||
@override
|
||||
State<PlayerPositionIndicator> createState() =>
|
||||
_PlayerPositionIndicatorState();
|
||||
}
|
||||
|
||||
class _PlayerPositionIndicatorState extends State<PlayerPositionIndicator> {
|
||||
late Duration _position;
|
||||
late Duration _duration;
|
||||
StreamSubscription<Duration>? _posSub;
|
||||
StreamSubscription<Duration>? _durSub;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_position = widget.player.state.position;
|
||||
_duration = widget.player.state.duration;
|
||||
_posSub = widget.player.stream.position.listen((position) {
|
||||
if (mounted) setState(() => _position = position);
|
||||
});
|
||||
_durSub = widget.player.stream.duration.listen((duration) {
|
||||
if (mounted) setState(() => _duration = duration);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant PlayerPositionIndicator oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.player != widget.player) {
|
||||
unawaited(_posSub?.cancel());
|
||||
unawaited(_durSub?.cancel());
|
||||
_position = widget.player.state.position;
|
||||
_duration = widget.player.state.duration;
|
||||
_posSub = widget.player.stream.position.listen((position) {
|
||||
if (mounted) setState(() => _position = position);
|
||||
});
|
||||
_durSub = widget.player.stream.duration.listen((duration) {
|
||||
if (mounted) setState(() => _duration = duration);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
unawaited(_posSub?.cancel());
|
||||
unawaited(_durSub?.cancel());
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Widget _buildText(Duration position, Duration duration) {
|
||||
return SizedBox(
|
||||
width: 126,
|
||||
child: Text(
|
||||
'${formatDurationClock(position)} / ${formatDurationClock(duration)}',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: 13,
|
||||
fontFeatures: [ui.FontFeature.tabularFigures()],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final seekPreview = widget.seekPreview;
|
||||
if (seekPreview != null) {
|
||||
return ValueListenableBuilder<Duration?>(
|
||||
valueListenable: seekPreview,
|
||||
builder: (context, preview, _) {
|
||||
final displayPos = preview ?? _position;
|
||||
return _buildText(displayPos, _duration);
|
||||
},
|
||||
);
|
||||
}
|
||||
return _buildText(_position, _duration);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user