diff --git a/android/src/main/java/dev/zoriya/omni/EventMap.kt b/android/src/main/java/dev/zoriya/omni/EventMap.kt index 22f6c03..d7e16ae 100644 --- a/android/src/main/java/dev/zoriya/omni/EventMap.kt +++ b/android/src/main/java/dev/zoriya/omni/EventMap.kt @@ -1,89 +1,259 @@ package dev.zoriya.omni +import com.margelo.nitro.omni.BoolProperty import com.margelo.nitro.omni.HybridOmniEventMapSpec +import com.margelo.nitro.omni.NumberProperty +import com.margelo.nitro.omni.PlayerStatus import com.margelo.nitro.omni.Rendition import com.margelo.nitro.omni.Track -import org.videolan.libvlc.MediaPlayer +import android.os.SystemClock +import dev.jdtech.mpv.MPVLib + +class EventMap(private val player: MPVLib) : HybridOmniEventMapSpec(), MPVLib.EventObserver { + private val onEndListeners = mutableSetOf<() -> Unit>() + private val onPrevListeners = mutableSetOf<() -> Unit>() + private val onNextListeners = mutableSetOf<() -> Unit>() + private val onErrorListeners = mutableSetOf<(type: String, message: String) -> Unit>() + private val onAudioFocusChangeListeners = mutableSetOf<(status: String) -> Unit>() + private val onVideoTrackChangeListeners = mutableSetOf<(track: Track) -> Unit>() + private val onAudioTrackChangeListeners = mutableSetOf<(track: Track) -> Unit>() + private val onSubtitleChangeListeners = mutableSetOf<(track: Track?) -> Unit>() + private val onRenditionChangeListeners = mutableSetOf<(rendition: Rendition) -> Unit>() + private val stateListeners = mutableMapOf Unit>>() + private val stateBoolListeners = mutableMapOf Unit>>() + private val playerStatusListeners = mutableSetOf<(PlayerStatus) -> Unit>() + private var isSeeking = false + private var eofReached = false + private var lastTimePosDispatchMs = 0L -class EventMap(val player: MediaPlayer) : HybridOmniEventMapSpec(), MediaPlayer.EventListener { init { - player.setEventListener(this) + player.addObserver(this) + player.observeProperty("vid", MPVLib.MpvFormat.MPV_FORMAT_INT64) + player.observeProperty("aid", MPVLib.MpvFormat.MPV_FORMAT_INT64) + player.observeProperty("sid", MPVLib.MpvFormat.MPV_FORMAT_INT64) + player.observeProperty("pause", MPVLib.MpvFormat.MPV_FORMAT_FLAG) + player.observeProperty("muted", MPVLib.MpvFormat.MPV_FORMAT_FLAG) + player.observeProperty("eof-reached", MPVLib.MpvFormat.MPV_FORMAT_FLAG) + player.observeProperty("core-idle", MPVLib.MpvFormat.MPV_FORMAT_FLAG) + player.observeProperty("paused-for-cache", MPVLib.MpvFormat.MPV_FORMAT_FLAG) + player.observeProperty("time-pos", MPVLib.MpvFormat.MPV_FORMAT_DOUBLE) + player.observeProperty("demuxer-cache-time", MPVLib.MpvFormat.MPV_FORMAT_DOUBLE) + player.observeProperty("duration", MPVLib.MpvFormat.MPV_FORMAT_DOUBLE) + player.observeProperty("speed", MPVLib.MpvFormat.MPV_FORMAT_DOUBLE) + player.observeProperty("volume", MPVLib.MpvFormat.MPV_FORMAT_DOUBLE) } - override fun onEvent(event: MediaPlayer.Event) { - when (event) { - + private fun computePlayerStatus(): PlayerStatus { + val idle = player.getPropertyBoolean("core-idle") ?: false + val loading = player.getPropertyBoolean("paused-for-cache") ?: false + return when { + idle -> PlayerStatus.IDLE + loading -> PlayerStatus.LOADING + else -> PlayerStatus.READYTOPLAY } } + private fun getTrackById(type: String, id: Long): Track? { + val count = player.getPropertyInt("track-list/count") ?: 0 + for (i in 0 until count) { + val base = "track-list/$i" + val trackType = player.getPropertyString("$base/type") ?: continue + if (trackType != type) continue + val trackId = player.getPropertyInt("$base/id") ?: continue + if (trackId.toLong() != id) continue + val selected = player.getPropertyBoolean("$base/selected") ?: false + val label = player.getPropertyString("$base/title") + ?: player.getPropertyString("$base/codec") + val language = player.getPropertyString("$base/lang") + return Track(id = trackId.toString(), label = label, language = language, selected = selected) + } + return null + } + + override fun event(event: Int) { + when (event) { + MPVLib.MpvEvent.MPV_EVENT_START_FILE -> + run { + eofReached = false + isSeeking = false + playerStatusListeners.forEach { it(PlayerStatus.LOADING) } + } + MPVLib.MpvEvent.MPV_EVENT_FILE_LOADED -> + playerStatusListeners.forEach { it(PlayerStatus.READYTOPLAY) } + MPVLib.MpvEvent.MPV_EVENT_SEEK -> isSeeking = true + MPVLib.MpvEvent.MPV_EVENT_PLAYBACK_RESTART -> isSeeking = false + MPVLib.MpvEvent.MPV_EVENT_END_FILE -> { + isSeeking = false + if (eofReached) { + onEndListeners.forEach { it() } + } else { + onErrorListeners.forEach { + it("end_file", "playback ended before reaching EOF") + } + } + playerStatusListeners.forEach { it(PlayerStatus.IDLE) } + } + MPVLib.MpvEvent.MPV_EVENT_QUEUE_OVERFLOW -> onErrorListeners.forEach { + it("queue_overflow", "mpv event queue overflow") + } + } + } + + override fun eventProperty(property: String) = Unit + + override fun eventProperty(property: String, value: Long) { + when (property) { + "vid" -> { + val track = getTrackById("video", value) + if (track != null) onVideoTrackChangeListeners.forEach { it(track) } + } + "aid" -> { + val track = getTrackById("audio", value) + if (track != null) onAudioTrackChangeListeners.forEach { it(track) } + } + "sid" -> { + val track = getTrackById("sub", value) + onSubtitleChangeListeners.forEach { it(track) } + } + } + } + + override fun eventProperty(property: String, value: Double) { + when (property) { + "time-pos" -> if (isSeeking || SystemClock.elapsedRealtime() - lastTimePosDispatchMs >= 1000L) { + lastTimePosDispatchMs = SystemClock.elapsedRealtime() + stateListeners[NumberProperty.CURRENTTIME]?.forEach { it(value.coerceAtLeast(0.0)) } + } + "demuxer-cache-time" -> stateListeners[NumberProperty.BUFFERED] + ?.forEach { it(value.coerceAtLeast(0.0)) } + "duration" -> stateListeners[NumberProperty.DURATION] + ?.forEach { it(value.coerceAtLeast(0.0)) } + "speed" -> stateListeners[NumberProperty.PLAYBACKRATE] + ?.forEach { it(value) } + "volume" -> stateListeners[NumberProperty.VOLUME] + ?.forEach { it((value / 100.0).coerceIn(0.0, 1.0)) } + } + } + + override fun eventProperty(property: String, value: Boolean) { + when (property) { + "pause" -> { + val isPlaying = !value + onAudioFocusChangeListeners.forEach { it(if (isPlaying) "playing" else "paused") } + stateBoolListeners[BoolProperty.ISPLAYING]?.forEach { it(isPlaying) } + } + "muted" -> + stateBoolListeners[BoolProperty.MUTED]?.forEach { it(value) } + "eof-reached" -> eofReached = value + "core-idle", "paused-for-cache" -> + playerStatusListeners.forEach { it(computePlayerStatus()) } + } + } + + override fun eventProperty(property: String, value: String) { + if (property == "sid" && value == "no") { + onSubtitleChangeListeners.forEach { it(null) } + } + } + + override fun addStateListener(key: NumberProperty, cb: (value: Double) -> Unit) { + stateListeners.getOrPut(key) { mutableSetOf() }.add(cb) + } + + override fun removeStateListener(key: NumberProperty, cb: (value: Double) -> Unit) { + stateListeners[key]?.remove(cb) + } + + override fun addStateBoolListener(key: BoolProperty, cb: (value: Boolean) -> Unit) { + stateBoolListeners.getOrPut(key) { mutableSetOf() }.add(cb) + } + + override fun removeStateBoolListener(key: BoolProperty, cb: (value: Boolean) -> Unit) { + stateBoolListeners[key]?.remove(cb) + } + + override fun addPlayerStatusListener(cb: (value: PlayerStatus) -> Unit) { + playerStatusListeners.add(cb) + } + + override fun removePlayerStatusListener(cb: (value: PlayerStatus) -> Unit) { + playerStatusListeners.remove(cb) + } + override fun addOnEndListener(cb: () -> Unit) { + onEndListeners.add(cb) } override fun removeOnEndListener(cb: () -> Unit) { - TODO("Not yet implemented") + onEndListeners.remove(cb) } override fun addOnPrevListener(cb: () -> Unit) { - TODO("Not yet implemented") + onPrevListeners.add(cb) } override fun removeOnPrevListener(cb: () -> Unit) { - TODO("Not yet implemented") + onPrevListeners.remove(cb) } override fun addOnNextListener(cb: () -> Unit) { - TODO("Not yet implemented") + onNextListeners.add(cb) } override fun removeOnNextListener(cb: () -> Unit) { - TODO("Not yet implemented") + onNextListeners.remove(cb) } override fun addOnErrorListener(cb: (type: String, message: String) -> Unit) { - TODO("Not yet implemented") + onErrorListeners.add(cb) } override fun removeOnErrorListener(cb: (type: String, message: String) -> Unit) { - TODO("Not yet implemented") + onErrorListeners.remove(cb) } override fun addOnAudioFocusChangeListener(cb: (status: String) -> Unit) { - TODO("Not yet implemented") + onAudioFocusChangeListeners.add(cb) } override fun removeOnAudioFocusChangeListener(cb: (status: String) -> Unit) { - TODO("Not yet implemented") + onAudioFocusChangeListeners.remove(cb) } override fun addOnVideoTrackChangeListener(cb: (track: Track) -> Unit) { - TODO("Not yet implemented") + onVideoTrackChangeListeners.add(cb) } override fun removeOnVideoTrackChangeListener(cb: (track: Track) -> Unit) { - TODO("Not yet implemented") + onVideoTrackChangeListeners.remove(cb) } override fun addOnAudioTrackChangeListener(cb: (track: Track) -> Unit) { - TODO("Not yet implemented") + onAudioTrackChangeListeners.add(cb) } override fun removeOnAudioTrackChangeListener(cb: (track: Track) -> Unit) { - TODO("Not yet implemented") + onAudioTrackChangeListeners.remove(cb) } override fun addOnSubtitleChangeListener(cb: (track: Track?) -> Unit) { - TODO("Not yet implemented") + onSubtitleChangeListeners.add(cb) } override fun removeOnSubtitleChangeListener(cb: (track: Track?) -> Unit) { - TODO("Not yet implemented") + onSubtitleChangeListeners.remove(cb) } override fun addOnRenditionChangeListener(cb: (rendition: Rendition) -> Unit) { - TODO("Not yet implemented") + onRenditionChangeListeners.add(cb) } override fun removeOnRenditionChangeListener(cb: (rendition: Rendition) -> Unit) { - TODO("Not yet implemented") + onRenditionChangeListeners.remove(cb) } -} \ No newline at end of file + + override fun dispose() { + player.removeObserver(this) + super.dispose() + } +} diff --git a/biome.json b/biome.json index d8a4a05..b40a853 100644 --- a/biome.json +++ b/biome.json @@ -19,6 +19,9 @@ "style": { "noNonNullAssertion": "off" }, + "suspicious": { + "noExplicitAny": "off" + }, "correctness": { "noUnusedVariables": "off", "noUnusedFunctionParameters": "off", diff --git a/nitrogen/generated/android/OmniOnLoad.cpp b/nitrogen/generated/android/OmniOnLoad.cpp index d747b34..21d3a7f 100644 --- a/nitrogen/generated/android/OmniOnLoad.cpp +++ b/nitrogen/generated/android/OmniOnLoad.cpp @@ -16,6 +16,9 @@ #include #include "JHybridOmniEventMapSpec.hpp" +#include "JFunc_void_double.hpp" +#include "JFunc_void_bool.hpp" +#include "JFunc_void_PlayerStatus.hpp" #include "JFunc_void.hpp" #include "JFunc_void_std__string_std__string.hpp" #include "JFunc_void_std__string.hpp" @@ -59,6 +62,9 @@ void registerAllNatives() { // Register native JNI methods margelo::nitro::omni::JHybridOmniEventMapSpec::CxxPart::registerNatives(); + margelo::nitro::omni::JFunc_void_double_cxx::registerNatives(); + margelo::nitro::omni::JFunc_void_bool_cxx::registerNatives(); + margelo::nitro::omni::JFunc_void_PlayerStatus_cxx::registerNatives(); margelo::nitro::omni::JFunc_void_cxx::registerNatives(); margelo::nitro::omni::JFunc_void_std__string_std__string_cxx::registerNatives(); margelo::nitro::omni::JFunc_void_std__string_cxx::registerNatives(); diff --git a/nitrogen/generated/android/c++/JBoolProperty.hpp b/nitrogen/generated/android/c++/JBoolProperty.hpp new file mode 100644 index 0000000..831c92a --- /dev/null +++ b/nitrogen/generated/android/c++/JBoolProperty.hpp @@ -0,0 +1,58 @@ +/// +/// JBoolProperty.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include "BoolProperty.hpp" + +namespace margelo::nitro::omni { + + using namespace facebook; + + /** + * The C++ JNI bridge between the C++ enum "BoolProperty" and the the Kotlin enum "BoolProperty". + */ + struct JBoolProperty final: public jni::JavaClass { + public: + static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/omni/BoolProperty;"; + + public: + /** + * Convert this Java/Kotlin-based enum to the C++ enum BoolProperty. + */ + [[maybe_unused]] + [[nodiscard]] + BoolProperty toCpp() const { + static const auto clazz = javaClassStatic(); + static const auto fieldOrdinal = clazz->getField("value"); + int ordinal = this->getFieldValue(fieldOrdinal); + return static_cast(ordinal); + } + + public: + /** + * Create a Java/Kotlin-based enum with the given C++ enum's value. + */ + [[maybe_unused]] + static jni::alias_ref fromCpp(BoolProperty value) { + static const auto clazz = javaClassStatic(); + switch (value) { + case BoolProperty::ISPLAYING: + static const auto fieldISPLAYING = clazz->getStaticField("ISPLAYING"); + return clazz->getStaticFieldValue(fieldISPLAYING); + case BoolProperty::MUTED: + static const auto fieldMUTED = clazz->getStaticField("MUTED"); + return clazz->getStaticFieldValue(fieldMUTED); + default: + std::string stringValue = std::to_string(static_cast(value)); + throw std::invalid_argument("Invalid enum value (" + stringValue + "!"); + } + } + }; + +} // namespace margelo::nitro::omni diff --git a/nitrogen/generated/android/c++/JFunc_void_PlayerStatus.hpp b/nitrogen/generated/android/c++/JFunc_void_PlayerStatus.hpp new file mode 100644 index 0000000..72c8ed4 --- /dev/null +++ b/nitrogen/generated/android/c++/JFunc_void_PlayerStatus.hpp @@ -0,0 +1,77 @@ +/// +/// JFunc_void_PlayerStatus.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include + +#include "PlayerStatus.hpp" +#include +#include +#include "JPlayerStatus.hpp" + +namespace margelo::nitro::omni { + + using namespace facebook; + + /** + * Represents the Java/Kotlin callback `(value: PlayerStatus) -> Unit`. + * This can be passed around between C++ and Java/Kotlin. + */ + struct JFunc_void_PlayerStatus: public jni::JavaClass { + public: + static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/omni/Func_void_PlayerStatus;"; + + public: + /** + * Invokes the function this `JFunc_void_PlayerStatus` instance holds through JNI. + */ + void invoke(PlayerStatus value) const { + static const auto method = javaClassStatic()->getMethod /* value */)>("invoke"); + method(self(), JPlayerStatus::fromCpp(value)); + } + }; + + /** + * An implementation of Func_void_PlayerStatus that is backed by a C++ implementation (using `std::function<...>`) + */ + class JFunc_void_PlayerStatus_cxx final: public jni::HybridClass { + public: + static jni::local_ref fromCpp(const std::function& func) { + return JFunc_void_PlayerStatus_cxx::newObjectCxxArgs(func); + } + + public: + /** + * Invokes the C++ `std::function<...>` this `JFunc_void_PlayerStatus_cxx` instance holds. + */ + void invoke_cxx(jni::alias_ref value) { + _func(value->toCpp()); + } + + public: + [[nodiscard]] + inline const std::function& getFunction() const { + return _func; + } + + public: + static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/omni/Func_void_PlayerStatus_cxx;"; + static void registerNatives() { + registerHybrid({makeNativeMethod("invoke_cxx", JFunc_void_PlayerStatus_cxx::invoke_cxx)}); + } + + private: + explicit JFunc_void_PlayerStatus_cxx(const std::function& func): _func(func) { } + + private: + friend HybridBase; + std::function _func; + }; + +} // namespace margelo::nitro::omni diff --git a/nitrogen/generated/android/c++/JFunc_void_bool.hpp b/nitrogen/generated/android/c++/JFunc_void_bool.hpp new file mode 100644 index 0000000..b5bfd07 --- /dev/null +++ b/nitrogen/generated/android/c++/JFunc_void_bool.hpp @@ -0,0 +1,75 @@ +/// +/// JFunc_void_bool.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include + +#include +#include + +namespace margelo::nitro::omni { + + using namespace facebook; + + /** + * Represents the Java/Kotlin callback `(value: Boolean) -> Unit`. + * This can be passed around between C++ and Java/Kotlin. + */ + struct JFunc_void_bool: public jni::JavaClass { + public: + static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/omni/Func_void_bool;"; + + public: + /** + * Invokes the function this `JFunc_void_bool` instance holds through JNI. + */ + void invoke(bool value) const { + static const auto method = javaClassStatic()->getMethod("invoke"); + method(self(), value); + } + }; + + /** + * An implementation of Func_void_bool that is backed by a C++ implementation (using `std::function<...>`) + */ + class JFunc_void_bool_cxx final: public jni::HybridClass { + public: + static jni::local_ref fromCpp(const std::function& func) { + return JFunc_void_bool_cxx::newObjectCxxArgs(func); + } + + public: + /** + * Invokes the C++ `std::function<...>` this `JFunc_void_bool_cxx` instance holds. + */ + void invoke_cxx(jboolean value) { + _func(static_cast(value)); + } + + public: + [[nodiscard]] + inline const std::function& getFunction() const { + return _func; + } + + public: + static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/omni/Func_void_bool_cxx;"; + static void registerNatives() { + registerHybrid({makeNativeMethod("invoke_cxx", JFunc_void_bool_cxx::invoke_cxx)}); + } + + private: + explicit JFunc_void_bool_cxx(const std::function& func): _func(func) { } + + private: + friend HybridBase; + std::function _func; + }; + +} // namespace margelo::nitro::omni diff --git a/nitrogen/generated/android/c++/JFunc_void_double.hpp b/nitrogen/generated/android/c++/JFunc_void_double.hpp new file mode 100644 index 0000000..9cb5397 --- /dev/null +++ b/nitrogen/generated/android/c++/JFunc_void_double.hpp @@ -0,0 +1,75 @@ +/// +/// JFunc_void_double.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include + +#include +#include + +namespace margelo::nitro::omni { + + using namespace facebook; + + /** + * Represents the Java/Kotlin callback `(value: Double) -> Unit`. + * This can be passed around between C++ and Java/Kotlin. + */ + struct JFunc_void_double: public jni::JavaClass { + public: + static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/omni/Func_void_double;"; + + public: + /** + * Invokes the function this `JFunc_void_double` instance holds through JNI. + */ + void invoke(double value) const { + static const auto method = javaClassStatic()->getMethod("invoke"); + method(self(), value); + } + }; + + /** + * An implementation of Func_void_double that is backed by a C++ implementation (using `std::function<...>`) + */ + class JFunc_void_double_cxx final: public jni::HybridClass { + public: + static jni::local_ref fromCpp(const std::function& func) { + return JFunc_void_double_cxx::newObjectCxxArgs(func); + } + + public: + /** + * Invokes the C++ `std::function<...>` this `JFunc_void_double_cxx` instance holds. + */ + void invoke_cxx(double value) { + _func(value); + } + + public: + [[nodiscard]] + inline const std::function& getFunction() const { + return _func; + } + + public: + static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/omni/Func_void_double_cxx;"; + static void registerNatives() { + registerHybrid({makeNativeMethod("invoke_cxx", JFunc_void_double_cxx::invoke_cxx)}); + } + + private: + explicit JFunc_void_double_cxx(const std::function& func): _func(func) { } + + private: + friend HybridBase; + std::function _func; + }; + +} // namespace margelo::nitro::omni diff --git a/nitrogen/generated/android/c++/JHybridOmniEventMapSpec.cpp b/nitrogen/generated/android/c++/JHybridOmniEventMapSpec.cpp index bae0a17..d4fddb5 100644 --- a/nitrogen/generated/android/c++/JHybridOmniEventMapSpec.cpp +++ b/nitrogen/generated/android/c++/JHybridOmniEventMapSpec.cpp @@ -7,14 +7,29 @@ #include "JHybridOmniEventMapSpec.hpp" +// Forward declaration of `NumberProperty` to properly resolve imports. +namespace margelo::nitro::omni { enum class NumberProperty; } +// Forward declaration of `BoolProperty` to properly resolve imports. +namespace margelo::nitro::omni { enum class BoolProperty; } +// Forward declaration of `PlayerStatus` to properly resolve imports. +namespace margelo::nitro::omni { enum class PlayerStatus; } // Forward declaration of `Track` to properly resolve imports. namespace margelo::nitro::omni { struct Track; } // Forward declaration of `Rendition` to properly resolve imports. namespace margelo::nitro::omni { struct Rendition; } +#include "NumberProperty.hpp" +#include "JNumberProperty.hpp" #include -#include "JFunc_void.hpp" +#include "JFunc_void_double.hpp" #include +#include "BoolProperty.hpp" +#include "JBoolProperty.hpp" +#include "JFunc_void_bool.hpp" +#include "PlayerStatus.hpp" +#include "JFunc_void_PlayerStatus.hpp" +#include "JPlayerStatus.hpp" +#include "JFunc_void.hpp" #include #include "JFunc_void_std__string_std__string.hpp" #include "JFunc_void_std__string.hpp" @@ -60,6 +75,30 @@ namespace margelo::nitro::omni { // Methods + void JHybridOmniEventMapSpec::addStateListener(NumberProperty key, const std::function& cb) { + static const auto method = _javaPart->javaClassStatic()->getMethod /* key */, jni::alias_ref /* cb */)>("addStateListener_cxx"); + method(_javaPart, JNumberProperty::fromCpp(key), JFunc_void_double_cxx::fromCpp(cb)); + } + void JHybridOmniEventMapSpec::removeStateListener(NumberProperty key, const std::function& cb) { + static const auto method = _javaPart->javaClassStatic()->getMethod /* key */, jni::alias_ref /* cb */)>("removeStateListener_cxx"); + method(_javaPart, JNumberProperty::fromCpp(key), JFunc_void_double_cxx::fromCpp(cb)); + } + void JHybridOmniEventMapSpec::addStateBoolListener(BoolProperty key, const std::function& cb) { + static const auto method = _javaPart->javaClassStatic()->getMethod /* key */, jni::alias_ref /* cb */)>("addStateBoolListener_cxx"); + method(_javaPart, JBoolProperty::fromCpp(key), JFunc_void_bool_cxx::fromCpp(cb)); + } + void JHybridOmniEventMapSpec::removeStateBoolListener(BoolProperty key, const std::function& cb) { + static const auto method = _javaPart->javaClassStatic()->getMethod /* key */, jni::alias_ref /* cb */)>("removeStateBoolListener_cxx"); + method(_javaPart, JBoolProperty::fromCpp(key), JFunc_void_bool_cxx::fromCpp(cb)); + } + void JHybridOmniEventMapSpec::addPlayerStatusListener(const std::function& cb) { + static const auto method = _javaPart->javaClassStatic()->getMethod /* cb */)>("addPlayerStatusListener_cxx"); + method(_javaPart, JFunc_void_PlayerStatus_cxx::fromCpp(cb)); + } + void JHybridOmniEventMapSpec::removePlayerStatusListener(const std::function& cb) { + static const auto method = _javaPart->javaClassStatic()->getMethod /* cb */)>("removePlayerStatusListener_cxx"); + method(_javaPart, JFunc_void_PlayerStatus_cxx::fromCpp(cb)); + } void JHybridOmniEventMapSpec::addOnEndListener(const std::function& cb) { static const auto method = _javaPart->javaClassStatic()->getMethod /* cb */)>("addOnEndListener_cxx"); method(_javaPart, JFunc_void_cxx::fromCpp(cb)); diff --git a/nitrogen/generated/android/c++/JHybridOmniEventMapSpec.hpp b/nitrogen/generated/android/c++/JHybridOmniEventMapSpec.hpp index c0679ca..a76ee6b 100644 --- a/nitrogen/generated/android/c++/JHybridOmniEventMapSpec.hpp +++ b/nitrogen/generated/android/c++/JHybridOmniEventMapSpec.hpp @@ -54,6 +54,12 @@ namespace margelo::nitro::omni { public: // Methods + void addStateListener(NumberProperty key, const std::function& cb) override; + void removeStateListener(NumberProperty key, const std::function& cb) override; + void addStateBoolListener(BoolProperty key, const std::function& cb) override; + void removeStateBoolListener(BoolProperty key, const std::function& cb) override; + void addPlayerStatusListener(const std::function& cb) override; + void removePlayerStatusListener(const std::function& cb) override; void addOnEndListener(const std::function& cb) override; void removeOnEndListener(const std::function& cb) override; void addOnPrevListener(const std::function& cb) override; diff --git a/nitrogen/generated/android/c++/JNumberProperty.hpp b/nitrogen/generated/android/c++/JNumberProperty.hpp new file mode 100644 index 0000000..62dc028 --- /dev/null +++ b/nitrogen/generated/android/c++/JNumberProperty.hpp @@ -0,0 +1,67 @@ +/// +/// JNumberProperty.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include "NumberProperty.hpp" + +namespace margelo::nitro::omni { + + using namespace facebook; + + /** + * The C++ JNI bridge between the C++ enum "NumberProperty" and the the Kotlin enum "NumberProperty". + */ + struct JNumberProperty final: public jni::JavaClass { + public: + static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/omni/NumberProperty;"; + + public: + /** + * Convert this Java/Kotlin-based enum to the C++ enum NumberProperty. + */ + [[maybe_unused]] + [[nodiscard]] + NumberProperty toCpp() const { + static const auto clazz = javaClassStatic(); + static const auto fieldOrdinal = clazz->getField("value"); + int ordinal = this->getFieldValue(fieldOrdinal); + return static_cast(ordinal); + } + + public: + /** + * Create a Java/Kotlin-based enum with the given C++ enum's value. + */ + [[maybe_unused]] + static jni::alias_ref fromCpp(NumberProperty value) { + static const auto clazz = javaClassStatic(); + switch (value) { + case NumberProperty::CURRENTTIME: + static const auto fieldCURRENTTIME = clazz->getStaticField("CURRENTTIME"); + return clazz->getStaticFieldValue(fieldCURRENTTIME); + case NumberProperty::BUFFERED: + static const auto fieldBUFFERED = clazz->getStaticField("BUFFERED"); + return clazz->getStaticFieldValue(fieldBUFFERED); + case NumberProperty::DURATION: + static const auto fieldDURATION = clazz->getStaticField("DURATION"); + return clazz->getStaticFieldValue(fieldDURATION); + case NumberProperty::PLAYBACKRATE: + static const auto fieldPLAYBACKRATE = clazz->getStaticField("PLAYBACKRATE"); + return clazz->getStaticFieldValue(fieldPLAYBACKRATE); + case NumberProperty::VOLUME: + static const auto fieldVOLUME = clazz->getStaticField("VOLUME"); + return clazz->getStaticFieldValue(fieldVOLUME); + default: + std::string stringValue = std::to_string(static_cast(value)); + throw std::invalid_argument("Invalid enum value (" + stringValue + "!"); + } + } + }; + +} // namespace margelo::nitro::omni diff --git a/nitrogen/generated/android/c++/JPlayerStatus.hpp b/nitrogen/generated/android/c++/JPlayerStatus.hpp index e2fe11a..e83fc25 100644 --- a/nitrogen/generated/android/c++/JPlayerStatus.hpp +++ b/nitrogen/generated/android/c++/JPlayerStatus.hpp @@ -42,9 +42,6 @@ namespace margelo::nitro::omni { static jni::alias_ref fromCpp(PlayerStatus value) { static const auto clazz = javaClassStatic(); switch (value) { - case PlayerStatus::ERROR: - static const auto fieldERROR = clazz->getStaticField("ERROR"); - return clazz->getStaticFieldValue(fieldERROR); case PlayerStatus::IDLE: static const auto fieldIDLE = clazz->getStaticField("IDLE"); return clazz->getStaticFieldValue(fieldIDLE); @@ -54,6 +51,9 @@ namespace margelo::nitro::omni { case PlayerStatus::READYTOPLAY: static const auto fieldREADYTOPLAY = clazz->getStaticField("READYTOPLAY"); return clazz->getStaticFieldValue(fieldREADYTOPLAY); + case PlayerStatus::ERROR: + static const auto fieldERROR = clazz->getStaticField("ERROR"); + return clazz->getStaticFieldValue(fieldERROR); default: std::string stringValue = std::to_string(static_cast(value)); throw std::invalid_argument("Invalid enum value (" + stringValue + "!"); diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/BoolProperty.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/BoolProperty.kt new file mode 100644 index 0000000..e4c3e62 --- /dev/null +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/BoolProperty.kt @@ -0,0 +1,23 @@ +/// +/// BoolProperty.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.omni + +import androidx.annotation.Keep +import com.facebook.proguard.annotations.DoNotStrip + +/** + * Represents the JavaScript enum/union "BoolProperty". + */ +@DoNotStrip +@Keep +enum class BoolProperty(@DoNotStrip @Keep val value: Int) { + ISPLAYING(0), + MUTED(1); + + companion object +} diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/Func_void_PlayerStatus.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/Func_void_PlayerStatus.kt new file mode 100644 index 0000000..7486fc1 --- /dev/null +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/Func_void_PlayerStatus.kt @@ -0,0 +1,80 @@ +/// +/// Func_void_PlayerStatus.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.omni + +import androidx.annotation.Keep +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import dalvik.annotation.optimization.FastNative + + +/** + * Represents the JavaScript callback `(value: enum) => void`. + * This can be either implemented in C++ (in which case it might be a callback coming from JS), + * or in Kotlin/Java (in which case it is a native callback). + */ +@DoNotStrip +@Keep +@Suppress("ClassName", "RedundantUnitReturnType") +fun interface Func_void_PlayerStatus: (PlayerStatus) -> Unit { + /** + * Call the given JS callback. + * @throws Throwable if the JS function itself throws an error, or if the JS function/runtime has already been deleted. + */ + @DoNotStrip + @Keep + override fun invoke(value: PlayerStatus): Unit +} + +/** + * Represents the JavaScript callback `(value: enum) => void`. + * This is implemented in C++, via a `std::function<...>`. + * The callback might be coming from JS. + */ +@DoNotStrip +@Keep +@Suppress( + "KotlinJniMissingFunction", "unused", + "RedundantSuppression", "RedundantUnitReturnType", "FunctionName", + "ConvertSecondaryConstructorToPrimary", "ClassName", "LocalVariableName", +) +class Func_void_PlayerStatus_cxx: Func_void_PlayerStatus { + @DoNotStrip + @Keep + private val mHybridData: HybridData + + @DoNotStrip + @Keep + private constructor(hybridData: HybridData) { + mHybridData = hybridData + } + + @DoNotStrip + @Keep + override fun invoke(value: PlayerStatus): Unit + = invoke_cxx(value) + + @FastNative + private external fun invoke_cxx(value: PlayerStatus): Unit +} + +/** + * Represents the JavaScript callback `(value: enum) => void`. + * This is implemented in Java/Kotlin, via a `(PlayerStatus) -> Unit`. + * The callback is always coming from native. + */ +@DoNotStrip +@Keep +@Suppress("ClassName", "RedundantUnitReturnType", "unused") +class Func_void_PlayerStatus_java(private val function: (PlayerStatus) -> Unit): Func_void_PlayerStatus { + @DoNotStrip + @Keep + override fun invoke(value: PlayerStatus): Unit { + return this.function(value) + } +} diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/Func_void_bool.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/Func_void_bool.kt new file mode 100644 index 0000000..2bd037e --- /dev/null +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/Func_void_bool.kt @@ -0,0 +1,80 @@ +/// +/// Func_void_bool.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.omni + +import androidx.annotation.Keep +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import dalvik.annotation.optimization.FastNative + + +/** + * Represents the JavaScript callback `(value: boolean) => void`. + * This can be either implemented in C++ (in which case it might be a callback coming from JS), + * or in Kotlin/Java (in which case it is a native callback). + */ +@DoNotStrip +@Keep +@Suppress("ClassName", "RedundantUnitReturnType") +fun interface Func_void_bool: (Boolean) -> Unit { + /** + * Call the given JS callback. + * @throws Throwable if the JS function itself throws an error, or if the JS function/runtime has already been deleted. + */ + @DoNotStrip + @Keep + override fun invoke(value: Boolean): Unit +} + +/** + * Represents the JavaScript callback `(value: boolean) => void`. + * This is implemented in C++, via a `std::function<...>`. + * The callback might be coming from JS. + */ +@DoNotStrip +@Keep +@Suppress( + "KotlinJniMissingFunction", "unused", + "RedundantSuppression", "RedundantUnitReturnType", "FunctionName", + "ConvertSecondaryConstructorToPrimary", "ClassName", "LocalVariableName", +) +class Func_void_bool_cxx: Func_void_bool { + @DoNotStrip + @Keep + private val mHybridData: HybridData + + @DoNotStrip + @Keep + private constructor(hybridData: HybridData) { + mHybridData = hybridData + } + + @DoNotStrip + @Keep + override fun invoke(value: Boolean): Unit + = invoke_cxx(value) + + @FastNative + private external fun invoke_cxx(value: Boolean): Unit +} + +/** + * Represents the JavaScript callback `(value: boolean) => void`. + * This is implemented in Java/Kotlin, via a `(Boolean) -> Unit`. + * The callback is always coming from native. + */ +@DoNotStrip +@Keep +@Suppress("ClassName", "RedundantUnitReturnType", "unused") +class Func_void_bool_java(private val function: (Boolean) -> Unit): Func_void_bool { + @DoNotStrip + @Keep + override fun invoke(value: Boolean): Unit { + return this.function(value) + } +} diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/Func_void_double.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/Func_void_double.kt new file mode 100644 index 0000000..7748337 --- /dev/null +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/Func_void_double.kt @@ -0,0 +1,80 @@ +/// +/// Func_void_double.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.omni + +import androidx.annotation.Keep +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import dalvik.annotation.optimization.FastNative + + +/** + * Represents the JavaScript callback `(value: number) => void`. + * This can be either implemented in C++ (in which case it might be a callback coming from JS), + * or in Kotlin/Java (in which case it is a native callback). + */ +@DoNotStrip +@Keep +@Suppress("ClassName", "RedundantUnitReturnType") +fun interface Func_void_double: (Double) -> Unit { + /** + * Call the given JS callback. + * @throws Throwable if the JS function itself throws an error, or if the JS function/runtime has already been deleted. + */ + @DoNotStrip + @Keep + override fun invoke(value: Double): Unit +} + +/** + * Represents the JavaScript callback `(value: number) => void`. + * This is implemented in C++, via a `std::function<...>`. + * The callback might be coming from JS. + */ +@DoNotStrip +@Keep +@Suppress( + "KotlinJniMissingFunction", "unused", + "RedundantSuppression", "RedundantUnitReturnType", "FunctionName", + "ConvertSecondaryConstructorToPrimary", "ClassName", "LocalVariableName", +) +class Func_void_double_cxx: Func_void_double { + @DoNotStrip + @Keep + private val mHybridData: HybridData + + @DoNotStrip + @Keep + private constructor(hybridData: HybridData) { + mHybridData = hybridData + } + + @DoNotStrip + @Keep + override fun invoke(value: Double): Unit + = invoke_cxx(value) + + @FastNative + private external fun invoke_cxx(value: Double): Unit +} + +/** + * Represents the JavaScript callback `(value: number) => void`. + * This is implemented in Java/Kotlin, via a `(Double) -> Unit`. + * The callback is always coming from native. + */ +@DoNotStrip +@Keep +@Suppress("ClassName", "RedundantUnitReturnType", "unused") +class Func_void_double_java(private val function: (Double) -> Unit): Func_void_double { + @DoNotStrip + @Keep + override fun invoke(value: Double): Unit { + return this.function(value) + } +} diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniEventMapSpec.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniEventMapSpec.kt index 33ad173..cd02b1a 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniEventMapSpec.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniEventMapSpec.kt @@ -28,6 +28,60 @@ abstract class HybridOmniEventMapSpec: HybridObject() { // Methods + abstract fun addStateListener(key: NumberProperty, cb: (value: Double) -> Unit): Unit + + @DoNotStrip + @Keep + private fun addStateListener_cxx(key: NumberProperty, cb: Func_void_double): Unit { + val __result = addStateListener(key, cb) + return __result + } + + abstract fun removeStateListener(key: NumberProperty, cb: (value: Double) -> Unit): Unit + + @DoNotStrip + @Keep + private fun removeStateListener_cxx(key: NumberProperty, cb: Func_void_double): Unit { + val __result = removeStateListener(key, cb) + return __result + } + + abstract fun addStateBoolListener(key: BoolProperty, cb: (value: Boolean) -> Unit): Unit + + @DoNotStrip + @Keep + private fun addStateBoolListener_cxx(key: BoolProperty, cb: Func_void_bool): Unit { + val __result = addStateBoolListener(key, cb) + return __result + } + + abstract fun removeStateBoolListener(key: BoolProperty, cb: (value: Boolean) -> Unit): Unit + + @DoNotStrip + @Keep + private fun removeStateBoolListener_cxx(key: BoolProperty, cb: Func_void_bool): Unit { + val __result = removeStateBoolListener(key, cb) + return __result + } + + abstract fun addPlayerStatusListener(cb: (value: PlayerStatus) -> Unit): Unit + + @DoNotStrip + @Keep + private fun addPlayerStatusListener_cxx(cb: Func_void_PlayerStatus): Unit { + val __result = addPlayerStatusListener(cb) + return __result + } + + abstract fun removePlayerStatusListener(cb: (value: PlayerStatus) -> Unit): Unit + + @DoNotStrip + @Keep + private fun removePlayerStatusListener_cxx(cb: Func_void_PlayerStatus): Unit { + val __result = removePlayerStatusListener(cb) + return __result + } + abstract fun addOnEndListener(cb: () -> Unit): Unit @DoNotStrip diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/NumberProperty.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/NumberProperty.kt new file mode 100644 index 0000000..5b771cc --- /dev/null +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/NumberProperty.kt @@ -0,0 +1,26 @@ +/// +/// NumberProperty.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.omni + +import androidx.annotation.Keep +import com.facebook.proguard.annotations.DoNotStrip + +/** + * Represents the JavaScript enum/union "NumberProperty". + */ +@DoNotStrip +@Keep +enum class NumberProperty(@DoNotStrip @Keep val value: Int) { + CURRENTTIME(0), + BUFFERED(1), + DURATION(2), + PLAYBACKRATE(3), + VOLUME(4); + + companion object +} diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/PlayerStatus.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/PlayerStatus.kt index c7207fe..3dbe080 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/PlayerStatus.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/PlayerStatus.kt @@ -16,10 +16,10 @@ import com.facebook.proguard.annotations.DoNotStrip @DoNotStrip @Keep enum class PlayerStatus(@DoNotStrip @Keep val value: Int) { - ERROR(0), - IDLE(1), - LOADING(2), - READYTOPLAY(3); + IDLE(0), + LOADING(1), + READYTOPLAY(2), + ERROR(3); companion object } diff --git a/nitrogen/generated/shared/c++/BoolProperty.hpp b/nitrogen/generated/shared/c++/BoolProperty.hpp new file mode 100644 index 0000000..83b2a23 --- /dev/null +++ b/nitrogen/generated/shared/c++/BoolProperty.hpp @@ -0,0 +1,76 @@ +/// +/// BoolProperty.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +namespace margelo::nitro::omni { + + /** + * An enum which can be represented as a JavaScript union (BoolProperty). + */ + enum class BoolProperty { + ISPLAYING SWIFT_NAME(isplaying) = 0, + MUTED SWIFT_NAME(muted) = 1, + } CLOSED_ENUM; + +} // namespace margelo::nitro::omni + +namespace margelo::nitro { + + // C++ BoolProperty <> JS BoolProperty (union) + template <> + struct JSIConverter final { + static inline margelo::nitro::omni::BoolProperty fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + std::string unionValue = JSIConverter::fromJSI(runtime, arg); + switch (hashString(unionValue.c_str(), unionValue.size())) { + case hashString("isPlaying"): return margelo::nitro::omni::BoolProperty::ISPLAYING; + case hashString("muted"): return margelo::nitro::omni::BoolProperty::MUTED; + default: [[unlikely]] + throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum BoolProperty - invalid value!"); + } + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, margelo::nitro::omni::BoolProperty arg) { + switch (arg) { + case margelo::nitro::omni::BoolProperty::ISPLAYING: return JSIConverter::toJSI(runtime, "isPlaying"); + case margelo::nitro::omni::BoolProperty::MUTED: return JSIConverter::toJSI(runtime, "muted"); + default: [[unlikely]] + throw std::invalid_argument("Cannot convert BoolProperty to JS - invalid value: " + + std::to_string(static_cast(arg)) + "!"); + } + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isString()) { + return false; + } + std::string unionValue = JSIConverter::fromJSI(runtime, value); + switch (hashString(unionValue.c_str(), unionValue.size())) { + case hashString("isPlaying"): + case hashString("muted"): + return true; + default: + return false; + } + } + }; + +} // namespace margelo::nitro diff --git a/nitrogen/generated/shared/c++/HybridOmniEventMapSpec.cpp b/nitrogen/generated/shared/c++/HybridOmniEventMapSpec.cpp index f41c5ec..55e5c2f 100644 --- a/nitrogen/generated/shared/c++/HybridOmniEventMapSpec.cpp +++ b/nitrogen/generated/shared/c++/HybridOmniEventMapSpec.cpp @@ -14,6 +14,12 @@ namespace margelo::nitro::omni { HybridObject::loadHybridMethods(); // load custom methods/properties registerHybrids(this, [](Prototype& prototype) { + prototype.registerHybridMethod("addStateListener", &HybridOmniEventMapSpec::addStateListener); + prototype.registerHybridMethod("removeStateListener", &HybridOmniEventMapSpec::removeStateListener); + prototype.registerHybridMethod("addStateBoolListener", &HybridOmniEventMapSpec::addStateBoolListener); + prototype.registerHybridMethod("removeStateBoolListener", &HybridOmniEventMapSpec::removeStateBoolListener); + prototype.registerHybridMethod("addPlayerStatusListener", &HybridOmniEventMapSpec::addPlayerStatusListener); + prototype.registerHybridMethod("removePlayerStatusListener", &HybridOmniEventMapSpec::removePlayerStatusListener); prototype.registerHybridMethod("addOnEndListener", &HybridOmniEventMapSpec::addOnEndListener); prototype.registerHybridMethod("removeOnEndListener", &HybridOmniEventMapSpec::removeOnEndListener); prototype.registerHybridMethod("addOnPrevListener", &HybridOmniEventMapSpec::addOnPrevListener); diff --git a/nitrogen/generated/shared/c++/HybridOmniEventMapSpec.hpp b/nitrogen/generated/shared/c++/HybridOmniEventMapSpec.hpp index e93665c..6a0e837 100644 --- a/nitrogen/generated/shared/c++/HybridOmniEventMapSpec.hpp +++ b/nitrogen/generated/shared/c++/HybridOmniEventMapSpec.hpp @@ -13,12 +13,21 @@ #error NitroModules cannot be found! Are you sure you installed NitroModules properly? #endif +// Forward declaration of `NumberProperty` to properly resolve imports. +namespace margelo::nitro::omni { enum class NumberProperty; } +// Forward declaration of `BoolProperty` to properly resolve imports. +namespace margelo::nitro::omni { enum class BoolProperty; } +// Forward declaration of `PlayerStatus` to properly resolve imports. +namespace margelo::nitro::omni { enum class PlayerStatus; } // Forward declaration of `Track` to properly resolve imports. namespace margelo::nitro::omni { struct Track; } // Forward declaration of `Rendition` to properly resolve imports. namespace margelo::nitro::omni { struct Rendition; } +#include "NumberProperty.hpp" #include +#include "BoolProperty.hpp" +#include "PlayerStatus.hpp" #include #include "Track.hpp" #include @@ -55,6 +64,12 @@ namespace margelo::nitro::omni { public: // Methods + virtual void addStateListener(NumberProperty key, const std::function& cb) = 0; + virtual void removeStateListener(NumberProperty key, const std::function& cb) = 0; + virtual void addStateBoolListener(BoolProperty key, const std::function& cb) = 0; + virtual void removeStateBoolListener(BoolProperty key, const std::function& cb) = 0; + virtual void addPlayerStatusListener(const std::function& cb) = 0; + virtual void removePlayerStatusListener(const std::function& cb) = 0; virtual void addOnEndListener(const std::function& cb) = 0; virtual void removeOnEndListener(const std::function& cb) = 0; virtual void addOnPrevListener(const std::function& cb) = 0; diff --git a/nitrogen/generated/shared/c++/NumberProperty.hpp b/nitrogen/generated/shared/c++/NumberProperty.hpp new file mode 100644 index 0000000..1544d49 --- /dev/null +++ b/nitrogen/generated/shared/c++/NumberProperty.hpp @@ -0,0 +1,88 @@ +/// +/// NumberProperty.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +namespace margelo::nitro::omni { + + /** + * An enum which can be represented as a JavaScript union (NumberProperty). + */ + enum class NumberProperty { + CURRENTTIME SWIFT_NAME(currenttime) = 0, + BUFFERED SWIFT_NAME(buffered) = 1, + DURATION SWIFT_NAME(duration) = 2, + PLAYBACKRATE SWIFT_NAME(playbackrate) = 3, + VOLUME SWIFT_NAME(volume) = 4, + } CLOSED_ENUM; + +} // namespace margelo::nitro::omni + +namespace margelo::nitro { + + // C++ NumberProperty <> JS NumberProperty (union) + template <> + struct JSIConverter final { + static inline margelo::nitro::omni::NumberProperty fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + std::string unionValue = JSIConverter::fromJSI(runtime, arg); + switch (hashString(unionValue.c_str(), unionValue.size())) { + case hashString("currentTime"): return margelo::nitro::omni::NumberProperty::CURRENTTIME; + case hashString("buffered"): return margelo::nitro::omni::NumberProperty::BUFFERED; + case hashString("duration"): return margelo::nitro::omni::NumberProperty::DURATION; + case hashString("playbackRate"): return margelo::nitro::omni::NumberProperty::PLAYBACKRATE; + case hashString("volume"): return margelo::nitro::omni::NumberProperty::VOLUME; + default: [[unlikely]] + throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum NumberProperty - invalid value!"); + } + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, margelo::nitro::omni::NumberProperty arg) { + switch (arg) { + case margelo::nitro::omni::NumberProperty::CURRENTTIME: return JSIConverter::toJSI(runtime, "currentTime"); + case margelo::nitro::omni::NumberProperty::BUFFERED: return JSIConverter::toJSI(runtime, "buffered"); + case margelo::nitro::omni::NumberProperty::DURATION: return JSIConverter::toJSI(runtime, "duration"); + case margelo::nitro::omni::NumberProperty::PLAYBACKRATE: return JSIConverter::toJSI(runtime, "playbackRate"); + case margelo::nitro::omni::NumberProperty::VOLUME: return JSIConverter::toJSI(runtime, "volume"); + default: [[unlikely]] + throw std::invalid_argument("Cannot convert NumberProperty to JS - invalid value: " + + std::to_string(static_cast(arg)) + "!"); + } + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isString()) { + return false; + } + std::string unionValue = JSIConverter::fromJSI(runtime, value); + switch (hashString(unionValue.c_str(), unionValue.size())) { + case hashString("currentTime"): + case hashString("buffered"): + case hashString("duration"): + case hashString("playbackRate"): + case hashString("volume"): + return true; + default: + return false; + } + } + }; + +} // namespace margelo::nitro diff --git a/nitrogen/generated/shared/c++/PlayerStatus.hpp b/nitrogen/generated/shared/c++/PlayerStatus.hpp index 11053eb..396ab05 100644 --- a/nitrogen/generated/shared/c++/PlayerStatus.hpp +++ b/nitrogen/generated/shared/c++/PlayerStatus.hpp @@ -29,10 +29,10 @@ namespace margelo::nitro::omni { * An enum which can be represented as a JavaScript union (PlayerStatus). */ enum class PlayerStatus { - ERROR SWIFT_NAME(error) = 0, - IDLE SWIFT_NAME(idle) = 1, - LOADING SWIFT_NAME(loading) = 2, - READYTOPLAY SWIFT_NAME(readytoplay) = 3, + IDLE SWIFT_NAME(idle) = 0, + LOADING SWIFT_NAME(loading) = 1, + READYTOPLAY SWIFT_NAME(readytoplay) = 2, + ERROR SWIFT_NAME(error) = 3, } CLOSED_ENUM; } // namespace margelo::nitro::omni @@ -45,20 +45,20 @@ namespace margelo::nitro { static inline margelo::nitro::omni::PlayerStatus fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { std::string unionValue = JSIConverter::fromJSI(runtime, arg); switch (hashString(unionValue.c_str(), unionValue.size())) { - case hashString("error"): return margelo::nitro::omni::PlayerStatus::ERROR; case hashString("idle"): return margelo::nitro::omni::PlayerStatus::IDLE; case hashString("loading"): return margelo::nitro::omni::PlayerStatus::LOADING; case hashString("readyToPlay"): return margelo::nitro::omni::PlayerStatus::READYTOPLAY; + case hashString("error"): return margelo::nitro::omni::PlayerStatus::ERROR; default: [[unlikely]] throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum PlayerStatus - invalid value!"); } } static inline jsi::Value toJSI(jsi::Runtime& runtime, margelo::nitro::omni::PlayerStatus arg) { switch (arg) { - case margelo::nitro::omni::PlayerStatus::ERROR: return JSIConverter::toJSI(runtime, "error"); case margelo::nitro::omni::PlayerStatus::IDLE: return JSIConverter::toJSI(runtime, "idle"); case margelo::nitro::omni::PlayerStatus::LOADING: return JSIConverter::toJSI(runtime, "loading"); case margelo::nitro::omni::PlayerStatus::READYTOPLAY: return JSIConverter::toJSI(runtime, "readyToPlay"); + case margelo::nitro::omni::PlayerStatus::ERROR: return JSIConverter::toJSI(runtime, "error"); default: [[unlikely]] throw std::invalid_argument("Cannot convert PlayerStatus to JS - invalid value: " + std::to_string(static_cast(arg)) + "!"); @@ -70,10 +70,10 @@ namespace margelo::nitro { } std::string unionValue = JSIConverter::fromJSI(runtime, value); switch (hashString(unionValue.c_str(), unionValue.size())) { - case hashString("error"): case hashString("idle"): case hashString("loading"): case hashString("readyToPlay"): + case hashString("error"): return true; default: return false; diff --git a/src/events.tsx b/src/events.tsx index ce47fe9..b26f4fa 100644 --- a/src/events.tsx +++ b/src/events.tsx @@ -24,8 +24,28 @@ export const useEvent = ( export const usePlayerState = ( key: Key, ): OmniPlayerState[Key] => { - const player = usePlayer(); - const [ret, setState] = useState(player[key]); - // TODO: find a way to listen to that. + const player = usePlayer() as OmniPlayer; + const [ret, setState] = useState(player[key]); + + useEffect(() => { + const em = player.eventMap; + switch (key) { + case "currentTime": + case "buffered": + case "duration": + case "playbackRate": + case "volume": + em.addStateListener(key, setState); + return () => em.removeStateListener(key, setState); + case "isPlaying": + case "muted": + em.addStateBoolListener(key, setState); + return () => em.removeStateBoolListener(key, setState); + case "status": + em.addPlayerStatusListener(setState); + return () => em.removePlayerStatusListener(setState); + } + }, [player, key]); + return ret; }; diff --git a/src/index.ts b/src/index.ts index 5ebc89d..7c95962 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,3 @@ +export { useEvent, usePlayerState } from "./events"; export { OmniProvider, usePlayer } from "./provider"; export { OmniView } from "./view"; diff --git a/src/specs/omni-player.nitro.ts b/src/specs/omni-player.nitro.ts index a9fdf31..1f29a64 100644 --- a/src/specs/omni-player.nitro.ts +++ b/src/specs/omni-player.nitro.ts @@ -1,17 +1,28 @@ import type { HybridObject } from "react-native-nitro-modules"; import type { OmniEvents } from "../types/events"; import type { - // OmniPlayerState, + OmniPlayerState, OmniPlayer as OmniPlayerT, + PlayerStatus, } from "../types/player"; import type { Source } from "../types/source"; +export type NumberProperty = Exclude< + keyof OmniPlayerState, + "status" | "isPlaying" | "muted" +>; +export type BoolProperty = "isPlaying" | "muted"; + export interface OmniEventMap extends HybridObject<{ android: "kotlin" }> { - // addStateListener( - // key: keyof OmniPlayerState, - // cb: (value: number) => void, - // ): void; - // removeStateListener(cb: OmniEvents["end"]): void; + addStateListener(key: NumberProperty, cb: (value: number) => void): void; + removeStateListener(key: NumberProperty, cb: (value: number) => void): void; + addStateBoolListener(key: BoolProperty, cb: (value: boolean) => void): void; + removeStateBoolListener( + key: BoolProperty, + cb: (value: boolean) => void, + ): void; + addPlayerStatusListener(cb: (value: PlayerStatus) => void): void; + removePlayerStatusListener(cb: (value: PlayerStatus) => void): void; addOnEndListener(cb: OmniEvents["end"]): void; removeOnEndListener(cb: OmniEvents["end"]): void;