Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions android/src/main/java/com/margelo/nitro/rive/DeprecationWarning.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.margelo.nitro.rive

object DeprecationWarning {
private val warned = mutableSetOf<String>()

fun warn(method: String, replacement: String) {
if (warned.add(method)) {
RiveLog.w(
"Deprecation",
"'$method' is deprecated and blocks the calling thread. Use '$replacement' instead.",
)
}
}
}
16 changes: 16 additions & 0 deletions android/src/main/java/com/margelo/nitro/rive/HybridRiveLogger.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.margelo.nitro.rive

import androidx.annotation.Keep
import com.facebook.proguard.annotations.DoNotStrip

@Keep
@DoNotStrip
class HybridRiveLogger : HybridRiveLoggerSpec() {
override fun setHandler(handler: (level: String, tag: String, message: String) -> Unit) {
RiveLog.handler = handler
}

override fun resetHandler() {
RiveLog.handler = null
}
}
23 changes: 23 additions & 0 deletions android/src/main/java/com/margelo/nitro/rive/RiveLog.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.margelo.nitro.rive

import android.util.Log

object RiveLog {
var handler: ((String, String, String) -> Unit)? = null

fun e(tag: String, message: String) {
handler?.invoke("error", tag, message) ?: Log.e(tag, message)
}

fun w(tag: String, message: String) {
handler?.invoke("warn", tag, message) ?: Log.w(tag, message)
}

fun i(tag: String, message: String) {
handler?.invoke("info", tag, message) ?: Log.i(tag, message)
}

fun d(tag: String, message: String) {
handler?.invoke("debug", tag, message) ?: Log.d(tag, message)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,11 @@ object ExperimentalAssetLoader {
} else if (data.matchesAt(8, 0x57, 0x45, 0x42, 0x50)) {
AssetType.IMAGE // WebP (WEBP)
} else {
Log.w(TAG, "Unknown RIFF asset, assuming IMAGE. Declare asset type explicitly to avoid this.")
RiveLog.w(TAG, "Unknown RIFF asset, assuming IMAGE. Declare asset type explicitly to avoid this.")
AssetType.IMAGE
}
else -> {
Log.w(TAG, "Could not infer asset type from magic bytes, assuming IMAGE. Declare asset type explicitly to avoid this.")
RiveLog.w(TAG, "Could not infer asset type from magic bytes, assuming IMAGE. Declare asset type explicitly to avoid this.")
AssetType.IMAGE
}
}
Expand Down
19 changes: 12 additions & 7 deletions android/src/new/java/com/margelo/nitro/rive/HybridRiveFile.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.margelo.nitro.rive

import android.util.Log
import androidx.annotation.Keep
import app.rive.Artboard
import app.rive.RiveFile
Expand All @@ -26,11 +25,12 @@ class HybridRiveFile(
// Deprecated: Use getViewModelNamesAsync instead
override val viewModelCount: Double?
get() {
DeprecationWarning.warn("viewModelCount", "getViewModelNamesAsync")
val file = riveFile ?: return null
return try {
runBlocking { file.getViewModelNames() }.size.toDouble()
} catch (e: Exception) {
Log.e(TAG, "viewModelCount failed", e)
RiveLog.e(TAG, "viewModelCount failed: ${e.message}")
null
}
}
Expand All @@ -44,14 +44,15 @@ class HybridRiveFile(

// Deprecated: Use getViewModelNamesAsync + viewModelByNameAsync instead
override fun viewModelByIndex(index: Double): HybridViewModelSpec? {
DeprecationWarning.warn("viewModelByIndex", "getViewModelNamesAsync + viewModelByNameAsync")
val file = riveFile ?: return null
return try {
val names = runBlocking { file.getViewModelNames() }
val idx = index.toInt()
if (idx < 0 || idx >= names.size) return null
HybridViewModel(file, riveWorker, names[idx], this, ViewModelSource.Named(names[idx]))
} catch (e: Exception) {
Log.e(TAG, "viewModelByIndex($index) failed", e)
RiveLog.e(TAG, "viewModelByIndex($index) failed: ${e.message}")
null
}
}
Expand All @@ -67,10 +68,11 @@ class HybridRiveFile(

// Deprecated: Use viewModelByNameAsync instead
override fun viewModelByName(name: String): HybridViewModelSpec? {
DeprecationWarning.warn("viewModelByName", "viewModelByNameAsync")
return try {
runBlocking { viewModelByNameImpl(name, validate = true) }
} catch (e: Exception) {
Log.e(TAG, "viewModelByName('$name') failed", e)
RiveLog.e(TAG, "viewModelByName('$name') failed: ${e.message}")
null
}
}
Expand Down Expand Up @@ -105,10 +107,11 @@ class HybridRiveFile(

// Deprecated: Use defaultArtboardViewModelAsync instead
override fun defaultArtboardViewModel(artboardBy: ArtboardBy?): HybridViewModelSpec? {
DeprecationWarning.warn("defaultArtboardViewModel", "defaultArtboardViewModelAsync")
return try {
runBlocking { defaultArtboardViewModelImpl(artboardBy) }
} catch (e: Exception) {
Log.e(TAG, "defaultArtboardViewModel failed", e)
RiveLog.e(TAG, "defaultArtboardViewModel failed: ${e.message}")
null
}
}
Expand All @@ -120,11 +123,12 @@ class HybridRiveFile(
// Deprecated: Use getArtboardCountAsync instead
override val artboardCount: Double
get() {
DeprecationWarning.warn("artboardCount", "getArtboardCountAsync")
val file = riveFile ?: return 0.0
return try {
runBlocking { file.getArtboardNames() }.size.toDouble()
} catch (e: Exception) {
Log.e(TAG, "artboardCount failed", e)
RiveLog.e(TAG, "artboardCount failed: ${e.message}")
0.0
}
}
Expand All @@ -139,11 +143,12 @@ class HybridRiveFile(
// Deprecated: Use getArtboardNamesAsync instead
override val artboardNames: Array<String>
get() {
DeprecationWarning.warn("artboardNames", "getArtboardNamesAsync")
val file = riveFile ?: return emptyArray()
return try {
runBlocking { file.getArtboardNames() }.toTypedArray()
} catch (e: Exception) {
Log.e(TAG, "artboardNames failed", e)
RiveLog.e(TAG, "artboardNames failed: ${e.message}")
emptyArray()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

/**
* Custom RiveLog logger that logs to Logcat and broadcasts error messages
* to registered listeners. This captures C++ errors from the Rive CommandQueue
* (e.g., "State machine not found", "Draw failed") that are otherwise silent.
* Custom RiveLog logger that routes all Rive C++ runtime logs through [RiveLog]
* and broadcasts error messages to registered listeners. This captures C++ errors
* from the Rive CommandQueue (e.g., "State machine not found", "Draw failed").
*/
object RiveErrorLogger : app.rive.RiveLog.Logger {
private val logcat = app.rive.RiveLog.LogcatLogger()
private val listeners = mutableListOf<(String) -> Unit>()
private val reportedErrors = mutableSetOf<String>()

Expand All @@ -47,13 +46,21 @@ object RiveErrorLogger : app.rive.RiveLog.Logger {
synchronized(reportedErrors) { reportedErrors.clear() }
}

override fun v(tag: String, msg: () -> String) = logcat.v(tag, msg)
override fun d(tag: String, msg: () -> String) = logcat.d(tag, msg)
override fun i(tag: String, msg: () -> String) = logcat.i(tag, msg)
override fun w(tag: String, msg: () -> String) = logcat.w(tag, msg)
override fun v(tag: String, msg: () -> String) {
RiveLog.d(tag, msg())
}
override fun d(tag: String, msg: () -> String) {
RiveLog.d(tag, msg())
}
override fun i(tag: String, msg: () -> String) {
RiveLog.i(tag, msg())
}
override fun w(tag: String, msg: () -> String) {
RiveLog.w(tag, msg())
}
override fun e(tag: String, t: Throwable?, msg: () -> String) {
val message = msg()
logcat.e(tag, t) { message }
RiveLog.e(tag, message)
broadcastError(tag, message)
}
}
Expand Down
19 changes: 12 additions & 7 deletions android/src/new/java/com/margelo/nitro/rive/HybridViewModel.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.margelo.nitro.rive

import android.util.Log
import androidx.annotation.Keep
import app.rive.RiveFile
import app.rive.ViewModelInstance
Expand Down Expand Up @@ -33,22 +32,24 @@ class HybridViewModel(

override val propertyCount: Double
get() {
DeprecationWarning.warn("propertyCount", "getPropertyCountAsync")
val name = viewModelName ?: throw UnsupportedOperationException(NO_NAME_ERROR)
return try {
runBlocking { riveFile.getViewModelProperties(name) }.size.toDouble()
} catch (e: Exception) {
Log.e(TAG, "propertyCount failed", e)
RiveLog.e(TAG, "propertyCount failed: ${e.message}")
0.0
}
}

override val instanceCount: Double
get() {
DeprecationWarning.warn("instanceCount", "getInstanceCountAsync")
val name = viewModelName ?: throw UnsupportedOperationException(NO_NAME_ERROR)
return try {
runBlocking { riveFile.getViewModelInstanceNames(name) }.size.toDouble()
} catch (e: Exception) {
Log.e(TAG, "instanceCount failed", e)
RiveLog.e(TAG, "instanceCount failed: ${e.message}")
0.0
}
}
Expand All @@ -68,6 +69,7 @@ class HybridViewModel(

// Deprecated: Use createInstanceByNameAsync instead
override fun createInstanceByIndex(index: Double): HybridViewModelInstanceSpec? {
DeprecationWarning.warn("createInstanceByIndex", "createInstanceByNameAsync")
val name = viewModelName ?: throw UnsupportedOperationException(NO_NAME_ERROR)
return try {
val idx = index.toInt()
Expand All @@ -78,7 +80,7 @@ class HybridViewModel(
} catch (e: UnsupportedOperationException) {
throw e
} catch (e: Exception) {
Log.e(TAG, "createInstanceByIndex($index) failed", e)
RiveLog.e(TAG, "createInstanceByIndex($index) failed: ${e.message}")
null
}
}
Expand All @@ -94,13 +96,14 @@ class HybridViewModel(

// Deprecated: Use createInstanceByNameAsync instead
override fun createInstanceByName(name: String): HybridViewModelInstanceSpec? {
DeprecationWarning.warn("createInstanceByName", "createInstanceByNameAsync")
if (viewModelName == null) throw UnsupportedOperationException(NO_NAME_ERROR)
return try {
runBlocking { createInstanceByNameImpl(name) }
} catch (e: UnsupportedOperationException) {
throw e
} catch (e: Exception) {
Log.e(TAG, "createInstanceByName('$name') failed", e)
RiveLog.e(TAG, "createInstanceByName('$name') failed: ${e.message}")
null
}
}
Expand All @@ -112,12 +115,13 @@ class HybridViewModel(

// Deprecated: Use createDefaultInstanceAsync instead
override fun createDefaultInstance(): HybridViewModelInstanceSpec? {
DeprecationWarning.warn("createDefaultInstance", "createDefaultInstanceAsync")
return try {
val source = vmSource.defaultInstance()
val vmi = ViewModelInstance.fromFile(riveFile, source)
HybridViewModelInstance(vmi, riveWorker, parentFile, viewModelName)
} catch (e: Exception) {
Log.e(TAG, "createDefaultInstance failed", e)
RiveLog.e(TAG, "createDefaultInstance failed: ${e.message}")
null
}
}
Expand All @@ -132,12 +136,13 @@ class HybridViewModel(

// Deprecated: Use createBlankInstanceAsync instead
override fun createInstance(): HybridViewModelInstanceSpec? {
DeprecationWarning.warn("createInstance", "createBlankInstanceAsync")
return try {
val source = vmSource.blankInstance()
val vmi = ViewModelInstance.fromFile(riveFile, source)
HybridViewModelInstance(vmi, riveWorker, parentFile, viewModelName)
} catch (e: Exception) {
Log.e(TAG, "createInstance (blank) failed", e)
RiveLog.e(TAG, "createInstance (blank) failed: ${e.message}")
null
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.margelo.nitro.rive

import android.util.Log
import androidx.annotation.Keep
import app.rive.ViewModelInstance
import com.facebook.proguard.annotations.DoNotStrip
Expand All @@ -22,10 +21,11 @@ class HybridViewModelBooleanProperty(
// Deprecated: Use getValueAsync (read) or set(value) (write) instead
override var value: Boolean
get() {
DeprecationWarning.warn("BooleanProperty.value", "getValueAsync")
return try {
runBlocking { instance.getBooleanFlow(path).first() }
} catch (e: Exception) {
Log.e(TAG, "getValue failed for path '$path'", e)
RiveLog.e(TAG, "getValue failed for path '$path': ${e.message}")
false
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.margelo.nitro.rive

import android.util.Log
import androidx.annotation.Keep
import app.rive.ViewModelInstance
import com.facebook.proguard.annotations.DoNotStrip
Expand All @@ -22,10 +21,11 @@ class HybridViewModelColorProperty(
// Deprecated: Use getValueAsync (read) or set(value) (write) instead
override var value: Double
get() {
DeprecationWarning.warn("ColorProperty.value", "getValueAsync")
return try {
runBlocking { instance.getColorFlow(path).first() }.toDouble()
} catch (e: Exception) {
Log.e(TAG, "getValue failed for path '$path'", e)
RiveLog.e(TAG, "getValue failed for path '$path': ${e.message}")
0.0
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.margelo.nitro.rive

import android.util.Log
import androidx.annotation.Keep
import app.rive.ViewModelInstance
import com.facebook.proguard.annotations.DoNotStrip
Expand All @@ -22,10 +21,11 @@ class HybridViewModelEnumProperty(
// Deprecated: Use getValueAsync (read) or set(value) (write) instead
override var value: String
get() {
DeprecationWarning.warn("EnumProperty.value", "getValueAsync")
return try {
runBlocking { instance.getEnumFlow(path).first() }
} catch (e: Exception) {
Log.e(TAG, "getValue failed for path '$path'", e)
RiveLog.e(TAG, "getValue failed for path '$path': ${e.message}")
""
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,11 @@ class HybridViewModelInstance(

// Deprecated: Use viewModelAsync instead
override fun viewModel(path: String): HybridViewModelInstanceSpec? {
DeprecationWarning.warn("viewModel", "viewModelAsync")
return try {
viewModelImpl(path)
} catch (e: Exception) {
Log.e(TAG, "viewModel failed for path '$path'", e)
RiveLog.e(TAG, "viewModel failed for path '$path': ${e.message}")
null
}
}
Expand Down
Loading
Loading