aves/plugins/aves_video/lib/src/controller.dart
2023-07-16 00:46:21 +02:00

143 lines
3.4 KiB
Dart

import 'dart:async';
import 'package:aves_model/aves_model.dart';
import 'package:aves_video/aves_video.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
abstract class AvesVideoControllerFactory {
void init();
AvesVideoController buildController(
AvesEntryBase entry, {
required PlaybackStateHandler playbackStateHandler,
required VideoSettings settings,
});
}
abstract class AvesVideoController {
final AvesEntryBase _entry;
final PlaybackStateHandler playbackStateHandler;
final VideoSettings settings;
AvesEntryBase get entry => _entry;
static const resumeTimeSaveMinDuration = Duration(minutes: 2);
AvesVideoController(
AvesEntryBase entry, {
required this.playbackStateHandler,
required this.settings,
}) : _entry = entry {
entry.visualChangeNotifier.addListener(onVisualChanged);
}
@mustCallSuper
Future<void> dispose() async {
_entry.visualChangeNotifier.removeListener(onVisualChanged);
await _savePlaybackState();
}
Future<void> _savePlaybackState() async {
if (!isReady || duration < resumeTimeSaveMinDuration.inMilliseconds) return;
await playbackStateHandler.saveResumeTime(entryId: _entry.id, position: currentPosition, progress: progress);
}
Future<int?> getResumeTime(BuildContext context) => playbackStateHandler.getResumeTime(entryId: _entry.id, context: context);
void onVisualChanged();
Future<void> play();
Future<void> pause();
Future<void> seekTo(int targetMillis);
Future<void> seekToProgress(double progress) => seekTo((duration * progress.clamp(0, 1)).toInt());
Listenable get playCompletedListenable;
VideoStatus get status;
Stream<VideoStatus> get statusStream;
Stream<double> get volumeStream;
Stream<double> get speedStream;
bool get isReady;
Future<void> get untilReady {
if (isReady) return Future.value();
final completer = Completer();
late StreamSubscription<VideoStatus> sub;
sub = statusStream.where((_) => isReady).listen((_) {
sub.cancel();
completer.complete();
});
return completer.future;
}
bool get isPlaying => status == VideoStatus.playing;
int get duration;
int get currentPosition;
double get progress {
final _duration = duration;
return _duration != 0 ? currentPosition.toDouble() / _duration : 0;
}
Stream<int> get positionStream;
Stream<String?> get timedTextStream;
ValueNotifier<bool> get canCaptureFrameNotifier;
ValueNotifier<bool> get canMuteNotifier;
ValueNotifier<bool> get canSetSpeedNotifier;
ValueNotifier<bool> get canSelectStreamNotifier;
ValueNotifier<double> get sarNotifier;
bool get isMuted;
double get speed;
double get minSpeed;
double get maxSpeed;
set speed(double speed);
Future<void> selectStream(MediaStreamType type, MediaStreamSummary? selected);
Future<MediaStreamSummary?> getSelectedStream(MediaStreamType type);
List<MediaStreamSummary> get streams;
Future<Uint8List?> captureFrame();
Future<void> mute(bool muted);
Widget buildPlayerWidget(BuildContext context);
}
enum VideoStatus {
idle,
initialized,
paused,
playing,
completed,
error,
}
abstract class PlaybackStateHandler {
Future<int?> getResumeTime({required int entryId, required BuildContext context});
Future<void> saveResumeTime({required int entryId, required int position, required double progress});
}