react-native-nitro-web-image 0.5.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/NitroWebImage.podspec +33 -0
  2. package/android/CMakeLists.txt +31 -0
  3. package/android/build.gradle +145 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/src/main/AndroidManifest.xml +2 -0
  6. package/android/src/main/cpp/cpp-adapter.cpp +6 -0
  7. package/android/src/main/java/com/margelo/nitro/web/image/AsyncImagePriority+toCoroutineContext.kt +15 -0
  8. package/android/src/main/java/com/margelo/nitro/web/image/HybridWebImageFactory.kt +32 -0
  9. package/android/src/main/java/com/margelo/nitro/web/image/HybridWebImageLoader.kt +32 -0
  10. package/android/src/main/java/com/margelo/nitro/web/image/ImageLoader+loadImageAsync.kt +37 -0
  11. package/android/src/main/java/com/margelo/nitro/web/image/ImageRequestBuilder+applyOptions.kt +58 -0
  12. package/android/src/main/java/com/margelo/nitro/web/image/NitroWebImagePackage.java +44 -0
  13. package/ios/AsyncImageLoadOptions+toSDWebImageOptions.swift +66 -0
  14. package/ios/Bridge.h +8 -0
  15. package/ios/HybridWebImageFactory.swift +32 -0
  16. package/ios/HybridWebImageLoader.swift +54 -0
  17. package/ios/SDWebImageManager+loadImage.swift +30 -0
  18. package/lib/commonjs/index.js +9 -0
  19. package/lib/commonjs/index.js.map +1 -0
  20. package/lib/commonjs/package.json +1 -0
  21. package/lib/commonjs/specs/WebImageFactory.nitro.js +6 -0
  22. package/lib/commonjs/specs/WebImageFactory.nitro.js.map +1 -0
  23. package/lib/module/index.js +5 -0
  24. package/lib/module/index.js.map +1 -0
  25. package/lib/module/package.json +1 -0
  26. package/lib/module/specs/WebImageFactory.nitro.js +4 -0
  27. package/lib/module/specs/WebImageFactory.nitro.js.map +1 -0
  28. package/lib/tsconfig.build.tsbuildinfo +1 -0
  29. package/lib/typescript/index.d.ts +3 -0
  30. package/lib/typescript/index.d.ts.map +1 -0
  31. package/lib/typescript/specs/WebImageFactory.nitro.d.ts +63 -0
  32. package/lib/typescript/specs/WebImageFactory.nitro.d.ts.map +1 -0
  33. package/nitro.json +18 -0
  34. package/nitrogen/generated/.gitattributes +1 -0
  35. package/nitrogen/generated/android/NitroWebImage+autolinking.cmake +78 -0
  36. package/nitrogen/generated/android/NitroWebImage+autolinking.gradle +27 -0
  37. package/nitrogen/generated/android/NitroWebImageOnLoad.cpp +46 -0
  38. package/nitrogen/generated/android/NitroWebImageOnLoad.hpp +25 -0
  39. package/nitrogen/generated/android/c++/JAsyncImageLoadOptions.hpp +88 -0
  40. package/nitrogen/generated/android/c++/JAsyncImagePriority.hpp +62 -0
  41. package/nitrogen/generated/android/c++/JHybridWebImageFactorySpec.cpp +82 -0
  42. package/nitrogen/generated/android/c++/JHybridWebImageFactorySpec.hpp +64 -0
  43. package/nitrogen/generated/android/kotlin/com/margelo/nitro/web/image/AsyncImageLoadOptions.kt +35 -0
  44. package/nitrogen/generated/android/kotlin/com/margelo/nitro/web/image/AsyncImagePriority.kt +26 -0
  45. package/nitrogen/generated/android/kotlin/com/margelo/nitro/web/image/HybridWebImageFactorySpec.kt +58 -0
  46. package/nitrogen/generated/android/kotlin/com/margelo/nitro/web/image/NitroWebImageOnLoad.kt +35 -0
  47. package/nitrogen/generated/ios/NitroWebImage+autolinking.rb +60 -0
  48. package/nitrogen/generated/ios/NitroWebImage-Swift-Cxx-Bridge.cpp +65 -0
  49. package/nitrogen/generated/ios/NitroWebImage-Swift-Cxx-Bridge.hpp +197 -0
  50. package/nitrogen/generated/ios/NitroWebImage-Swift-Cxx-Umbrella.hpp +62 -0
  51. package/nitrogen/generated/ios/NitroWebImageAutolinking.mm +33 -0
  52. package/nitrogen/generated/ios/NitroWebImageAutolinking.swift +25 -0
  53. package/nitrogen/generated/ios/c++/HybridWebImageFactorySpecSwift.cpp +11 -0
  54. package/nitrogen/generated/ios/c++/HybridWebImageFactorySpecSwift.hpp +95 -0
  55. package/nitrogen/generated/ios/swift/AsyncImageLoadOptions.swift +237 -0
  56. package/nitrogen/generated/ios/swift/AsyncImagePriority.swift +44 -0
  57. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +47 -0
  58. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_margelo__nitro__image__HybridImageSpec_.swift +51 -0
  59. package/nitrogen/generated/ios/swift/HybridWebImageFactorySpec.swift +51 -0
  60. package/nitrogen/generated/ios/swift/HybridWebImageFactorySpec_cxx.swift +161 -0
  61. package/nitrogen/generated/shared/c++/AsyncImageLoadOptions.hpp +104 -0
  62. package/nitrogen/generated/shared/c++/AsyncImagePriority.hpp +82 -0
  63. package/nitrogen/generated/shared/c++/HybridWebImageFactorySpec.cpp +22 -0
  64. package/nitrogen/generated/shared/c++/HybridWebImageFactorySpec.hpp +74 -0
  65. package/package.json +113 -0
  66. package/react-native.config.js +16 -0
  67. package/src/index.ts +5 -0
  68. package/src/specs/WebImageFactory.nitro.ts +76 -0
@@ -0,0 +1,33 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "NitroWebImage"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = package["license"]
11
+ s.authors = package["author"]
12
+
13
+ s.platforms = { :ios => min_ios_version_supported, :visionos => 1.0 }
14
+ s.source = { :git => "https://github.com/mrousavy/nitro.git", :tag => "#{s.version}" }
15
+
16
+ s.source_files = [
17
+ # Implementation (Swift)
18
+ "ios/**/*.{swift}",
19
+ # Autolinking/Registration (Objective-C++)
20
+ "ios/**/*.{m,mm}",
21
+ # Implementation (C++ objects)
22
+ "cpp/**/*.{hpp,cpp}",
23
+ ]
24
+
25
+ load 'nitrogen/generated/ios/NitroWebImage+autolinking.rb'
26
+ add_nitrogen_files(s)
27
+
28
+ s.dependency 'React-jsi'
29
+ s.dependency 'React-callinvoker'
30
+ s.dependency 'SDWebImage'
31
+ s.dependency 'NitroImage'
32
+ install_modules_dependencies(s)
33
+ end
@@ -0,0 +1,31 @@
1
+ project(NitroWebImage)
2
+ cmake_minimum_required(VERSION 3.9.0)
3
+
4
+ set (PACKAGE_NAME NitroWebImage)
5
+ set (CMAKE_VERBOSE_MAKEFILE ON)
6
+ set (CMAKE_CXX_STANDARD 20)
7
+
8
+ # Define C++ library and add all sources
9
+ add_library(${PACKAGE_NAME} SHARED
10
+ src/main/cpp/cpp-adapter.cpp
11
+ )
12
+
13
+ # Add Nitrogen specs :)
14
+ include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/NitroWebImage+autolinking.cmake)
15
+
16
+ # Set up local includes
17
+ include_directories(
18
+ "src/main/cpp"
19
+ "../cpp"
20
+ )
21
+
22
+ find_library(LOG_LIB log)
23
+ find_package(react-native-nitro-image REQUIRED) # <-- for the HybridImage type
24
+
25
+ # Link all libraries together
26
+ target_link_libraries(
27
+ ${PACKAGE_NAME}
28
+ ${LOG_LIB}
29
+ android # <-- Android core
30
+ react-native-nitro-image::NitroImage # <-- NitroImage
31
+ )
@@ -0,0 +1,145 @@
1
+ buildscript {
2
+ repositories {
3
+ google()
4
+ mavenCentral()
5
+ }
6
+
7
+ dependencies {
8
+ classpath "com.android.tools.build:gradle:8.10.1"
9
+ }
10
+ }
11
+
12
+ def reactNativeArchitectures() {
13
+ def value = rootProject.getProperties().get("reactNativeArchitectures")
14
+ return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
15
+ }
16
+
17
+ def isNewArchitectureEnabled() {
18
+ return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
19
+ }
20
+
21
+ apply plugin: "com.android.library"
22
+ apply plugin: 'org.jetbrains.kotlin.android'
23
+ apply from: '../nitrogen/generated/android/NitroWebImage+autolinking.gradle'
24
+
25
+ if (isNewArchitectureEnabled()) {
26
+ apply plugin: "com.facebook.react"
27
+ }
28
+
29
+ def getExtOrDefault(name) {
30
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["NitroImage_" + name]
31
+ }
32
+
33
+ def getExtOrIntegerDefault(name) {
34
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["NitroImage_" + name]).toInteger()
35
+ }
36
+
37
+ android {
38
+ namespace "com.margelo.nitro.web.image"
39
+
40
+ ndkVersion getExtOrDefault("ndkVersion")
41
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
42
+
43
+ defaultConfig {
44
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
45
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
46
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
47
+
48
+ externalNativeBuild {
49
+ cmake {
50
+ cppFlags "-frtti -fexceptions -Wall -Wextra -fstack-protector-all"
51
+ arguments "-DANDROID_STL=c++_shared", "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
52
+ abiFilters (*reactNativeArchitectures())
53
+
54
+ buildTypes {
55
+ debug {
56
+ cppFlags "-O1 -g"
57
+ }
58
+ release {
59
+ cppFlags "-O2"
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
65
+
66
+ externalNativeBuild {
67
+ cmake {
68
+ path "CMakeLists.txt"
69
+ }
70
+ }
71
+
72
+ packagingOptions {
73
+ excludes = [
74
+ "META-INF",
75
+ "META-INF/**",
76
+ "**/libc++_shared.so",
77
+ "**/libfbjni.so",
78
+ "**/libjsi.so",
79
+ "**/libfolly_json.so",
80
+ "**/libfolly_runtime.so",
81
+ "**/libglog.so",
82
+ "**/libhermes.so",
83
+ "**/libhermes-executor-debug.so",
84
+ "**/libhermes_executor.so",
85
+ "**/libreactnative.so",
86
+ "**/libreactnativejni.so",
87
+ "**/libturbomodulejsijni.so",
88
+ "**/libreact_nativemodule_core.so",
89
+ "**/libjscexecutor.so"
90
+ ]
91
+ }
92
+
93
+ buildFeatures {
94
+ buildConfig true
95
+ prefab true
96
+ }
97
+
98
+ buildTypes {
99
+ release {
100
+ minifyEnabled false
101
+ }
102
+ }
103
+
104
+ lintOptions {
105
+ disable "GradleCompatible"
106
+ }
107
+
108
+ compileOptions {
109
+ sourceCompatibility JavaVersion.VERSION_1_8
110
+ targetCompatibility JavaVersion.VERSION_1_8
111
+ }
112
+
113
+ sourceSets {
114
+ main {
115
+ if (isNewArchitectureEnabled()) {
116
+ java.srcDirs += [
117
+ // React Codegen files
118
+ "${project.buildDir}/generated/source/codegen/java"
119
+ ]
120
+ }
121
+ }
122
+ }
123
+ }
124
+
125
+ repositories {
126
+ mavenCentral()
127
+ google()
128
+ }
129
+
130
+
131
+ dependencies {
132
+ // For < 0.71, this will be from the local maven repo
133
+ // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
134
+ //noinspection GradleDynamicVersion
135
+ implementation "com.facebook.react:react-native:+"
136
+
137
+ // Add a dependency on NitroModules
138
+ implementation project(":react-native-nitro-modules")
139
+ // Add a dependency on NitroImage
140
+ implementation project(":react-native-nitro-image")
141
+ // Coil
142
+ implementation("io.coil-kt.coil3:coil:3.3.0")
143
+ implementation("io.coil-kt.coil3:coil-network-okhttp:3.3.0")
144
+ }
145
+
@@ -0,0 +1,5 @@
1
+ NitroImage_kotlinVersion=2.0.21
2
+ NitroImage_minSdkVersion=23
3
+ NitroImage_targetSdkVersion=35
4
+ NitroImage_compileSdkVersion=34
5
+ NitroImage_ndkVersion=27.1.12297006
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,6 @@
1
+ #include <jni.h>
2
+ #include "NitroWebImageOnLoad.hpp"
3
+
4
+ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
5
+ return margelo::nitro::web::image::initialize(vm);
6
+ }
@@ -0,0 +1,15 @@
1
+ package com.margelo.nitro.web.image
2
+
3
+ import kotlinx.coroutines.Dispatchers
4
+ import kotlinx.coroutines.currentCoroutineContext
5
+ import kotlin.coroutines.CoroutineContext
6
+
7
+
8
+ fun AsyncImagePriority.toCoroutineContext(): CoroutineContext? {
9
+ // TODO: Does this look about right?
10
+ return when (this) {
11
+ AsyncImagePriority.LOW -> Dispatchers.IO.limitedParallelism(2)
12
+ AsyncImagePriority.DEFAULT -> null
13
+ AsyncImagePriority.HIGH -> Dispatchers.IO
14
+ }
15
+ }
@@ -0,0 +1,32 @@
1
+ package com.margelo.nitro.web.image
2
+
3
+ import androidx.annotation.Keep
4
+ import coil3.ImageLoader
5
+ import com.facebook.common.internal.DoNotStrip
6
+ import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.margelo.nitro.NitroModules
8
+ import com.margelo.nitro.core.Promise
9
+ import com.margelo.nitro.image.HybridImageLoaderSpec
10
+ import com.margelo.nitro.image.HybridImageSpec
11
+
12
+ @DoNotStrip
13
+ @Keep
14
+ class HybridWebImageFactory: HybridWebImageFactorySpec() {
15
+ private val context: ReactApplicationContext
16
+ get() = NitroModules.applicationContext ?: throw Error("No context - NitroModules.applicationContext was null!")
17
+ private val imageLoader = ImageLoader(context)
18
+
19
+ override fun createWebImageLoader(
20
+ url: String,
21
+ options: AsyncImageLoadOptions?
22
+ ): HybridImageLoaderSpec {
23
+ return HybridWebImageLoader(imageLoader, url, options, context)
24
+ }
25
+
26
+ override fun loadFromURLAsync(
27
+ url: String,
28
+ options: AsyncImageLoadOptions?
29
+ ): Promise<HybridImageSpec> {
30
+ return imageLoader.loadImageAsync(url, options, context)
31
+ }
32
+ }
@@ -0,0 +1,32 @@
1
+ package com.margelo.nitro.web.image
2
+
3
+ import android.content.Context
4
+ import android.widget.ImageView
5
+ import coil3.ImageLoader
6
+ import coil3.load
7
+ import com.margelo.nitro.core.Promise
8
+ import com.margelo.nitro.image.HybridImageSpec
9
+ import com.margelo.nitro.image.HybridImageLoaderSpec
10
+ import com.margelo.nitro.image.HybridNitroImageViewSpec
11
+
12
+ class HybridWebImageLoader(private val imageLoader: ImageLoader,
13
+ private val url: String,
14
+ private val options: AsyncImageLoadOptions?,
15
+ private val context: Context) : HybridImageLoaderSpec() {
16
+ override fun loadImage(): Promise<HybridImageSpec> {
17
+ return imageLoader.loadImageAsync(url, options, context)
18
+ }
19
+
20
+ override fun requestImage(forView: HybridNitroImageViewSpec) {
21
+ val imageView = forView.view as? ImageView ?: return
22
+
23
+ imageView.load(url, imageLoader) {
24
+ this.applyOptions(options)
25
+ }
26
+ imageView.load(url)
27
+ }
28
+
29
+ override fun dropImage(forView: HybridNitroImageViewSpec) {
30
+ // Coil automatically handles recycling here - I _think_.
31
+ }
32
+ }
@@ -0,0 +1,37 @@
1
+ package com.margelo.nitro.web.image
2
+
3
+ import android.content.Context
4
+ import coil3.BitmapImage
5
+ import coil3.Image
6
+ import coil3.ImageLoader
7
+ import coil3.request.ImageRequest
8
+ import com.margelo.nitro.core.Promise
9
+ import com.margelo.nitro.image.HybridImage
10
+ import com.margelo.nitro.image.HybridImageSpec
11
+
12
+ suspend fun ImageLoader.loadCoilImageAsync(url: String,
13
+ options: AsyncImageLoadOptions?,
14
+ context: Context): Image {
15
+ // 1. Create the Coil Request
16
+ val request = ImageRequest.Builder(context)
17
+ .data(url)
18
+ .applyOptions(options)
19
+ .build()
20
+ // 2. Execute it (async)
21
+ val result = this.execute(request)
22
+ val image = result.image ?: throw Error("Failed to load Image!")
23
+ return image
24
+ }
25
+
26
+ fun ImageLoader.loadImageAsync(url: String,
27
+ options: AsyncImageLoadOptions?,
28
+ context: Context
29
+ ): Promise<HybridImageSpec> {
30
+ return Promise.async {
31
+ // 1. Load the coil image
32
+ val image = loadCoilImageAsync(url, options, context)
33
+ // 3. Downcast to a Bitmap - if that fails, it might be an Animated Image...
34
+ val bitmap = image as? BitmapImage ?: throw Error("Requested Image is not a Bitmap!")
35
+ return@async HybridImage(bitmap.bitmap)
36
+ }
37
+ }
@@ -0,0 +1,58 @@
1
+ package com.margelo.nitro.web.image
2
+
3
+ import coil3.annotation.ExperimentalCoilApi
4
+ import coil3.decode.BlackholeDecoder
5
+ import coil3.request.CachePolicy
6
+ import coil3.request.ImageRequest
7
+ import coil3.size.Precision
8
+
9
+ @OptIn(ExperimentalCoilApi::class)
10
+ fun ImageRequest.Builder.applyOptions(options: AsyncImageLoadOptions?): ImageRequest.Builder {
11
+ if (options == null) return this
12
+ var result = this
13
+
14
+ if (options.priority != null) {
15
+ options.priority.toCoroutineContext()?.let { context ->
16
+ result = result.coroutineContext(context)
17
+ }
18
+ }
19
+
20
+ if (options.forceRefresh == true) {
21
+ // don't allow reading from cache, only writing.
22
+ result = result.diskCachePolicy(CachePolicy.WRITE_ONLY)
23
+ result = result.memoryCachePolicy(CachePolicy.WRITE_ONLY)
24
+ result = result.networkCachePolicy(CachePolicy.WRITE_ONLY)
25
+ }
26
+
27
+ if (options.continueInBackground == true) {
28
+ // TODO: Implement .continueInBackground
29
+ }
30
+
31
+ if (options.allowInvalidSSLCertificates == true) {
32
+ // TODO: Implement .allowInvalidSSLCertificates
33
+ }
34
+
35
+ if (options.scaleDownLargeImages == true) {
36
+ // Limit to 4096x4096 (~60 MB)
37
+ result = result.size(4096, 4096)
38
+ result = result.precision(Precision.INEXACT)
39
+ }
40
+
41
+ if (options.queryMemoryDataSync == true) {
42
+ // TODO: Implement .queryMemoryDataSync
43
+ }
44
+
45
+ if (options.queryDiskDataSync == true) {
46
+ // TODO: Implement .queryDiskDataSync
47
+ }
48
+
49
+ if (options.decodeImage == false) {
50
+ result = result.decoderFactory(BlackholeDecoder.Factory())
51
+ }
52
+
53
+ if (options.cacheKey != null) {
54
+ result = result.diskCacheKey(options.cacheKey)
55
+ }
56
+
57
+ return result
58
+ }
@@ -0,0 +1,44 @@
1
+ package com.margelo.nitro.web.image;
2
+
3
+ import android.util.Log;
4
+
5
+ import androidx.annotation.NonNull;
6
+ import androidx.annotation.Nullable;
7
+
8
+ import com.facebook.react.bridge.NativeModule;
9
+ import com.facebook.react.bridge.ReactApplicationContext;
10
+ import com.facebook.react.module.model.ReactModuleInfoProvider;
11
+ import com.facebook.react.TurboReactPackage;
12
+ import com.facebook.react.uimanager.ViewManager;
13
+ import com.margelo.nitro.core.HybridObject;
14
+
15
+ import java.util.ArrayList;
16
+ import java.util.HashMap;
17
+ import java.util.List;
18
+ import java.util.function.Supplier;
19
+
20
+ public class NitroWebImagePackage extends TurboReactPackage {
21
+ @Nullable
22
+ @Override
23
+ public NativeModule getModule(String name, ReactApplicationContext reactContext) {
24
+ return null;
25
+ }
26
+
27
+ @Override
28
+ public ReactModuleInfoProvider getReactModuleInfoProvider() {
29
+ return () -> {
30
+ return new HashMap<>();
31
+ };
32
+ }
33
+
34
+
35
+ @Override
36
+ public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
37
+ List<ViewManager> viewManagers = new ArrayList<>();
38
+ return viewManagers;
39
+ }
40
+
41
+ static {
42
+ NitroWebImageOnLoad.initializeNative();
43
+ }
44
+ }
@@ -0,0 +1,66 @@
1
+ //
2
+ // AsyncImageLoadOptions+toSDWebImageOptions.swift
3
+ // NitroWebImage
4
+ //
5
+ // Created by Marc Rousavy on 30.06.25.
6
+ //
7
+
8
+ import Foundation
9
+ import SDWebImage
10
+
11
+ extension AsyncImageLoadOptions {
12
+ func toSDWebImageOptions() -> SDWebImageOptions {
13
+ var options: SDWebImageOptions = []
14
+
15
+ switch priority {
16
+ case .default, .none:
17
+ break
18
+ case .low:
19
+ options.insert(.lowPriority)
20
+ case .high:
21
+ options.insert(.highPriority)
22
+ }
23
+
24
+ if forceRefresh == true {
25
+ options.insert(.refreshCached)
26
+ }
27
+
28
+ if continueInBackground == true {
29
+ options.insert(.continueInBackground)
30
+ }
31
+
32
+ if allowInvalidSSLCertificates == true {
33
+ options.insert(.allowInvalidSSLCertificates)
34
+ }
35
+
36
+ if scaleDownLargeImages == true {
37
+ options.insert(.scaleDownLargeImages)
38
+ }
39
+
40
+ if queryMemoryDataSync == true {
41
+ options.insert(.queryMemoryDataSync)
42
+ }
43
+
44
+ if queryDiskDataSync == true {
45
+ options.insert(.queryDiskDataSync)
46
+ }
47
+
48
+ if decodeImage == false {
49
+ options.insert(.avoidDecodeImage)
50
+ }
51
+
52
+ return options
53
+ }
54
+
55
+ func toSDWebImageContext() -> [SDWebImageContextOption: Any] {
56
+ var context: [SDWebImageContextOption: Any] = [:]
57
+
58
+ if let cacheKey {
59
+ context[.cacheKeyFilter] = SDWebImageCacheKeyFilter { _ in
60
+ return cacheKey
61
+ }
62
+ }
63
+
64
+ return context
65
+ }
66
+ }
package/ios/Bridge.h ADDED
@@ -0,0 +1,8 @@
1
+ //
2
+ // Bridge.h
3
+ // NitroWebImage
4
+ //
5
+ // Created by Marc Rousavy on 22.07.24.
6
+ //
7
+
8
+ #pragma once
@@ -0,0 +1,32 @@
1
+ //
2
+ // HybridWebImageFactory.swift
3
+ // react-native-nitro-web-image
4
+ //
5
+ // Created by Marc Rousavy on 10.06.25.
6
+ //
7
+
8
+ import Foundation
9
+ import NitroModules
10
+ import SDWebImage
11
+ import NitroImage
12
+
13
+ class HybridWebImageFactory: HybridWebImageFactorySpec {
14
+ func loadFromURLAsync(url: String, options: AsyncImageLoadOptions?) throws -> Promise<any HybridImageSpec> {
15
+ throw RuntimeError.error(withMessage: "Not yet implemented!")
16
+ }
17
+
18
+ private let queue = DispatchQueue(label: "image-loader",
19
+ qos: .default,
20
+ attributes: .concurrent)
21
+
22
+ /**
23
+ * Load Image from URL
24
+ */
25
+ func createWebImageLoader(url urlString: String, options: AsyncImageLoadOptions?) throws -> any HybridImageLoaderSpec {
26
+ guard let url = URL(string: urlString) else {
27
+ throw RuntimeError.error(withMessage: "URL string \"\(urlString)\" is not a valid URL!")
28
+ }
29
+
30
+ return HybridWebImageLoader(url: url, options: options)
31
+ }
32
+ }
@@ -0,0 +1,54 @@
1
+ //
2
+ // HybridWebImageLoader.swift
3
+ // NitroWebImage
4
+ //
5
+ // Created by Marc Rousavy on 28.07.25.
6
+ //
7
+
8
+ import NitroModules
9
+ import SDWebImage
10
+ import NitroImage
11
+
12
+ fileprivate class HybridImage: HybridImageSpec, NativeImage {
13
+ let uiImage: UIImage
14
+ init(uiImage: UIImage) {
15
+ self.uiImage = uiImage
16
+ super.init()
17
+ }
18
+ }
19
+
20
+ class HybridWebImageLoader: HybridImageLoaderSpec {
21
+ private let url: URL
22
+ private let options: AsyncImageLoadOptions?
23
+
24
+ init(url: URL, options: AsyncImageLoadOptions?) {
25
+ self.url = url
26
+ self.options = options
27
+ super.init()
28
+ }
29
+
30
+ func loadImage() throws -> Promise<(any HybridImageSpec)> {
31
+ return Promise.async {
32
+ let webImageOptions = self.options?.toSDWebImageOptions() ?? []
33
+ let webImageContext = self.options?.toSDWebImageContext() ?? [:]
34
+ let uiImage = try await SDWebImageManager.shared.loadImage(with: self.url,
35
+ options: webImageOptions,
36
+ context: webImageContext)
37
+ return HybridImage(uiImage: uiImage)
38
+ }
39
+ }
40
+
41
+ func requestImage(forView view: (any HybridNitroImageViewSpec)) throws {
42
+ guard let view = view as? NativeImageView else { throw RuntimeError.error(withMessage: "Invalid view type!") }
43
+
44
+ let webImageOptions = options?.toSDWebImageOptions() ?? []
45
+ view.imageView.sd_setImage(with: url,
46
+ placeholderImage: nil,
47
+ options: webImageOptions,
48
+ context: nil)
49
+ }
50
+
51
+ func dropImage(forView view: (any HybridNitroImageViewSpec)) throws {
52
+ // TODO: Do we need to reset the image here or not?
53
+ }
54
+ }
@@ -0,0 +1,30 @@
1
+ //
2
+ // SDWebImageManager+loadImage.swift
3
+ // NitroWebImage
4
+ //
5
+ // Created by Marc Rousavy on 30.06.25.
6
+ //
7
+
8
+ import Foundation
9
+ import SDWebImage
10
+ import NitroModules
11
+
12
+ extension SDWebImageManager {
13
+ func loadImage(with url: URL, options: SDWebImageOptions) async throws -> UIImage {
14
+ return try await withUnsafeThrowingContinuation { continuation in
15
+ self.loadImage(with: url, options: options) { current, total, url in
16
+ print("\(url): Loaded \(current)/\(total) bytes")
17
+ } completed: { image, data, error, cacheType, finished, url in
18
+ if let image {
19
+ continuation.resume(returning: image)
20
+ } else {
21
+ if let error {
22
+ continuation.resume(throwing: error)
23
+ } else {
24
+ continuation.resume(throwing: RuntimeError.error(withMessage: "No Image or error was returned!"))
25
+ }
26
+ }
27
+ }
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.WebImages = void 0;
7
+ var _reactNativeNitroModules = require("react-native-nitro-modules");
8
+ const WebImages = exports.WebImages = _reactNativeNitroModules.NitroModules.createHybridObject("WebImageFactory");
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNativeNitroModules","require","WebImages","exports","NitroModules","createHybridObject"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;AAAA,IAAAA,wBAAA,GAAAC,OAAA;AAGO,MAAMC,SAAS,GAAAC,OAAA,CAAAD,SAAA,GAClBE,qCAAY,CAACC,kBAAkB,CAAkB,iBAAiB,CAAC","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ //# sourceMappingURL=WebImageFactory.nitro.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["specs/WebImageFactory.nitro.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ import { NitroModules } from "react-native-nitro-modules";
4
+ export const WebImages = NitroModules.createHybridObject("WebImageFactory");
5
+ //# sourceMappingURL=index.js.map