diff --git a/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt b/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt index 0616c90..e493513 100644 --- a/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt +++ b/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt @@ -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) } diff --git a/android/src/main/java/dev/zoriya/omni/OmniView.kt b/android/src/main/java/dev/zoriya/omni/OmniView.kt index af00cc7..524c95e 100755 --- a/android/src/main/java/dev/zoriya/omni/OmniView.kt +++ b/android/src/main/java/dev/zoriya/omni/OmniView.kt @@ -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 + } } diff --git a/nitrogen/generated/android/c++/JHybridOmniViewSpec.cpp b/nitrogen/generated/android/c++/JHybridOmniViewSpec.cpp index 3e1cbfd..bc09553 100644 --- a/nitrogen/generated/android/c++/JHybridOmniViewSpec.cpp +++ b/nitrogen/generated/android/c++/JHybridOmniViewSpec.cpp @@ -7,8 +7,12 @@ #include "JHybridOmniViewSpec.hpp" +// Forward declaration of `HybridOmniPlayerSpec` to properly resolve imports. +namespace margelo::nitro::omni { class HybridOmniPlayerSpec; } - +#include +#include "HybridOmniPlayerSpec.hpp" +#include "JHybridOmniPlayerSpec.hpp" #include namespace margelo::nitro::omni { @@ -41,6 +45,15 @@ namespace margelo::nitro::omni { } // Properties + std::shared_ptr JHybridOmniViewSpec::getPlayer() { + static const auto method = _javaPart->javaClassStatic()->getMethod()>("getPlayer"); + auto __result = method(_javaPart); + return __result->getJHybridOmniPlayerSpec(); + } + void JHybridOmniViewSpec::setPlayer(const std::shared_ptr& player) { + static const auto method = _javaPart->javaClassStatic()->getMethod /* player */)>("setPlayer"); + method(_javaPart, std::dynamic_pointer_cast(player)->getJavaPart()); + } std::optional JHybridOmniViewSpec::getAutoplay() { static const auto method = _javaPart->javaClassStatic()->getMethod()>("getAutoplay"); auto __result = method(_javaPart); diff --git a/nitrogen/generated/android/c++/JHybridOmniViewSpec.hpp b/nitrogen/generated/android/c++/JHybridOmniViewSpec.hpp index 7b1f151..0d288f1 100644 --- a/nitrogen/generated/android/c++/JHybridOmniViewSpec.hpp +++ b/nitrogen/generated/android/c++/JHybridOmniViewSpec.hpp @@ -50,6 +50,8 @@ namespace margelo::nitro::omni { public: // Properties + std::shared_ptr getPlayer() override; + void setPlayer(const std::shared_ptr& player) override; std::optional getAutoplay() override; void setAutoplay(std::optional autoplay) override; std::optional getShowNotification() override; diff --git a/nitrogen/generated/android/c++/views/JHybridOmniViewStateUpdater.cpp b/nitrogen/generated/android/c++/views/JHybridOmniViewStateUpdater.cpp index 08e8e21..cdcde89 100644 --- a/nitrogen/generated/android/c++/views/JHybridOmniViewStateUpdater.cpp +++ b/nitrogen/generated/android/c++/views/JHybridOmniViewStateUpdater.cpp @@ -37,6 +37,10 @@ void JHybridOmniViewStateUpdater::updateViewProps(jni::alias_ref /* } // 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; diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniViewSpec.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniViewSpec.kt index b0534ff..b15fb07 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniViewSpec.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniViewSpec.kt @@ -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 diff --git a/nitrogen/generated/shared/c++/HybridOmniViewSpec.cpp b/nitrogen/generated/shared/c++/HybridOmniViewSpec.cpp index a03b6ab..2fef818 100644 --- a/nitrogen/generated/shared/c++/HybridOmniViewSpec.cpp +++ b/nitrogen/generated/shared/c++/HybridOmniViewSpec.cpp @@ -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); diff --git a/nitrogen/generated/shared/c++/HybridOmniViewSpec.hpp b/nitrogen/generated/shared/c++/HybridOmniViewSpec.hpp index 081921c..5139d4a 100644 --- a/nitrogen/generated/shared/c++/HybridOmniViewSpec.hpp +++ b/nitrogen/generated/shared/c++/HybridOmniViewSpec.hpp @@ -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 +#include "HybridOmniPlayerSpec.hpp" #include namespace margelo::nitro::omni { @@ -44,6 +47,8 @@ namespace margelo::nitro::omni { public: // Properties + virtual std::shared_ptr getPlayer() = 0; + virtual void setPlayer(const std::shared_ptr& player) = 0; virtual std::optional getAutoplay() = 0; virtual void setAutoplay(std::optional autoplay) = 0; virtual std::optional getShowNotification() = 0; diff --git a/nitrogen/generated/shared/c++/views/HybridOmniViewComponent.cpp b/nitrogen/generated/shared/c++/views/HybridOmniViewComponent.cpp index 0823a3a..80d55b1 100644 --- a/nitrogen/generated/shared/c++/views/HybridOmniViewComponent.cpp +++ b/nitrogen/generated/shared/c++/views/HybridOmniViewComponent.cpp @@ -26,6 +26,16 @@ namespace margelo::nitro::omni::views { const HybridOmniViewProps& sourceProps, const react::RawProps& rawProps): react::ViewProps(context, sourceProps, rawProps, filterObjectKeys), + player([&]() -> CachedProp> { + try { + const react::RawValue* rawValue = rawProps.at("player", nullptr, nullptr); + if (rawValue == nullptr) return sourceProps.player; + const auto& [runtime, value] = (std::pair)*rawValue; + return CachedProp>::fromRawValue(*runtime, value, sourceProps.player); + } catch (const std::exception& exc) { + throw std::runtime_error(std::string("OmniView.player: ") + exc.what()); + } + }()), autoplay([&]() -> CachedProp> { 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; diff --git a/nitrogen/generated/shared/c++/views/HybridOmniViewComponent.hpp b/nitrogen/generated/shared/c++/views/HybridOmniViewComponent.hpp index 7980c36..3e9c2dc 100644 --- a/nitrogen/generated/shared/c++/views/HybridOmniViewComponent.hpp +++ b/nitrogen/generated/shared/c++/views/HybridOmniViewComponent.hpp @@ -16,8 +16,9 @@ #include #include -#include #include +#include "HybridOmniPlayerSpec.hpp" +#include #include "HybridOmniViewSpec.hpp" #include @@ -41,6 +42,7 @@ namespace margelo::nitro::omni::views { const react::RawProps& rawProps); public: + CachedProp> player; CachedProp> autoplay; CachedProp> showNotification; CachedProp> autoPip; diff --git a/nitrogen/generated/shared/json/OmniViewConfig.json b/nitrogen/generated/shared/json/OmniViewConfig.json index f5d4e3b..30d7d1b 100644 --- a/nitrogen/generated/shared/json/OmniViewConfig.json +++ b/nitrogen/generated/shared/json/OmniViewConfig.json @@ -4,6 +4,7 @@ "bubblingEventTypes": {}, "directEventTypes": {}, "validAttributes": { + "player": true, "autoplay": true, "showNotification": true, "autoPip": true, diff --git a/src/specs/omni-view.nitro.ts b/src/specs/omni-view.nitro.ts index 1d6b3d6..b0700d6 100644 --- a/src/specs/omni-view.nitro.ts +++ b/src/specs/omni-view.nitro.ts @@ -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, diff --git a/src/view.ts b/src/view.ts deleted file mode 100644 index ded1b2c..0000000 --- a/src/view.ts +++ /dev/null @@ -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( - "OmniView", - () => OmniConfig, -); - -export type OmnViewiRef = HybridRef; diff --git a/src/view.tsx b/src/view.tsx new file mode 100644 index 0000000..8ea8519 --- /dev/null +++ b/src/view.tsx @@ -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( + "OmniView", + () => OmniConfig, +); + +export const OmniView = (props: OmniViewProps) => { + const player = usePlayer() as OmniPlayer; + return ; +};