mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-15 02:05:58 -07:00
feat: Android TV support (#503)
Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
parent
7ab8c015b9
commit
c299492d6d
168 changed files with 12019 additions and 3073 deletions
167
lib/wrappers/players/native_player.dart
Normal file
167
lib/wrappers/players/native_player.dart
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fladder/models/items/media_streams_model.dart';
|
||||
import 'package:fladder/models/playback/playback_model.dart';
|
||||
import 'package:fladder/models/settings/video_player_settings.dart';
|
||||
import 'package:fladder/src/video_player_helper.g.dart';
|
||||
import 'package:fladder/wrappers/players/base_player.dart';
|
||||
import 'package:fladder/wrappers/players/player_states.dart';
|
||||
|
||||
class NativePlayer extends BasePlayer implements VideoPlayerListenerCallback {
|
||||
final player = VideoPlayerApi();
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
return NativeVideoActivity().disposeActivity();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> init(VideoPlayerSettingsModel settings) async => VideoPlayerListenerCallback.setUp(this);
|
||||
|
||||
@override
|
||||
Future<void> loop(bool loop) {
|
||||
return player.setLooping(loop);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> loadVideo(String url, bool play) async => player.open(url, play);
|
||||
|
||||
@override
|
||||
Future<void> open(BuildContext newContext) async => NativeVideoActivity().launchActivity();
|
||||
|
||||
@override
|
||||
Future<void> pause() {
|
||||
return player.pause();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> play() => player.play();
|
||||
|
||||
@override
|
||||
Future<void> playOrPause() async {
|
||||
return;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> seek(Duration position) {
|
||||
return player.seekTo(position.inMilliseconds);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> setAudioTrack(AudioStreamModel? model, PlaybackModel playbackModel) async {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setSpeed(double speed) async {}
|
||||
|
||||
@override
|
||||
Future<int> setSubtitleTrack(SubStreamModel? model, PlaybackModel playbackModel) async {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setVolume(double volume) async {
|
||||
return player.setVolume(volume);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> stop() async {
|
||||
return player.stop();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget? subtitles(bool showOverlay, {GlobalKey<State<StatefulWidget>>? controlsKey}) => null;
|
||||
|
||||
@override
|
||||
Widget? videoWidget(Key key, BoxFit fit) => null;
|
||||
|
||||
@override
|
||||
void onPlaybackStateChanged(PlaybackState state) {
|
||||
lastState = lastState.update(
|
||||
playing: state.playing,
|
||||
position: Duration(milliseconds: state.position),
|
||||
buffer: Duration(milliseconds: state.buffered),
|
||||
buffering: state.buffering,
|
||||
);
|
||||
_stateController.add(lastState);
|
||||
}
|
||||
|
||||
final StreamController<PlayerState> _stateController = StreamController.broadcast();
|
||||
|
||||
@override
|
||||
Stream<PlayerState> get stateStream => _stateController.stream;
|
||||
|
||||
Future<void> sendPlaybackDataToNative(
|
||||
BuildContext? context,
|
||||
PlaybackModel model,
|
||||
Duration startPosition,
|
||||
) async {
|
||||
final playableData = PlayableData(
|
||||
id: model.item.id,
|
||||
title: model.item.title,
|
||||
subTitle: context != null ? model.item.label(context) : "",
|
||||
logoUrl: model.item.getPosters?.logo?.path,
|
||||
startPosition: startPosition.inMilliseconds,
|
||||
description: model.item.overview.summary,
|
||||
defaultAudioTrack: model.mediaStreams?.defaultAudioStreamIndex ?? 1,
|
||||
nextVideo: model.nextVideo?.name,
|
||||
previousVideo: model.previousVideo?.name,
|
||||
audioTracks: model.audioStreams
|
||||
?.map(
|
||||
(audio) => AudioTrack(
|
||||
name: audio.displayTitle,
|
||||
languageCode: audio.language,
|
||||
codec: audio.codec,
|
||||
index: audio.index,
|
||||
external: false,
|
||||
),
|
||||
)
|
||||
.toList() ??
|
||||
[],
|
||||
defaultSubtrack: model.mediaStreams?.defaultSubStreamIndex ?? 1,
|
||||
subtitleTracks: model.subStreams
|
||||
?.map(
|
||||
(sub) => SubtitleTrack(
|
||||
name: sub.displayTitle,
|
||||
languageCode: sub.language,
|
||||
codec: sub.codec,
|
||||
index: sub.index,
|
||||
external: sub.isExternal,
|
||||
url: sub.url,
|
||||
),
|
||||
)
|
||||
.toList() ??
|
||||
[],
|
||||
segments: model.mediaSegments?.segments
|
||||
.map(
|
||||
(e) => MediaSegment(
|
||||
type: MediaSegmentType.values.firstWhere((element) => element.name == e.type.name),
|
||||
name: context != null ? e.type.label(context) : e.type.name,
|
||||
start: e.start.inMilliseconds,
|
||||
end: e.end.inMilliseconds,
|
||||
),
|
||||
)
|
||||
.toList() ??
|
||||
[],
|
||||
trickPlayModel: model.trickPlay != null
|
||||
? TrickPlayModel(
|
||||
width: model.trickPlay!.width,
|
||||
height: model.trickPlay!.height,
|
||||
tileWidth: model.trickPlay!.tileWidth,
|
||||
tileHeight: model.trickPlay!.tileHeight,
|
||||
thumbnailCount: model.trickPlay!.thumbnailCount,
|
||||
interval: model.trickPlay!.interval.inMilliseconds,
|
||||
images: model.trickPlay?.images ?? [])
|
||||
: null,
|
||||
chapters: model.chapters
|
||||
?.map((e) => Chapter(name: e.name, url: e.imageUrl, time: e.startPosition.inMilliseconds))
|
||||
.toList() ??
|
||||
[],
|
||||
url: model.media?.url ?? "",
|
||||
);
|
||||
player.sendPlayableModel(playableData);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue