This commit is contained in:
Alex Kim
2024-10-12 03:00:26 +11:00
parent 8be1e2df0c
commit 57354e6b06
6 changed files with 123 additions and 49 deletions

View File

@@ -6,7 +6,7 @@ import { Loader } from "@/components/Loader";
import { MediaListSection } from "@/components/medialists/MediaListSection";
import { Colors } from "@/constants/Colors";
import { TAB_HEIGHT } from "@/constants/Values";
import { hello } from "@/modules/vlc-player";
import { hello, VlcPlayerView } from "@/modules/vlc-player";
import { useDownload } from "@/providers/DownloadProvider";
import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
import { useSettings } from "@/utils/atoms/settings";
@@ -383,9 +383,27 @@ export default function index() {
);
return (
<View>
<Text>{hello()}</Text>
</View>
<ScrollView
nestedScrollEnabled
contentInsetAdjustmentBehavior="automatic"
refreshControl={
<RefreshControl refreshing={loading} onRefresh={refetch} />
}
key={"home"}
contentContainerStyle={{
paddingLeft: insets.left,
paddingRight: insets.right,
paddingBottom: 16,
}}
style={{
marginBottom: TAB_HEIGHT,
}}
>
<View className="flex flex-col space-y-4">
<Text>{hello()}</Text>
<VlcPlayerView source="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" />
</View>
</ScrollView>
);
}

View File

@@ -1,10 +1,14 @@
import { NativeModulesProxy, EventEmitter, Subscription } from 'expo-modules-core';
import {
NativeModulesProxy,
EventEmitter,
Subscription,
} from "expo-modules-core";
// Import the native module. On web, it will be resolved to VlcPlayer.web.ts
// and on native platforms to VlcPlayer.ts
import VlcPlayerModule from './src/VlcPlayerModule';
import VlcPlayerView from './src/VlcPlayerView';
import { ChangeEventPayload, VlcPlayerViewProps } from './src/VlcPlayer.types';
import VlcPlayerModule from "./src/VlcPlayerModule";
import VlcPlayerView from "./src/VlcPlayerView";
import { ChangeEventPayload, VlcPlayerViewProps } from "./src/VlcPlayer.types";
// Get the native constant value.
export const PI = VlcPlayerModule.PI;
@@ -17,10 +21,14 @@ export async function setValueAsync(value: string) {
return await VlcPlayerModule.setValueAsync(value);
}
const emitter = new EventEmitter(VlcPlayerModule ?? NativeModulesProxy.VlcPlayer);
const emitter = new EventEmitter(
VlcPlayerModule ?? NativeModulesProxy.VlcPlayer
);
export function addChangeListener(listener: (event: ChangeEventPayload) => void): Subscription {
return emitter.addListener<ChangeEventPayload>('onChange', listener);
export function addChangeListener(
listener: (event: ChangeEventPayload) => void
): Subscription {
return emitter.addListener<ChangeEventPayload>("onChange", listener);
}
export { VlcPlayerView, VlcPlayerViewProps, ChangeEventPayload };

View File

@@ -9,36 +9,14 @@ public class VlcPlayerModule: Module {
// Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
// The module will be accessible from `requireNativeModule('VlcPlayer')` in JavaScript.
Name("VlcPlayer")
// Sets constant properties on the module. Can take a dictionary or a closure that returns a dictionary.
Constants([
"PI": Double.pi
])
// Defines event names that the module can send to JavaScript.
Events("onChange")
// Defines a JavaScript synchronous function that runs the native code on the JavaScript thread.
Function("hello") {
return "Hello world! 👋"
}
// Defines a JavaScript function that always returns a Promise and whose native code
// is by default dispatched on the different thread than the JavaScript runtime runs on.
AsyncFunction("setValueAsync") { (value: String) in
// Send an event to JavaScript.
self.sendEvent("onChange", [
"value": value
])
}
// Enables the module to be used as a native view. Definition components that are accepted as part of the
// view definition: Prop, Events.
View(VlcPlayerView.self) {
// Defines a setter for the `name` prop.
Prop("name") { (view: VlcPlayerView, prop: String) in
print(prop)
Prop("source") { (view: VlcPlayerView, source: String) in
view.setSource(source)
}
}
Function("hello") {
return "hello from native ios"
}
}
}

View File

@@ -1,7 +1,77 @@
import ExpoModulesCore
import UIKit
import MobileVLCKit
// This view will be used as a native component. Make sure to inherit from `ExpoView`
// to apply the proper styling (e.g. border radius and shadows).
class VlcPlayerView: ExpoView {
}
class VlcPlayerView: ExpoView, VLCMediaPlayerDelegate {
private var mediaPlayer: VLCMediaPlayer?
private var movieView: UIView?
required init(appContext: AppContext? = nil) {
super.init(appContext: appContext)
DispatchQueue.main.async {
self.setupView()
self.backgroundColor = UIColor.black // Set background color to black
}
}
private func setupView() {
DispatchQueue.main.async {
self.movieView = UIView()
self.movieView?.translatesAutoresizingMaskIntoConstraints = false
if let movieView = self.movieView {
self.addSubview(movieView)
NSLayoutConstraint.activate([
movieView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
movieView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
movieView.topAnchor.constraint(equalTo: self.topAnchor),
movieView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
])
}
self.setupMediaPlayer()
}
}
private func setupMediaPlayer() {
DispatchQueue.main.async {
self.mediaPlayer = VLCMediaPlayer()
self.mediaPlayer?.delegate = self
self.mediaPlayer?.drawable = self.movieView
print("Media player setup on main thread: \(Thread.isMainThread)")
}
}
@objc func setSource(_ source: String) {
DispatchQueue.main.async {
print("Setting media source on main thread: \(Thread.isMainThread)")
if let url = URL(string: source) {
self.mediaPlayer?.media = VLCMedia(url: url)
print("Media set, now playing...")
self.mediaPlayer?.play()
} else {
print("Invalid URL.")
}
}
}
@objc func handlePlayPause() {
DispatchQueue.main.async {
print("Handling play/pause on main thread: \(Thread.isMainThread)")
if self.mediaPlayer?.isPlaying == true {
self.mediaPlayer?.pause()
} else {
self.mediaPlayer?.play()
}
}
}
func mediaPlayerStateChanged(_ aNotification: Notification!) {
DispatchQueue.main.async {
print("Media player state changed on main thread: \(Thread.isMainThread)")
if self.mediaPlayer?.state == .stopped {
print("Media player stopped")
}
}
}
}

View File

@@ -3,5 +3,5 @@ export type ChangeEventPayload = {
};
export type VlcPlayerViewProps = {
name: string;
source: string;
};

View File

@@ -1,10 +1,10 @@
import { requireNativeViewManager } from 'expo-modules-core';
import * as React from 'react';
import { requireNativeViewManager } from "expo-modules-core";
import * as React from "react";
import { VlcPlayerViewProps } from './VlcPlayer.types';
import { VlcPlayerViewProps } from "./VlcPlayer.types";
const NativeView: React.ComponentType<VlcPlayerViewProps> =
requireNativeViewManager('VlcPlayer');
requireNativeViewManager("VlcPlayer");
export default function VlcPlayerView(props: VlcPlayerViewProps) {
return <NativeView {...props} />;