Implement view

This commit is contained in:
2026-04-10 20:12:34 +02:00
parent fd40915bc9
commit 626380bcc4
14 changed files with 126 additions and 30 deletions
@@ -13,13 +13,16 @@ import org.videolan.libvlc.Media
import org.videolan.libvlc.MediaPlayer
import org.videolan.libvlc.interfaces.IMedia
class OmniPlayer() : HybridOmniPlayerSpec() {
object VlcConst {
val vlc = LibVLC(NitroModules.applicationContext ?: throw Error("No Context available!"))
val player = MediaPlayer(vlc)
}
class OmniPlayer() : HybridOmniPlayerSpec() {
val player = MediaPlayer(VlcConst.vlc)
override var source: Source by deferredObservable { _, _, new ->
val src = new.src.firstOrNull()?.uri ?: return@deferredObservable
player.media = Media(vlc, Uri.parse(src))
player.media = Media(VlcConst.vlc, Uri.parse(src))
new.startTime?.let { start ->
player.time = (start * 1000.0).toLong().coerceAtLeast(0L)
}
@@ -1,22 +1,57 @@
package dev.zoriya.omni
import android.graphics.Color
import android.view.View
import com.facebook.react.uimanager.ThemedReactContext
import com.margelo.nitro.omni.HybridOmniPlayerSpec
import com.margelo.nitro.omni.HybridOmniViewSpec
import org.videolan.libvlc.util.VLCVideoLayout
class OmniView(val context: ThemedReactContext) : HybridOmniViewSpec() {
// View
override val view: View = View(context)
private val videoLayout = VLCVideoLayout(context)
private var viewsAttached = false
private var boundPlayer: OmniPlayer? = null
// Props
override var autoplay: Boolean?
get() = TODO("Not yet implemented")
set(value) {}
override var showNotification: Boolean?
get() = TODO("Not yet implemented")
set(value) {}
override var autoPip: Boolean?
get() = TODO("Not yet implemented")
set(value) {}
override val view: View = videoLayout
override lateinit var player: HybridOmniPlayerSpec
override var autoplay: Boolean? = true
override var showNotification: Boolean? = true
override var autoPip: Boolean? = true
override fun afterUpdate() {
if (!::player.isInitialized) {
throw IllegalStateException("Player is null in OmniView")
}
val omniPlayer = player as? OmniPlayer
?: throw IllegalStateException("Player is not an OmniPlayer in OmniView")
val vout = omniPlayer.player.vlcVout
if (boundPlayer !== omniPlayer) {
boundPlayer?.player?.detachViews()
viewsAttached = false
boundPlayer = omniPlayer
}
if (!viewsAttached || !vout.areViewsAttached()) {
omniPlayer.player.attachViews(videoLayout, null, false, false)
viewsAttached = true
}
if (autoplay == true && !omniPlayer.isPlaying) {
omniPlayer.play()
}
}
override fun onDropView() {
if (!::player.isInitialized) return
val omniPlayer = player as? OmniPlayer ?: return
val vout = omniPlayer.player.vlcVout
if (vout.areViewsAttached()) {
omniPlayer.player.detachViews()
}
viewsAttached = false
boundPlayer = null
}
}
+14 -1
View File
@@ -7,8 +7,12 @@
#include "JHybridOmniViewSpec.hpp"
// Forward declaration of `HybridOmniPlayerSpec` to properly resolve imports.
namespace margelo::nitro::omni { class HybridOmniPlayerSpec; }
#include <memory>
#include "HybridOmniPlayerSpec.hpp"
#include "JHybridOmniPlayerSpec.hpp"
#include <optional>
namespace margelo::nitro::omni {
@@ -41,6 +45,15 @@ namespace margelo::nitro::omni {
}
// Properties
std::shared_ptr<HybridOmniPlayerSpec> JHybridOmniViewSpec::getPlayer() {
static const auto method = _javaPart->javaClassStatic()->getMethod<jni::local_ref<JHybridOmniPlayerSpec::JavaPart>()>("getPlayer");
auto __result = method(_javaPart);
return __result->getJHybridOmniPlayerSpec();
}
void JHybridOmniViewSpec::setPlayer(const std::shared_ptr<HybridOmniPlayerSpec>& player) {
static const auto method = _javaPart->javaClassStatic()->getMethod<void(jni::alias_ref<JHybridOmniPlayerSpec::JavaPart> /* player */)>("setPlayer");
method(_javaPart, std::dynamic_pointer_cast<JHybridOmniPlayerSpec>(player)->getJavaPart());
}
std::optional<bool> JHybridOmniViewSpec::getAutoplay() {
static const auto method = _javaPart->javaClassStatic()->getMethod<jni::local_ref<jni::JBoolean>()>("getAutoplay");
auto __result = method(_javaPart);
+2
View File
@@ -50,6 +50,8 @@ namespace margelo::nitro::omni {
public:
// Properties
std::shared_ptr<HybridOmniPlayerSpec> getPlayer() override;
void setPlayer(const std::shared_ptr<HybridOmniPlayerSpec>& player) override;
std::optional<bool> getAutoplay() override;
void setAutoplay(std::optional<bool> autoplay) override;
std::optional<bool> getShowNotification() override;
@@ -37,6 +37,10 @@ void JHybridOmniViewStateUpdater::updateViewProps(jni::alias_ref<jni::JClass> /*
}
// Update all props if they are dirty
if (props->player.isDirty) {
hybridView->setPlayer(props->player.value);
props->player.isDirty = false;
}
if (props->autoplay.isDirty) {
hybridView->setAutoplay(props->autoplay.value);
props->autoplay.isDirty = false;
@@ -26,6 +26,12 @@ import com.margelo.nitro.views.HybridView
)
abstract class HybridOmniViewSpec: HybridView() {
// Properties
@get:DoNotStrip
@get:Keep
@set:DoNotStrip
@set:Keep
abstract var player: HybridOmniPlayerSpec
@get:DoNotStrip
@get:Keep
@set:DoNotStrip
+2
View File
@@ -14,6 +14,8 @@ namespace margelo::nitro::omni {
HybridObject::loadHybridMethods();
// load custom methods/properties
registerHybrids(this, [](Prototype& prototype) {
prototype.registerHybridGetter("player", &HybridOmniViewSpec::getPlayer);
prototype.registerHybridSetter("player", &HybridOmniViewSpec::setPlayer);
prototype.registerHybridGetter("autoplay", &HybridOmniViewSpec::getAutoplay);
prototype.registerHybridSetter("autoplay", &HybridOmniViewSpec::setAutoplay);
prototype.registerHybridGetter("showNotification", &HybridOmniViewSpec::getShowNotification);
+6 -1
View File
@@ -13,8 +13,11 @@
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
#endif
// Forward declaration of `HybridOmniPlayerSpec` to properly resolve imports.
namespace margelo::nitro::omni { class HybridOmniPlayerSpec; }
#include <memory>
#include "HybridOmniPlayerSpec.hpp"
#include <optional>
namespace margelo::nitro::omni {
@@ -44,6 +47,8 @@ namespace margelo::nitro::omni {
public:
// Properties
virtual std::shared_ptr<HybridOmniPlayerSpec> getPlayer() = 0;
virtual void setPlayer(const std::shared_ptr<HybridOmniPlayerSpec>& player) = 0;
virtual std::optional<bool> getAutoplay() = 0;
virtual void setAutoplay(std::optional<bool> autoplay) = 0;
virtual std::optional<bool> getShowNotification() = 0;
@@ -26,6 +26,16 @@ namespace margelo::nitro::omni::views {
const HybridOmniViewProps& sourceProps,
const react::RawProps& rawProps):
react::ViewProps(context, sourceProps, rawProps, filterObjectKeys),
player([&]() -> CachedProp<std::shared_ptr<HybridOmniPlayerSpec>> {
try {
const react::RawValue* rawValue = rawProps.at("player", nullptr, nullptr);
if (rawValue == nullptr) return sourceProps.player;
const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
return CachedProp<std::shared_ptr<HybridOmniPlayerSpec>>::fromRawValue(*runtime, value, sourceProps.player);
} catch (const std::exception& exc) {
throw std::runtime_error(std::string("OmniView.player: ") + exc.what());
}
}()),
autoplay([&]() -> CachedProp<std::optional<bool>> {
try {
const react::RawValue* rawValue = rawProps.at("autoplay", nullptr, nullptr);
@@ -69,6 +79,7 @@ namespace margelo::nitro::omni::views {
bool HybridOmniViewProps::filterObjectKeys(const std::string& propName) {
switch (hashString(propName)) {
case hashString("player"): return true;
case hashString("autoplay"): return true;
case hashString("showNotification"): return true;
case hashString("autoPip"): return true;
@@ -16,8 +16,9 @@
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
#include <react/renderer/components/view/ViewProps.h>
#include <optional>
#include <memory>
#include "HybridOmniPlayerSpec.hpp"
#include <optional>
#include "HybridOmniViewSpec.hpp"
#include <functional>
@@ -41,6 +42,7 @@ namespace margelo::nitro::omni::views {
const react::RawProps& rawProps);
public:
CachedProp<std::shared_ptr<HybridOmniPlayerSpec>> player;
CachedProp<std::optional<bool>> autoplay;
CachedProp<std::optional<bool>> showNotification;
CachedProp<std::optional<bool>> autoPip;
+1
View File
@@ -4,6 +4,7 @@
"bubblingEventTypes": {},
"directEventTypes": {},
"validAttributes": {
"player": true,
"autoplay": true,
"showNotification": true,
"autoPip": true,
+4 -1
View File
@@ -4,8 +4,11 @@ import type {
HybridViewProps,
} from "react-native-nitro-modules";
import type { OmniViewProps } from "../types/view";
import type { OmniPlayer } from "./omni-player.nitro";
export interface Props extends HybridViewProps, OmniViewProps {}
export interface Props extends HybridViewProps, OmniViewProps {
player: OmniPlayer;
}
export type OmniView = HybridView<
Props,
-10
View File
@@ -1,10 +0,0 @@
import { getHostComponent, type HybridRef, type HybridViewMethods } from "react-native-nitro-modules";
import OmniConfig from "../nitrogen/generated/shared/json/OmniViewConfig.json";
import type { Props } from "./specs/omni-view.nitro";
export const OmniView = getHostComponent<Props, HybridViewMethods>(
"OmniView",
() => OmniConfig,
);
export type OmnViewiRef = HybridRef<Props, HybridViewMethods>;
+19
View File
@@ -0,0 +1,19 @@
import {
getHostComponent,
type HybridViewMethods,
} from "react-native-nitro-modules";
import OmniConfig from "../nitrogen/generated/shared/json/OmniViewConfig.json";
import { usePlayer } from "./provider";
import type { OmniPlayer } from "./specs/omni-player.nitro";
import type { Props } from "./specs/omni-view.nitro";
import type { OmniViewProps } from "./types/view";
const NativeView = getHostComponent<Props, HybridViewMethods>(
"OmniView",
() => OmniConfig,
);
export const OmniView = (props: OmniViewProps) => {
const player = usePlayer() as OmniPlayer;
return <NativeView player={player} {...props} />;
};