Skip to content

Commit

Permalink
Merge pull request #414 from lamarios/feature/freezed_players
Browse files Browse the repository at this point in the history
Migrate to freezed for video and audio player
  • Loading branch information
lamarios authored Dec 16, 2023
2 parents e3be757 + 9eb6a02 commit f753f8a
Show file tree
Hide file tree
Showing 15 changed files with 980 additions and 642 deletions.
19 changes: 12 additions & 7 deletions lib/app/views/screens/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@ class MainScreen extends StatelessWidget {

@override
Widget build(BuildContext context) {
return const Stack(
children: [
MiniPlayerAware(
child: AutoRouter(),
return LayoutBuilder(builder: (context, constraints) {
return Container(
color: Theme.of(context).colorScheme.background,
child: Stack(
children: [
const MiniPlayerAware(
child: AutoRouter(),
),
Player(constraints.maxHeight)
],
),
Player()
],
);
);
});
}
}
113 changes: 53 additions & 60 deletions lib/player/states/audio_player.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:copy_with_extension/copy_with_extension.dart';
import 'package:easy_debounce/easy_throttle.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:invidious/downloads/models/downloaded_video.dart';
import 'package:invidious/extensions.dart';
import 'package:invidious/globals.dart';
Expand All @@ -12,11 +12,12 @@ import '../../settings/states/settings.dart';
import '../../videos/models/adaptive_format.dart';
import '../models/media_event.dart';

part 'audio_player.g.dart';
part 'audio_player.freezed.dart';

Logger log = Logger('AudioPlayerController');

class AudioPlayerCubit extends MediaPlayerCubit<AudioPlayerState> {
AudioPlayer? audioPlayer;
final SettingsCubit settings;

AudioPlayerCubit(super.initialState, super.player, this.settings) {
Expand All @@ -36,19 +37,19 @@ class AudioPlayerCubit extends MediaPlayerCubit<AudioPlayerState> {

@override
void disposeControllers() {
state.player?.dispose();
audioPlayer?.dispose();
}

initPlayer() {
if (state.player == null) {
state.player = AudioPlayer();
state.player?.playerStateStream.listen(onStateStreamChange,
if (audioPlayer == null) {
audioPlayer = AudioPlayer();
audioPlayer?.playerStateStream.listen(onStateStreamChange,
onError: (e, st) {
return player.setEvent(const MediaEvent(state: MediaState.error));
});
state.player?.positionStream.listen(onPositionChanged);
state.player?.durationStream.listen(onDurationChanged);
state.player?.bufferedPositionStream.listen(onBufferChanged);
audioPlayer?.positionStream.listen(onPositionChanged);
audioPlayer?.durationStream.listen(onDurationChanged);
audioPlayer?.bufferedPositionStream.listen(onBufferChanged);
}
}

Expand All @@ -75,8 +76,7 @@ class AudioPlayerCubit extends MediaPlayerCubit<AudioPlayerState> {
}

onDurationChanged(Duration? duration) async {
var state = this.state.copyWith();
state.loading = false;
emit(state.copyWith(loading: false));
if (!isClosed) emit(state);
player.setEvent(MediaEvent(
state: MediaState.playing,
Expand All @@ -86,7 +86,7 @@ class AudioPlayerCubit extends MediaPlayerCubit<AudioPlayerState> {

onPositionChanged(Duration position) {
EasyThrottle.throttle('audio-progress', const Duration(seconds: 1), () {
state.audioPosition = position;
emit(state.copyWith(audioPosition: position));
player.setEvent(MediaEvent(
state: MediaState.playing,
type: MediaEventType.progress,
Expand All @@ -102,13 +102,14 @@ class AudioPlayerCubit extends MediaPlayerCubit<AudioPlayerState> {
if (state.video != null || state.offlineVideo != null) {
// disposeControllers();
initPlayer();
var state = this.state.copyWith();
state.audioPosition = Duration.zero;
state.audioLength = Duration(
var audioLength = Duration(
seconds: offline
? state.offlineVideo!.lengthSeconds
: state.video!.lengthSeconds);
state.loading = true;
emit(state.copyWith(
audioPosition: Duration.zero,
audioLength: audioLength,
loading: true));
player.setEvent(const MediaEvent(state: MediaState.loading));
try {
AudioSource? source;
Expand Down Expand Up @@ -146,7 +147,7 @@ class AudioPlayerCubit extends MediaPlayerCubit<AudioPlayerState> {
throw Error();
}

await state.player?.setAudioSource(source, initialPosition: startAt);
await audioPlayer?.setAudioSource(source, initialPosition: startAt);

play();
// TODO: make this less duplicated between videos and audio
Expand All @@ -155,14 +156,13 @@ class AudioPlayerCubit extends MediaPlayerCubit<AudioPlayerState> {
speed = settings.state.lastSpeed;

log.fine("Setting playback speed to $speed");
state.player?.setSpeed(speed);
audioPlayer?.setSpeed(speed);
}
} catch (e) {
log.severe("Couldn't play video", e);
player.setEvent(const MediaEvent(state: MediaState.error));
state.error = e.toString();
state.loading = false;
if (!isClosed) emit(state);
if (!isClosed)
emit(state.copyWith(error: e.toString(), loading: false));
}
}
super.playVideo(offline);
Expand All @@ -175,62 +175,54 @@ class AudioPlayerCubit extends MediaPlayerCubit<AudioPlayerState> {

@override
void switchToOfflineVideo(DownloadedVideo v) {
state.video = null;
state.offlineVideo = v;
emit(state.copyWith(video: null, offlineVideo: v));
playVideo(true);
}

@override
void switchVideo(Video video, {Duration? startAt}) async {
state.offlineVideo = null;
state.video = video;
emit(state.copyWith(video: video, offlineVideo: null));
playVideo(false, startAt: startAt);
}

@override
void togglePlaying() {
var state = this.state.copyWith();
state.playing ? play() : pause();
playing ? play() : pause();
emit(state);
}

void onScrubbed(double value) {
var state = this.state.copyWith();
Duration seekTo = Duration(milliseconds: value.toInt());
seek(seekTo);
state.audioPosition = seekTo;
emit(state);
emit(state.copyWith(audioPosition: seekTo));
}

void onScrubDrag(double value) {
var state = this.state.copyWith();
Duration seekTo = Duration(milliseconds: value.toInt());
state.audioPosition = seekTo;
emit(state);
emit(state.copyWith(audioPosition: seekTo));
}

@override
void toggleControls(bool visible) {
var state = this.state.copyWith();
state.disableControls = !visible;
emit(state);
emit(state.copyWith(disableControls: !visible));
}

@override
bool isPlaying() {
return state.playing;
return playing;
}

@override
void play() {
state.player?.play();
audioPlayer?.play();
player.setEvent(
const MediaEvent(state: MediaState.playing, type: MediaEventType.play));
}

@override
void seek(Duration position) {
state.player?.seek(position);
audioPlayer?.seek(position);
player.setEvent(
const MediaEvent(state: MediaState.playing, type: MediaEventType.seek));
player.setEvent(MediaEvent(
Expand All @@ -241,14 +233,14 @@ class AudioPlayerCubit extends MediaPlayerCubit<AudioPlayerState> {

@override
void pause() {
state.player?.pause();
audioPlayer?.pause();
player.setEvent(const MediaEvent(
state: MediaState.playing, type: MediaEventType.pause));
}

@override
Duration? bufferedPosition() {
return state.player?.bufferedPosition;
return audioPlayer?.bufferedPosition;
}

@override
Expand Down Expand Up @@ -310,23 +302,23 @@ class AudioPlayerCubit extends MediaPlayerCubit<AudioPlayerState> {

@override
bool isMuted() {
return (state.player?.volume ?? 0) == 0;
return (audioPlayer?.volume ?? 0) == 0;
}

@override
void toggleVolume(bool soundOn) {
state.player?.setVolume(soundOn ? 1 : 0);
audioPlayer?.setVolume(soundOn ? 1 : 0);
}

@override
void setSpeed(double d) {
state.player?.setSpeed(d);
audioPlayer?.setSpeed(d);
settings.setLastSpeed(d);
}

@override
double getSpeed() {
return state.player?.speed ?? 1;
return audioPlayer?.speed ?? 1;
}

@override
Expand All @@ -347,7 +339,7 @@ class AudioPlayerCubit extends MediaPlayerCubit<AudioPlayerState> {

@override
Duration duration() {
return state.player?.duration ?? const Duration(milliseconds: 1);
return audioPlayer?.duration ?? const Duration(milliseconds: 1);
}

void onBufferChanged(Duration event) {
Expand All @@ -358,25 +350,26 @@ class AudioPlayerCubit extends MediaPlayerCubit<AudioPlayerState> {
value: event));
});
}
}

@CopyWith(constructor: "_")
class AudioPlayerState extends MediaPlayerState {
AudioPlayer? player;
bool get playing => audioPlayer?.playing ?? false;
}

AudioPlayerState({super.video, super.offlineVideo});
@freezed
class AudioPlayerState extends MediaPlayerState with _$AudioPlayerState {
const factory AudioPlayerState({
@Default(Duration(milliseconds: 1)) Duration audioLength,
@Default(Duration.zero) Duration audioPosition,
@Default(0) int previousSponsorCheck,
Video? video,
DownloadedVideo? offlineVideo,
bool? playNow,
bool? disableControls,
@Default(false) bool loading,
String? error,
}) = _AudioPlayerState;

double get progress =>
audioPosition.inMilliseconds / audioLength.inMilliseconds;
Duration audioLength = const Duration(milliseconds: 1);
Duration audioPosition = const Duration(milliseconds: 0);
int previousSponsorCheck = 0;

bool get playing => player?.playing ?? false;
bool loading = false;
String? error;

AudioPlayerState._(this.player, this.audioLength, this.audioPosition,
this.previousSponsorCheck, this.loading, this.error,
{super.video, super.offlineVideo, super.disableControls, super.playNow});
const AudioPlayerState._();
}
Loading

0 comments on commit f753f8a

Please sign in to comment.