diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 711738f..871a098 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ + diff --git a/android/src/main/java/dev/zoriya/omni/OmniPlaybackService.kt b/android/src/main/java/dev/zoriya/omni/OmniPlaybackService.kt deleted file mode 100644 index 42644d5..0000000 --- a/android/src/main/java/dev/zoriya/omni/OmniPlaybackService.kt +++ /dev/null @@ -1,86 +0,0 @@ -package dev.zoriya.omni - -import android.annotation.SuppressLint -import android.content.Intent -import androidx.core.content.ContextCompat -import androidx.media3.common.Player -import androidx.media3.session.DefaultMediaNotificationProvider -import androidx.media3.session.MediaSession -import androidx.media3.session.MediaSessionService -import com.margelo.nitro.NitroModules -import java.util.concurrent.atomic.AtomicReference - -@SuppressLint("UnsafeOptInUsageError") -class OmniPlaybackService : MediaSessionService() { - private var mediaSession: MediaSession? = null - - override fun onCreate() { - super.onCreate() - serviceRef.set(this) - setMediaNotificationProvider( - DefaultMediaNotificationProvider.Builder(this) - .setChannelId(NOTIFICATION_CHANNEL_ID) - .build() - ) - attachedPlayer.get()?.let { ensureSession(it) } - } - - override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? { - attachedPlayer.get()?.let { ensureSession(it) } - return mediaSession - } - - override fun onTaskRemoved(rootIntent: Intent?) { - if (!isPlaybackOngoing) { - pauseAllPlayersAndStopSelf() - } - } - - override fun onDestroy() { - mediaSession?.release() - mediaSession = null - serviceRef.compareAndSet(this, null) - super.onDestroy() - } - - private fun ensureSession(player: Player) { - if (mediaSession?.player === player) return - mediaSession?.release() - mediaSession = MediaSession.Builder(this, player) - .setId(SESSION_ID) - .build() - } - - private fun clearSessionIf(player: Player) { - if (mediaSession?.player !== player) return - mediaSession?.release() - mediaSession = null - stopSelf() - } - - companion object { - private const val SESSION_ID = "omni-session" - private const val NOTIFICATION_CHANNEL_ID = "omni_playback" - private val attachedPlayer = AtomicReference(null) - private val serviceRef = AtomicReference(null) - - fun attachPlayer(player: Player) { - attachedPlayer.set(player) - serviceRef.get()?.ensureSession(player) - } - - fun detachPlayer(player: Player) { - if (!attachedPlayer.compareAndSet(player, null)) return - serviceRef.get()?.clearSessionIf(player) - } - - fun ensureStarted(player: Player) { - val context = NitroModules.Companion.applicationContext ?: return - attachPlayer(player) - ContextCompat.startForegroundService( - context, - Intent(context, OmniPlaybackService::class.java) - ) - } - } -} \ No newline at end of file diff --git a/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt b/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt index 2e0f3f2..614530b 100644 --- a/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt +++ b/android/src/main/java/dev/zoriya/omni/OmniPlayer.kt @@ -1,10 +1,14 @@ package dev.zoriya.omni import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.util.Log import android.view.SurfaceHolder import androidx.media3.common.C import androidx.media3.common.MediaItem import androidx.media3.common.MediaMetadata +import androidx.media3.common.Player import com.margelo.nitro.NitroModules import com.margelo.nitro.omni.HybridOmniPlayerSpec import com.margelo.nitro.omni.PlayerStatus @@ -12,7 +16,12 @@ import com.margelo.nitro.omni.Rendition import com.margelo.nitro.omni.Source import com.margelo.nitro.omni.Track import androidx.core.net.toUri +import androidx.media3.common.MediaItem.RequestMetadata +import androidx.media3.common.MediaItem.SubtitleConfiguration import androidx.media3.common.TrackSelectionOverride +import androidx.media3.session.DefaultMediaNotificationProvider +import androidx.media3.session.MediaSession +import androidx.media3.session.MediaSessionService @SuppressLint("UnsafeOptInUsageError") class OmniPlayer : HybridOmniPlayerSpec() { @@ -20,15 +29,26 @@ class OmniPlayer : HybridOmniPlayerSpec() { val player = MpvPlayer(ctx) override val eventMap = EventMap(player) - init { - OmniPlaybackService.attachPlayer(player) - } + override var showNotification: Boolean? = false + set(value) { + Log.e("omni", "Toggle show notif, old: ${field}, new: ${value}") + if (value == true) { + if (notificationPlayer != null) { + throw Error("Two players can't display notifications at the same time.") + } + notificationPlayer = player + ctx.startForegroundService(Intent(ctx, OmniPlayerService::class.java)) + } else if (field == true) { + ctx.stopService(Intent(ctx, OmniPlayerService::class.java)) + } + field = value + } override fun dispose() { + showNotification = false super.dispose() eventMap.dispose() - OmniPlaybackService.detachPlayer(player) player.release() } @@ -38,7 +58,50 @@ class OmniPlayer : HybridOmniPlayerSpec() { ?: throw IllegalStateException("source should be initialized before get") set(value) { currentSource = value - player.setMediaItem(buildMediaItem(value)) + val src = source.src.firstOrNull() ?: return player.setMediaItem(MediaItem.EMPTY) + // val headers = Bundle().apply { + // putStringArrayList( + // MpvPlayer.REQUEST_HEADER_NAMES_KEY, + // ArrayList(src.headers.keys) + // ) + // putStringArrayList( + // MpvPlayer.REQUEST_HEADER_VALUES_KEY, + // ArrayList(src.headers.values) + // ) + // source.startTime?.let { + // putLong(MpvPlayer.REQUEST_START_MS_KEY, (it.coerceAtLeast(0.0) * 1000.0).toLong()) + // } + // } + player.setMediaItem( + MediaItem.Builder() + .setUri(src.uri) + .setMimeType(src.mimeType) + .setMediaId(src.uri) + .setMediaMetadata( + MediaMetadata.Builder() + .setTitle(value.metadata?.title) + .setAlbumTitle(value.metadata?.album) + .setArtist(value.metadata?.artist) + .apply { + value.metadata?.imageLink?.let { setArtworkUri(it.toUri()) } + } + .build()) + .setSubtitleConfigurations(value.subtitles.map { subtitle -> + SubtitleConfiguration.Builder(subtitle.link.toUri()) + .setId(subtitle.id) + .setLanguage(subtitle.language) + .setLabel(subtitle.label) + .setMimeType(subtitle.mimeType) + .build() + }) + .setRequestMetadata( + RequestMetadata.Builder() + .setMediaUri(src.uri.toUri()) + // .setExtras(headers) + .build() + ) + .build() + ) } fun setSurface(holder: SurfaceHolder?) { @@ -53,10 +116,9 @@ class OmniPlayer : HybridOmniPlayerSpec() { override val hasNext get() = player.hasNextMediaItem() override val status: PlayerStatus get() = when (player.playbackState) { - androidx.media3.common.Player.STATE_IDLE, - androidx.media3.common.Player.STATE_ENDED -> PlayerStatus.IDLE - - androidx.media3.common.Player.STATE_BUFFERING -> PlayerStatus.LOADING + Player.STATE_IDLE, + Player.STATE_ENDED -> PlayerStatus.IDLE + Player.STATE_BUFFERING -> PlayerStatus.LOADING else -> PlayerStatus.READYTOPLAY } @@ -104,7 +166,6 @@ class OmniPlayer : HybridOmniPlayerSpec() { override val rendition: Array get() = emptyArray() override fun play() { - OmniPlaybackService.ensureStarted(player) player.play() } @@ -147,57 +208,6 @@ class OmniPlayer : HybridOmniPlayerSpec() { override fun selectRendition(rendition: Rendition?) { } - private fun buildMediaItem(source: Source): MediaItem { - val src = source.src.firstOrNull() ?: return MediaItem.EMPTY - - val mediaMetadata = MediaMetadata.Builder() - .setTitle(source.metadata?.title) - .setAlbumTitle(source.metadata?.album) - .setArtist(source.metadata?.artist) - .apply { - source.metadata?.imageLink?.let { setArtworkUri(it.toUri()) } - } - .build() - - val subtitleConfigurations = source.subtitles.map { subtitle -> - MediaItem.SubtitleConfiguration.Builder(subtitle.link.toUri()) - .setId(subtitle.id) - .setLanguage(subtitle.language) - .setLabel(subtitle.label) - .setMimeType(subtitle.mimeType) - .build() - } - -// val headers = Bundle().apply { -// putStringArrayList( -// MpvPlayer.REQUEST_HEADER_NAMES_KEY, -// ArrayList(src.headers.keys) -// ) -// putStringArrayList( -// MpvPlayer.REQUEST_HEADER_VALUES_KEY, -// ArrayList(src.headers.values) -// ) -// source.startTime?.let { -// putLong(MpvPlayer.REQUEST_START_MS_KEY, (it.coerceAtLeast(0.0) * 1000.0).toLong()) -// } -// } - - val requestMetadata = MediaItem.RequestMetadata.Builder() - .setMediaUri(src.uri.toUri()) -// .setExtras(headers) - .build() - - val itemBuilder = MediaItem.Builder() - .setUri(src.uri) - .setMimeType(src.mimeType) - .setMediaId(src.uri) - .setMediaMetadata(mediaMetadata) - .setSubtitleConfigurations(subtitleConfigurations) - .setRequestMetadata(requestMetadata) - - return itemBuilder.build() - } - private fun tracksByType(trackType: Int): Array { val groups = player.currentTracks.groups.filter { it.type == trackType } if (groups.isEmpty()) return emptyArray() @@ -237,4 +247,43 @@ class OmniPlayer : HybridOmniPlayerSpec() { } } + companion object { + var notificationPlayer: Player? = null + } +} + +@SuppressLint("UnsafeOptInUsageError") +class OmniPlayerService : MediaSessionService() { + private val ctx = NitroModules.applicationContext ?: throw Error("No Context available!") + private val player = OmniPlayer.notificationPlayer ?: throw Error("No player available") + var mediaSession: MediaSession = MediaSession.Builder(ctx, player).build() + + init { + Log.e("omni", "service inited") + } + + override fun onCreate() { + Log.e("omni", "service created") + super.onCreate() + setMediaNotificationProvider( + DefaultMediaNotificationProvider.Builder(ctx).build() + ) + } + + override fun onGetSession(controllerInfo: MediaSession.ControllerInfo) = mediaSession + + override fun onTaskRemoved(rootIntent: Intent?) { + if (!isPlaybackOngoing) { + pauseAllPlayersAndStopSelf() + } + } + + override fun onDestroy() { + mediaSession.release() + super.onDestroy() + } + + override fun getApplicationContext(): Context? { + return NitroModules.applicationContext + } } diff --git a/android/src/main/java/dev/zoriya/omni/OmniPlayerFactory.kt b/android/src/main/java/dev/zoriya/omni/OmniPlayerFactory.kt index 3efadf1..6df66b8 100755 --- a/android/src/main/java/dev/zoriya/omni/OmniPlayerFactory.kt +++ b/android/src/main/java/dev/zoriya/omni/OmniPlayerFactory.kt @@ -1,5 +1,6 @@ package dev.zoriya.omni +import android.util.Log import com.facebook.react.uimanager.ThemedReactContext import com.margelo.nitro.omni.HybridOmniPlayerFactorySpec import com.margelo.nitro.omni.HybridOmniPlayerSpec diff --git a/android/src/main/java/dev/zoriya/omni/OmniView.kt b/android/src/main/java/dev/zoriya/omni/OmniView.kt index 77ac5fe..cd3e948 100755 --- a/android/src/main/java/dev/zoriya/omni/OmniView.kt +++ b/android/src/main/java/dev/zoriya/omni/OmniView.kt @@ -3,7 +3,6 @@ package dev.zoriya.omni import android.util.Log import android.view.SurfaceHolder import android.view.SurfaceView -import android.view.View import android.widget.FrameLayout import com.facebook.react.uimanager.ThemedReactContext import com.margelo.nitro.omni.HybridOmniPlayerSpec @@ -25,7 +24,6 @@ class OmniView(val context: ThemedReactContext) : HybridOmniViewSpec(), SurfaceH override lateinit var player: HybridOmniPlayerSpec override var autoplay: Boolean? = true - override var showNotification: Boolean? = true override var autoPip: Boolean? = true override fun afterUpdate() { @@ -62,7 +60,6 @@ class OmniView(val context: ThemedReactContext) : HybridOmniViewSpec(), SurfaceH } override fun onDropView() { - Log.e("omniView", "omni-view dropped") if (!::player.isInitialized) return val omniPlayer = player as? OmniPlayer ?: return @@ -72,7 +69,6 @@ class OmniView(val context: ThemedReactContext) : HybridOmniViewSpec(), SurfaceH override fun surfaceCreated(holder: SurfaceHolder) { surfaceReady = true - Log.e("omniView", "surface created") boundPlayer?.setSurface(holder) } @@ -81,12 +77,9 @@ class OmniView(val context: ThemedReactContext) : HybridOmniViewSpec(), SurfaceH format: Int, width: Int, height: Int - ) { - // Surface size is resolved from SurfaceHolder in MpvPlayer. - } + ) { } override fun surfaceDestroyed(holder: SurfaceHolder) { - Log.e("omniView", "surface destroyed") surfaceReady = false boundPlayer?.setSurface(null) } diff --git a/example/App.tsx b/example/App.tsx index fe958b4..1b1cdec 100644 --- a/example/App.tsx +++ b/example/App.tsx @@ -48,6 +48,7 @@ function PlayerExample({ const currentTime = usePlayerState("currentTime"); const duration = usePlayerState("duration"); const playbackRate = usePlayerState("playbackRate"); + const muted = usePlayerState("muted"); const volume = usePlayerState("volume"); const [logs, setLogs] = useState([]); @@ -450,7 +451,7 @@ function App(): React.JSX.Element { ); return ( - + javaClassStatic()->getMethod /* source */)>("setSource"); method(_javaPart, JSource::fromCpp(source)); } + std::optional JHybridOmniPlayerSpec::getShowNotification() { + static const auto method = _javaPart->javaClassStatic()->getMethod()>("getShowNotification"); + auto __result = method(_javaPart); + return __result != nullptr ? std::make_optional(static_cast(__result->value())) : std::nullopt; + } + void JHybridOmniPlayerSpec::setShowNotification(std::optional showNotification) { + static const auto method = _javaPart->javaClassStatic()->getMethod /* showNotification */)>("setShowNotification"); + method(_javaPart, showNotification.has_value() ? jni::JBoolean::valueOf(showNotification.value()) : nullptr); + } bool JHybridOmniPlayerSpec::getHasPrev() { static const auto method = _javaPart->javaClassStatic()->getMethod("getHasPrev"); auto __result = method(_javaPart); diff --git a/nitrogen/generated/android/c++/JHybridOmniPlayerSpec.hpp b/nitrogen/generated/android/c++/JHybridOmniPlayerSpec.hpp index bd7b119..b089565 100644 --- a/nitrogen/generated/android/c++/JHybridOmniPlayerSpec.hpp +++ b/nitrogen/generated/android/c++/JHybridOmniPlayerSpec.hpp @@ -53,6 +53,8 @@ namespace margelo::nitro::omni { std::shared_ptr getEventMap() override; Source getSource() override; void setSource(const Source& source) override; + std::optional getShowNotification() override; + void setShowNotification(std::optional showNotification) override; bool getHasPrev() override; bool getHasNext() override; std::vector getVideos() override; diff --git a/nitrogen/generated/android/c++/JHybridOmniViewSpec.cpp b/nitrogen/generated/android/c++/JHybridOmniViewSpec.cpp index bc09553..f316f25 100644 --- a/nitrogen/generated/android/c++/JHybridOmniViewSpec.cpp +++ b/nitrogen/generated/android/c++/JHybridOmniViewSpec.cpp @@ -63,15 +63,6 @@ namespace margelo::nitro::omni { static const auto method = _javaPart->javaClassStatic()->getMethod /* autoplay */)>("setAutoplay"); method(_javaPart, autoplay.has_value() ? jni::JBoolean::valueOf(autoplay.value()) : nullptr); } - std::optional JHybridOmniViewSpec::getShowNotification() { - static const auto method = _javaPart->javaClassStatic()->getMethod()>("getShowNotification"); - auto __result = method(_javaPart); - return __result != nullptr ? std::make_optional(static_cast(__result->value())) : std::nullopt; - } - void JHybridOmniViewSpec::setShowNotification(std::optional showNotification) { - static const auto method = _javaPart->javaClassStatic()->getMethod /* showNotification */)>("setShowNotification"); - method(_javaPart, showNotification.has_value() ? jni::JBoolean::valueOf(showNotification.value()) : nullptr); - } std::optional JHybridOmniViewSpec::getAutoPip() { static const auto method = _javaPart->javaClassStatic()->getMethod()>("getAutoPip"); auto __result = method(_javaPart); diff --git a/nitrogen/generated/android/c++/JHybridOmniViewSpec.hpp b/nitrogen/generated/android/c++/JHybridOmniViewSpec.hpp index 0d288f1..c6ea10e 100644 --- a/nitrogen/generated/android/c++/JHybridOmniViewSpec.hpp +++ b/nitrogen/generated/android/c++/JHybridOmniViewSpec.hpp @@ -54,8 +54,6 @@ namespace margelo::nitro::omni { void setPlayer(const std::shared_ptr& player) override; std::optional getAutoplay() override; void setAutoplay(std::optional autoplay) override; - std::optional getShowNotification() override; - void setShowNotification(std::optional showNotification) override; std::optional getAutoPip() override; void setAutoPip(std::optional autoPip) override; diff --git a/nitrogen/generated/android/c++/views/JHybridOmniViewStateUpdater.cpp b/nitrogen/generated/android/c++/views/JHybridOmniViewStateUpdater.cpp index cdcde89..b2d39b6 100644 --- a/nitrogen/generated/android/c++/views/JHybridOmniViewStateUpdater.cpp +++ b/nitrogen/generated/android/c++/views/JHybridOmniViewStateUpdater.cpp @@ -45,10 +45,6 @@ void JHybridOmniViewStateUpdater::updateViewProps(jni::alias_ref /* hybridView->setAutoplay(props->autoplay.value); props->autoplay.isDirty = false; } - if (props->showNotification.isDirty) { - hybridView->setShowNotification(props->showNotification.value); - props->showNotification.isDirty = false; - } if (props->autoPip.isDirty) { hybridView->setAutoPip(props->autoPip.value); props->autoPip.isDirty = false; diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniPlayerSpec.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniPlayerSpec.kt index 0e210c4..9120e9c 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniPlayerSpec.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniPlayerSpec.kt @@ -35,6 +35,12 @@ abstract class HybridOmniPlayerSpec: HybridObject() { @set:Keep abstract var source: Source + @get:DoNotStrip + @get:Keep + @set:DoNotStrip + @set:Keep + abstract var showNotification: Boolean? + @get:DoNotStrip @get:Keep abstract val hasPrev: Boolean 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 b15fb07..190485c 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniViewSpec.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/omni/HybridOmniViewSpec.kt @@ -38,12 +38,6 @@ abstract class HybridOmniViewSpec: HybridView() { @set:Keep abstract var autoplay: Boolean? - @get:DoNotStrip - @get:Keep - @set:DoNotStrip - @set:Keep - abstract var showNotification: Boolean? - @get:DoNotStrip @get:Keep @set:DoNotStrip diff --git a/nitrogen/generated/shared/c++/HybridOmniPlayerSpec.cpp b/nitrogen/generated/shared/c++/HybridOmniPlayerSpec.cpp index 20bab6a..52877ca 100644 --- a/nitrogen/generated/shared/c++/HybridOmniPlayerSpec.cpp +++ b/nitrogen/generated/shared/c++/HybridOmniPlayerSpec.cpp @@ -17,6 +17,8 @@ namespace margelo::nitro::omni { prototype.registerHybridGetter("eventMap", &HybridOmniPlayerSpec::getEventMap); prototype.registerHybridGetter("source", &HybridOmniPlayerSpec::getSource); prototype.registerHybridSetter("source", &HybridOmniPlayerSpec::setSource); + prototype.registerHybridGetter("showNotification", &HybridOmniPlayerSpec::getShowNotification); + prototype.registerHybridSetter("showNotification", &HybridOmniPlayerSpec::setShowNotification); prototype.registerHybridGetter("hasPrev", &HybridOmniPlayerSpec::getHasPrev); prototype.registerHybridGetter("hasNext", &HybridOmniPlayerSpec::getHasNext); prototype.registerHybridGetter("videos", &HybridOmniPlayerSpec::getVideos); diff --git a/nitrogen/generated/shared/c++/HybridOmniPlayerSpec.hpp b/nitrogen/generated/shared/c++/HybridOmniPlayerSpec.hpp index e17a84b..4204561 100644 --- a/nitrogen/generated/shared/c++/HybridOmniPlayerSpec.hpp +++ b/nitrogen/generated/shared/c++/HybridOmniPlayerSpec.hpp @@ -27,11 +27,11 @@ namespace margelo::nitro::omni { enum class PlayerStatus; } #include #include "HybridOmniEventMapSpec.hpp" #include "Source.hpp" +#include #include "Track.hpp" #include #include "Rendition.hpp" #include "PlayerStatus.hpp" -#include namespace margelo::nitro::omni { @@ -63,6 +63,8 @@ namespace margelo::nitro::omni { virtual std::shared_ptr getEventMap() = 0; virtual Source getSource() = 0; virtual void setSource(const Source& source) = 0; + virtual std::optional getShowNotification() = 0; + virtual void setShowNotification(std::optional showNotification) = 0; virtual bool getHasPrev() = 0; virtual bool getHasNext() = 0; virtual std::vector getVideos() = 0; diff --git a/nitrogen/generated/shared/c++/HybridOmniViewSpec.cpp b/nitrogen/generated/shared/c++/HybridOmniViewSpec.cpp index 2fef818..80e1382 100644 --- a/nitrogen/generated/shared/c++/HybridOmniViewSpec.cpp +++ b/nitrogen/generated/shared/c++/HybridOmniViewSpec.cpp @@ -18,8 +18,6 @@ namespace margelo::nitro::omni { prototype.registerHybridSetter("player", &HybridOmniViewSpec::setPlayer); prototype.registerHybridGetter("autoplay", &HybridOmniViewSpec::getAutoplay); prototype.registerHybridSetter("autoplay", &HybridOmniViewSpec::setAutoplay); - prototype.registerHybridGetter("showNotification", &HybridOmniViewSpec::getShowNotification); - prototype.registerHybridSetter("showNotification", &HybridOmniViewSpec::setShowNotification); prototype.registerHybridGetter("autoPip", &HybridOmniViewSpec::getAutoPip); prototype.registerHybridSetter("autoPip", &HybridOmniViewSpec::setAutoPip); }); diff --git a/nitrogen/generated/shared/c++/HybridOmniViewSpec.hpp b/nitrogen/generated/shared/c++/HybridOmniViewSpec.hpp index 5139d4a..239747a 100644 --- a/nitrogen/generated/shared/c++/HybridOmniViewSpec.hpp +++ b/nitrogen/generated/shared/c++/HybridOmniViewSpec.hpp @@ -51,8 +51,6 @@ namespace margelo::nitro::omni { 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; - virtual void setShowNotification(std::optional showNotification) = 0; virtual std::optional getAutoPip() = 0; virtual void setAutoPip(std::optional autoPip) = 0; diff --git a/nitrogen/generated/shared/c++/views/HybridOmniViewComponent.cpp b/nitrogen/generated/shared/c++/views/HybridOmniViewComponent.cpp index 80d55b1..435239d 100644 --- a/nitrogen/generated/shared/c++/views/HybridOmniViewComponent.cpp +++ b/nitrogen/generated/shared/c++/views/HybridOmniViewComponent.cpp @@ -46,16 +46,6 @@ namespace margelo::nitro::omni::views { throw std::runtime_error(std::string("OmniView.autoplay: ") + exc.what()); } }()), - showNotification([&]() -> CachedProp> { - try { - const react::RawValue* rawValue = rawProps.at("showNotification", nullptr, nullptr); - if (rawValue == nullptr) return sourceProps.showNotification; - const auto& [runtime, value] = (std::pair)*rawValue; - return CachedProp>::fromRawValue(*runtime, value, sourceProps.showNotification); - } catch (const std::exception& exc) { - throw std::runtime_error(std::string("OmniView.showNotification: ") + exc.what()); - } - }()), autoPip([&]() -> CachedProp> { try { const react::RawValue* rawValue = rawProps.at("autoPip", nullptr, nullptr); @@ -81,7 +71,6 @@ namespace margelo::nitro::omni::views { switch (hashString(propName)) { case hashString("player"): return true; case hashString("autoplay"): return true; - case hashString("showNotification"): return true; case hashString("autoPip"): return true; case hashString("hybridRef"): return true; default: return false; diff --git a/nitrogen/generated/shared/c++/views/HybridOmniViewComponent.hpp b/nitrogen/generated/shared/c++/views/HybridOmniViewComponent.hpp index 3e9c2dc..6cee4ed 100644 --- a/nitrogen/generated/shared/c++/views/HybridOmniViewComponent.hpp +++ b/nitrogen/generated/shared/c++/views/HybridOmniViewComponent.hpp @@ -44,7 +44,6 @@ namespace margelo::nitro::omni::views { public: CachedProp> player; CachedProp> autoplay; - CachedProp> showNotification; CachedProp> autoPip; CachedProp& /* ref */)>>> hybridRef; diff --git a/nitrogen/generated/shared/json/OmniViewConfig.json b/nitrogen/generated/shared/json/OmniViewConfig.json index 30d7d1b..d1d9e8c 100644 --- a/nitrogen/generated/shared/json/OmniViewConfig.json +++ b/nitrogen/generated/shared/json/OmniViewConfig.json @@ -6,7 +6,6 @@ "validAttributes": { "player": true, "autoplay": true, - "showNotification": true, "autoPip": true, "hybridRef": true } diff --git a/src/events.tsx b/src/events.tsx index 9fc316e..466446e 100644 --- a/src/events.tsx +++ b/src/events.tsx @@ -20,10 +20,17 @@ export const useEvent = ( }, [player, event, callback]); }; -// export const usePlayerState = (key: "progress", refresh?: number): OmniPlayerState["progress"]; -export const usePlayerState = ( +export function usePlayerState( key: Key, -): OmniPlayerState[Key] => { +): OmniPlayerState[Key]; +export function usePlayerState( + key: "currentTime", + refresh?: number, +): OmniPlayerState["currentTime"]; +export function usePlayerState( + key: Key, + refresh?: number, +): OmniPlayerState[Key] { const player = usePlayer() as OmniPlayer; const [ret, setState] = useState(player[key]); @@ -47,5 +54,14 @@ export const usePlayerState = ( } }, [player, key]); + if (key === "currentTime") refresh ??= 1; + useEffect(() => { + if (!refresh || refresh <= 0) return; + const int = setInterval(() => { + setState(player[key]) + }, refresh); + return () => clearInterval(int); + }, [refresh, key, player]); + return ret; -}; +} diff --git a/src/provider.tsx b/src/provider.tsx index 33ccb82..aa5e221 100755 --- a/src/provider.tsx +++ b/src/provider.tsx @@ -5,28 +5,31 @@ import type { OmniPlayer } from "./types/player"; import type { Source } from "./types/source"; import { useLazyRef } from "./utils/lazy-ref"; -const ProviderFactory = NitroModules.createHybridObject( - "OmniPlayerFactory", -); +const ProviderFactory = + NitroModules.createHybridObject("OmniPlayerFactory"); const PlayerCtx = createContext(null!); export const OmniProvider = ({ children, source, + showNotification = false, }: { source: Source; children: ReactNode; + showNotification?: boolean; }) => { const player = useLazyRef(() => ProviderFactory.createPlayer(source)); useEffect(() => { - player.current.source = source; + player.source = source; }, [source]); - return ( - {children} - ); + useEffect(() => { + player.showNotification = showNotification; + }, [showNotification]); + + return {children}; }; export const usePlayer = () => { diff --git a/src/types/player.ts b/src/types/player.ts index 8c57724..3660b75 100644 --- a/src/types/player.ts +++ b/src/types/player.ts @@ -2,6 +2,7 @@ import type { Source } from "./source"; export interface OmniPlayer extends OmniPlayerState { source: Source; + showNotification?: boolean; play(): void; pause(): void; diff --git a/src/types/view.ts b/src/types/view.ts index abd1d43..2478614 100644 --- a/src/types/view.ts +++ b/src/types/view.ts @@ -1,5 +1,4 @@ export interface OmniViewProps { autoplay?: boolean; - showNotification?: boolean; autoPip?: boolean; } diff --git a/src/utils/lazy-ref.ts b/src/utils/lazy-ref.ts index 2eccacf..bc5da85 100644 --- a/src/utils/lazy-ref.ts +++ b/src/utils/lazy-ref.ts @@ -1,13 +1,6 @@ -import { type RefObject, useRef } from "react"; +import { useState } from "react"; -const empty = Symbol("useLazyRef empty value"); - -export const useLazyRef = (init: () => T): RefObject => { - const resultRef = useRef(empty); - - if (resultRef.current === empty) { - resultRef.current = init(); - } - - return resultRef as RefObject; +export const useLazyRef = (init: () => T): T => { + const [ret] = useState(init); + return ret };