Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
582f156
feat: experimental iOS Rive backend with synchronous API
mfazekas Feb 9, 2026
5916624
chore: move docs to .local/docs, remove from git
mfazekas Feb 9, 2026
a845f29
refactor: remove ExperimentalFileSource from legacy backend
mfazekas Feb 9, 2026
6ebf265
fix: restore whitespace in legacy files, remove fragile asset type gu…
mfazekas Feb 9, 2026
32e742c
fix: share single Worker across all files, fix artboard property data…
mfazekas Feb 9, 2026
7dc2964
fix: wire up trigger property to experimental fire/stream API
mfazekas Feb 9, 2026
7ff04e8
fix: set fit after view setup to fix .layout mode on initial render
mfazekas Feb 11, 2026
e418b4b
test: add advanced data binding harness tests
mfazekas Feb 11, 2026
31c3115
fix: guard negative index in legacy viewModelByIndex and createInstan…
mfazekas Feb 11, 2026
cf062f2
fix: correct trigger property listener task type signature
mfazekas Feb 11, 2026
caff580
fix: embed SPM RiveRuntime.framework via Podfile post_install hook
mfazekas Feb 11, 2026
04d7a20
refactor: split Android into legacy/experimental backend directories
mfazekas Feb 12, 2026
046becf
feat: implement Android experimental backend using new app.rive.* API
mfazekas Feb 12, 2026
2c25174
feat: implement Android experimental backend with CommandQueue API
mfazekas Feb 16, 2026
aebbc51
feat: migrate getEnums() from sync to async (Promise)
mfazekas Feb 17, 2026
beb5827
fix: color property overflow and test tolerance for cross-platform di…
mfazekas Feb 17, 2026
8196fed
feat: add backend property to RiveFileFactory for runtime detection
mfazekas Feb 17, 2026
3e42312
feat: migrate viewModelByIndex, createInstanceByIndex, viewModel to a…
mfazekas Feb 17, 2026
a01fc48
fix: lint formatting in ViewModel spec and harness test
mfazekas Feb 17, 2026
920dfb4
ci: add experimental runtime harness tests for iOS and Android
mfazekas Feb 18, 2026
c68ec58
ci: increase iOS experimental harness timeout to 90min for cold builds
mfazekas Feb 18, 2026
436d243
fix: handle throwing Worker() init in rive-ios 6.15.1
mfazekas Feb 18, 2026
fc628e5
fix: experimental iOS instance lookup and test guards
mfazekas Feb 19, 2026
7e984b2
feat: add async APIs for RiveFile/ViewModel and fix experimental inst…
mfazekas Feb 19, 2026
4fd2755
chore: upgrade rive-ios SPM to 6.15.2
mfazekas Feb 19, 2026
96abedd
fix: only allow snakeLizard enum on android legacy backend
mfazekas Feb 19, 2026
5b13844
test: add useViewModelInstance e2e harness tests
mfazekas Feb 19, 2026
91c487b
fix: implement color property get/listen and fix UInt32 crash on expe…
mfazekas Feb 26, 2026
06e7401
feat(ios): decouple SPM from experimental runtime toggle
mfazekas Mar 11, 2026
7f5904d
feat: make useRiveProperty start undefined and deliver value via list…
mfazekas Mar 11, 2026
503a981
Merge remote-tracking branch 'origin/main' into feat/rive-ios-experim…
mfazekas Mar 11, 2026
efd8521
fix: unify USE_RIVE_NEW_API flag, replace SPM with CocoaPods, fix exp…
mfazekas Mar 12, 2026
47f4a51
fix: skip autoPlay test on both experimental backends
mfazekas Mar 12, 2026
f1b851e
fix: remove unused Platform import
mfazekas Mar 12, 2026
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
195 changes: 195 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -474,3 +474,198 @@ jobs:
run: |
echo "=== Checking logcat for errors ==="
adb logcat -d -s ReactNativeJS:* RiveExample:* RNRive:* | tail -200 || echo "No logs found"

test-harness-ios-experimental:
runs-on: macos-latest
timeout-minutes: 90
env:
XCODE_VERSION: 16.4
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup
uses: ./.github/actions/setup

- name: Use appropriate Xcode version
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: ${{ env.XCODE_VERSION }}

- name: Restore cocoapods
id: cocoapods-cache
uses: actions/cache/restore@v4
with:
path: |
**/ios/Pods
key: ${{ runner.os }}-experimental-cocoapods-${{ hashFiles('example/ios/Podfile', '*.podspec') }}
restore-keys: |
${{ runner.os }}-experimental-cocoapods-

- name: Install cocoapods
if: steps.cocoapods-cache.outputs.cache-hit != 'true'
run: |
cd example
bundle install
USE_RIVE_NEW_API=1 bundle exec pod install --project-directory=ios

- name: Save cocoapods cache
if: steps.cocoapods-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: |
**/ios/Pods
key: ${{ steps.cocoapods-cache.outputs.cache-key }}

- name: Restore iOS build cache
id: ios-build-cache
uses: actions/cache/restore@v4
with:
path: example/ios/build
key: ${{ runner.os }}-ios-experimental-build-${{ env.XCODE_VERSION }}-${{ hashFiles('yarn.lock', 'ios/**', 'nitrogen/generated/ios/**', '*.podspec', 'example/ios/Podfile', 'example/ios/RiveExample/**') }}
restore-keys: |
${{ runner.os }}-ios-experimental-build-${{ env.XCODE_VERSION }}-

- name: Build iOS app
if: steps.ios-build-cache.outputs.cache-hit != 'true'
working-directory: example/ios
run: |
set -o pipefail && xcodebuild \
-derivedDataPath build \
-workspace RiveExample.xcworkspace \
-scheme RiveExample \
-sdk iphonesimulator \
-configuration Debug \
build \
CODE_SIGNING_ALLOWED=NO

- name: Save iOS build cache
if: steps.ios-build-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: example/ios/build
key: ${{ steps.ios-build-cache.outputs.cache-primary-key }}

- name: Boot iOS Simulator
uses: futureware-tech/simulator-action@v4
with:
model: 'iPhone 16 Pro'
os_version: '18.6'

- name: Install app on simulator
run: xcrun simctl install booted example/ios/build/Build/Products/Debug-iphonesimulator/RiveExample.app

- name: Wait for simulator to be fully ready
run: |
echo "Waiting for simulator to be fully ready..."
sleep 10
xcrun simctl list devices | grep Booted

- name: Run harness tests on iOS
working-directory: example
run: |
for attempt in 1 2 3; do
echo "Attempt $attempt of 3"
if yarn test:harness:ios --verbose --testTimeout 120000; then
echo "Tests passed on attempt $attempt"
exit 0
fi
echo "Attempt $attempt failed, retrying..."
sleep 5
done
echo "All attempts failed"
exit 1

- name: Debug - Check for console logs
if: failure()
run: |
echo "=== Checking simulator logs for errors ==="
xcrun simctl spawn booted log show --predicate 'processImagePath CONTAINS "RiveExample"' --last 5m --style compact 2>&1 | tail -200 || echo "No logs found"

test-harness-android-experimental:
runs-on: ubuntu-latest
timeout-minutes: 30
env:
ANDROID_API_LEVEL: 35
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup
uses: ./.github/actions/setup

- name: Install JDK
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: '17'

- name: Finalize Android SDK
run: |
/bin/bash -c "yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses > /dev/null"

- name: Enable experimental Rive API
run: |
sed -i 's/USE_RIVE_NEW_API=false/USE_RIVE_NEW_API=true/' example/android/gradle.properties

- name: Cache Gradle
uses: actions/cache@v4
with:
path: |
~/.gradle/wrapper
~/.gradle/caches
key: ${{ runner.os }}-gradle-harness-experimental-${{ hashFiles('example/android/gradle/wrapper/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-harness-experimental-
${{ runner.os }}-gradle-harness-
${{ runner.os }}-gradle-

- name: Restore Android build cache
id: android-build-cache
uses: actions/cache/restore@v4
with:
path: example/android/app/build
key: ${{ runner.os }}-android-experimental-build-${{ env.ANDROID_API_LEVEL }}-${{ hashFiles('yarn.lock', 'android/**', 'nitrogen/generated/android/**', 'example/android/app/build.gradle', 'example/android/gradle.properties') }}
restore-keys: |
${{ runner.os }}-android-experimental-build-${{ env.ANDROID_API_LEVEL }}-

- name: Build Android app
if: steps.android-build-cache.outputs.cache-hit != 'true'
working-directory: example/android
env:
JAVA_OPTS: "-XX:MaxHeapSize=6g"
run: |
./gradlew assembleDebug --no-daemon --console=plain -PreactNativeArchitectures=x86_64

- name: Save Android build cache
if: steps.android-build-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: example/android/app/build
key: ${{ steps.android-build-cache.outputs.cache-primary-key }}

- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm

- name: Run harness tests on Android
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ env.ANDROID_API_LEVEL }}
arch: x86_64
target: google_apis
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim
disable-animations: true
script: |
adb install example/android/app/build/outputs/apk/debug/app-debug.apk
sleep 10
cd example && for attempt in 1 2 3; do echo "Attempt $attempt of 3"; if timeout 300 env ANDROID_AVD=test yarn test:harness:android --verbose --testTimeout 120000; then echo "Tests passed on attempt $attempt"; exit 0; fi; echo "Attempt $attempt failed (exit $?), retrying..."; sleep 5; done; echo "All attempts failed"; exit 1

- name: Debug - Check logcat
if: failure() || cancelled()
run: |
echo "=== Checking logcat for errors ==="
adb logcat -d -s ReactNativeJS:* RiveExample:* RNRive:* | tail -200 || echo "No logs found"
22 changes: 20 additions & 2 deletions RNRive.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,15 @@ if !rive_ios_version
raise "Internal Error: Failed to determine Rive iOS SDK version. Please ensure package.json contains 'runtimeVersions.ios'"
end

Pod::UI.puts "@rive-app/react-native: Rive iOS SDK #{rive_ios_version}"
# Set to '1' (or set $UseRiveNewAPI = true in Podfile) to enable the
# experimental Rive runtime backend. When disabled, the legacy backend is used.
use_rive_new_api = ENV['USE_RIVE_NEW_API'] == '1' || (defined?($UseRiveNewAPI) && $UseRiveNewAPI)

if use_rive_new_api
Pod::UI.puts "@rive-app/react-native: Using experimental Rive runtime backend"
else
Pod::UI.puts "@rive-app/react-native: Using legacy Rive runtime backend (iOS SDK #{rive_ios_version})"
end

Pod::Spec.new do |s|
s.name = "RNRive"
Expand All @@ -43,11 +51,21 @@ Pod::Spec.new do |s|

s.source_files = "ios/**/*.{h,m,mm,swift}"

if use_rive_new_api
s.exclude_files = ["ios/legacy/**"]
else
s.exclude_files = ["ios/new/**"]
end

s.public_header_files = ['ios/RCTSwiftLog.h']
load 'nitrogen/generated/ios/RNRive+autolinking.rb'
add_nitrogen_files(s)

s.dependency "RiveRuntime", rive_ios_version
s.dependency 'RiveRuntime', rive_ios_version

install_modules_dependencies(s)

if use_rive_new_api
s.xcconfig = { 'OTHER_SWIFT_FLAGS' => '$(inherited) -DRIVE_EXPERIMENTAL_API' }
end
end
7 changes: 7 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,17 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}

def useNewRiveApi = rootProject.findProperty('USE_RIVE_NEW_API') == 'true'

sourceSets {
main {
java.srcDirs += ["generated/java",
"generated/jni"]
if (useNewRiveApi) {
java.srcDirs += ["src/experimental/java"]
} else {
java.srcDirs += ["src/legacy/java"]
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package com.margelo.nitro.rive

import android.util.Log
import app.rive.AudioAsset
import app.rive.FontAsset
import app.rive.ImageAsset
import app.rive.core.CommandQueue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

object ExperimentalAssetLoader {
private const val TAG = "ExperimentalAssetLoader"

fun registerAssets(
referencedAssets: ReferencedAssetsType?,
riveWorker: CommandQueue
) {
val assetsData = referencedAssets?.data ?: return
val scope = CoroutineScope(Dispatchers.IO)

for ((name, assetData) in assetsData) {
val source = DataSourceResolver.resolve(assetData) ?: continue
scope.launch {
try {
val loader = source.createLoader()
val data = loader.load(source)
val type = inferAssetType(name, data)
registerAsset(data, name, type, riveWorker)
} catch (e: Exception) {
Log.e(TAG, "Failed to load asset '$name'", e)
}
}
}
}

fun updateAssets(
referencedAssets: ReferencedAssetsType,
riveWorker: CommandQueue
) {
val assetsData = referencedAssets.data ?: return
val scope = CoroutineScope(Dispatchers.IO)

for ((name, assetData) in assetsData) {
val source = DataSourceResolver.resolve(assetData) ?: continue
scope.launch {
try {
val loader = source.createLoader()
val data = loader.load(source)
val type = inferAssetType(name, data)
registerAsset(data, name, type, riveWorker)
} catch (e: Exception) {
Log.e(TAG, "Failed to update asset '$name'", e)
}
}
}
}

private suspend fun registerAsset(
data: ByteArray,
name: String,
type: AssetType,
riveWorker: CommandQueue
) {
Log.i(TAG, "Registering $type asset '$name' (${data.size} bytes)")
when (type) {
AssetType.IMAGE -> {
riveWorker.unregisterImage(name)
val result = ImageAsset.fromBytes(riveWorker, data)
if (result is app.rive.Result.Success) {
result.value.register(name)
Log.i(TAG, "Image '$name' registered")
}
}
AssetType.FONT -> {
riveWorker.unregisterFont(name)
val result = FontAsset.fromBytes(riveWorker, data)
if (result is app.rive.Result.Success) {
result.value.register(name)
Log.i(TAG, "Font '$name' registered")
}
}
AssetType.AUDIO -> {
riveWorker.unregisterAudio(name)
val result = AudioAsset.fromBytes(riveWorker, data)
if (result is app.rive.Result.Success) {
result.value.register(name)
Log.i(TAG, "Audio '$name' registered")
}
}
}
}

private fun inferAssetType(name: String, data: ByteArray): AssetType {
val ext = name.substringAfterLast('.', "").lowercase()
return when (ext) {
"png", "jpg", "jpeg", "webp", "gif", "bmp", "svg" -> AssetType.IMAGE
"ttf", "otf", "woff", "woff2" -> AssetType.FONT
"wav", "mp3", "ogg", "flac", "aac", "m4a" -> AssetType.AUDIO
else -> inferFromMagicBytes(data)
}
}

private fun inferFromMagicBytes(data: ByteArray): AssetType {
if (data.size < 4) return AssetType.IMAGE

// PNG: 89 50 4E 47
if (data[0] == 0x89.toByte() && data[1] == 0x50.toByte() &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:condition-wrapping reported by reviewdog 🐶
Newline expected before operand in multiline condition

data[2] == 0x4E.toByte() && data[3] == 0x47.toByte()) return AssetType.IMAGE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:condition-wrapping reported by reviewdog 🐶
Newline expected before operand in multiline condition

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:wrapping reported by reviewdog 🐶
Missing newline before ")"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:if-else-wrapping reported by reviewdog 🐶
Expected a newline

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:multiline-if-else reported by reviewdog 🐶
Missing { ... }

// JPEG: FF D8 FF
if (data[0] == 0xFF.toByte() && data[1] == 0xD8.toByte() &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:condition-wrapping reported by reviewdog 🐶
Newline expected before operand in multiline condition

data[2] == 0xFF.toByte()) return AssetType.IMAGE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:wrapping reported by reviewdog 🐶
Missing newline before ")"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:if-else-wrapping reported by reviewdog 🐶
Expected a newline

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:multiline-if-else reported by reviewdog 🐶
Missing { ... }

// RIFF container: WebP (RIFF....WEBP) or WAV (RIFF....WAVE)
if (data[0] == 0x52.toByte() && data[1] == 0x49.toByte() &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:condition-wrapping reported by reviewdog 🐶
Newline expected before operand in multiline condition

data[2] == 0x46.toByte() && data[3] == 0x46.toByte()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:condition-wrapping reported by reviewdog 🐶
Newline expected before operand in multiline condition

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:wrapping reported by reviewdog 🐶
Missing newline before ")"

if (data.size >= 12 &&
data[8] == 0x57.toByte() && data[9] == 0x41.toByte() &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:condition-wrapping reported by reviewdog 🐶
Newline expected before operand in multiline condition

data[10] == 0x56.toByte() && data[11] == 0x45.toByte()) return AssetType.AUDIO // "WAVE"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:condition-wrapping reported by reviewdog 🐶
Newline expected before operand in multiline condition

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:wrapping reported by reviewdog 🐶
Missing newline before ")"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:if-else-wrapping reported by reviewdog 🐶
Expected a newline

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:multiline-if-else reported by reviewdog 🐶
Missing { ... }

return AssetType.IMAGE // assume WebP for other RIFF
}
// ID3 (MP3): 49 44 33
if (data[0] == 0x49.toByte() && data[1] == 0x44.toByte() &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:condition-wrapping reported by reviewdog 🐶
Newline expected before operand in multiline condition

data[2] == 0x33.toByte()) return AssetType.AUDIO
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:wrapping reported by reviewdog 🐶
Missing newline before ")"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:if-else-wrapping reported by reviewdog 🐶
Expected a newline

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:multiline-if-else reported by reviewdog 🐶
Missing { ... }

// TrueType: 00 01 00 00
if (data[0] == 0x00.toByte() && data[1] == 0x01.toByte() &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:condition-wrapping reported by reviewdog 🐶
Newline expected before operand in multiline condition

data[2] == 0x00.toByte() && data[3] == 0x00.toByte()) return AssetType.FONT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:condition-wrapping reported by reviewdog 🐶
Newline expected before operand in multiline condition

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:wrapping reported by reviewdog 🐶
Missing newline before ")"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:if-else-wrapping reported by reviewdog 🐶
Expected a newline

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:multiline-if-else reported by reviewdog 🐶
Missing { ... }

// OpenType: 4F 54 54 4F ("OTTO")
if (data[0] == 0x4F.toByte() && data[1] == 0x54.toByte() &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:condition-wrapping reported by reviewdog 🐶
Newline expected before operand in multiline condition

data[2] == 0x54.toByte() && data[3] == 0x4F.toByte()) return AssetType.FONT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:condition-wrapping reported by reviewdog 🐶
Newline expected before operand in multiline condition

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:wrapping reported by reviewdog 🐶
Missing newline before ")"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:if-else-wrapping reported by reviewdog 🐶
Expected a newline

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [ktlint] standard:multiline-if-else reported by reviewdog 🐶
Missing { ... }


return AssetType.IMAGE
}

enum class AssetType { IMAGE, FONT, AUDIO }
}
Loading
Loading