@abeman/react-native-nitro-blur 0.1.0

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 (86) hide show
  1. package/LICENSE +20 -0
  2. package/NitroBlur.podspec +29 -0
  3. package/README.md +200 -0
  4. package/android/CMakeLists.txt +24 -0
  5. package/android/build.gradle +120 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/cpp/cpp-adapter.cpp +6 -0
  8. package/android/src/main/java/com/margelo/nitro/nitroblur/NitroBlur.kt +229 -0
  9. package/android/src/main/java/com/margelo/nitro/nitroblur/NitroBlurPackage.kt +31 -0
  10. package/android/src/main/java/com/margelo/nitro/nitroblur/NitroBlurTarget.kt +149 -0
  11. package/android/src/main/java/com/margelo/nitro/nitroblur/NitroBlurTargetViewGroupManager.kt +47 -0
  12. package/android/src/main/java/com/margelo/nitro/nitroblur/TintStyle.kt +85 -0
  13. package/ios/NitroBlur.swift +173 -0
  14. package/ios/NitroBlurTarget.swift +5 -0
  15. package/lib/module/NitroBlur.nitro.js +4 -0
  16. package/lib/module/NitroBlur.nitro.js.map +1 -0
  17. package/lib/module/NitroBlurTarget.nitro.js +4 -0
  18. package/lib/module/NitroBlurTarget.nitro.js.map +1 -0
  19. package/lib/module/index.js +114 -0
  20. package/lib/module/index.js.map +1 -0
  21. package/lib/module/package.json +1 -0
  22. package/lib/typescript/package.json +1 -0
  23. package/lib/typescript/src/NitroBlur.nitro.d.ts +25 -0
  24. package/lib/typescript/src/NitroBlur.nitro.d.ts.map +1 -0
  25. package/lib/typescript/src/NitroBlurTarget.nitro.d.ts +7 -0
  26. package/lib/typescript/src/NitroBlurTarget.nitro.d.ts.map +1 -0
  27. package/lib/typescript/src/index.d.ts +201 -0
  28. package/lib/typescript/src/index.d.ts.map +1 -0
  29. package/nitro.json +33 -0
  30. package/nitrogen/generated/android/c++/JBlurMethod.hpp +61 -0
  31. package/nitrogen/generated/android/c++/JBlurTint.hpp +115 -0
  32. package/nitrogen/generated/android/c++/JHybridNitroBlurSpec.cpp +99 -0
  33. package/nitrogen/generated/android/c++/JHybridNitroBlurSpec.hpp +72 -0
  34. package/nitrogen/generated/android/c++/JHybridNitroBlurTargetSpec.cpp +49 -0
  35. package/nitrogen/generated/android/c++/JHybridNitroBlurTargetSpec.hpp +63 -0
  36. package/nitrogen/generated/android/c++/views/JHybridNitroBlurStateUpdater.cpp +72 -0
  37. package/nitrogen/generated/android/c++/views/JHybridNitroBlurStateUpdater.hpp +49 -0
  38. package/nitrogen/generated/android/c++/views/JHybridNitroBlurTargetStateUpdater.cpp +53 -0
  39. package/nitrogen/generated/android/c++/views/JHybridNitroBlurTargetStateUpdater.hpp +49 -0
  40. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/BlurMethod.kt +24 -0
  41. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/BlurTint.kt +42 -0
  42. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/HybridNitroBlurSpec.kt +81 -0
  43. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/HybridNitroBlurTargetSpec.kt +53 -0
  44. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/nitroblurOnLoad.kt +35 -0
  45. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/views/HybridNitroBlurManager.kt +80 -0
  46. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/views/HybridNitroBlurStateUpdater.kt +23 -0
  47. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/views/HybridNitroBlurTargetManager.kt +80 -0
  48. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/views/HybridNitroBlurTargetStateUpdater.kt +23 -0
  49. package/nitrogen/generated/android/nitroblur+autolinking.cmake +87 -0
  50. package/nitrogen/generated/android/nitroblur+autolinking.gradle +27 -0
  51. package/nitrogen/generated/android/nitroblurOnLoad.cpp +74 -0
  52. package/nitrogen/generated/android/nitroblurOnLoad.hpp +34 -0
  53. package/nitrogen/generated/ios/NitroBlur+autolinking.rb +60 -0
  54. package/nitrogen/generated/ios/NitroBlur-Swift-Cxx-Bridge.cpp +50 -0
  55. package/nitrogen/generated/ios/NitroBlur-Swift-Cxx-Bridge.hpp +57 -0
  56. package/nitrogen/generated/ios/NitroBlur-Swift-Cxx-Umbrella.hpp +52 -0
  57. package/nitrogen/generated/ios/NitroBlurAutolinking.mm +41 -0
  58. package/nitrogen/generated/ios/NitroBlurAutolinking.swift +38 -0
  59. package/nitrogen/generated/ios/c++/HybridNitroBlurSpecSwift.cpp +11 -0
  60. package/nitrogen/generated/ios/c++/HybridNitroBlurSpecSwift.hpp +110 -0
  61. package/nitrogen/generated/ios/c++/HybridNitroBlurTargetSpecSwift.cpp +11 -0
  62. package/nitrogen/generated/ios/c++/HybridNitroBlurTargetSpecSwift.hpp +75 -0
  63. package/nitrogen/generated/ios/c++/views/HybridNitroBlurComponent.mm +142 -0
  64. package/nitrogen/generated/ios/c++/views/HybridNitroBlurTargetComponent.mm +118 -0
  65. package/nitrogen/generated/ios/swift/BlurMethod.swift +44 -0
  66. package/nitrogen/generated/ios/swift/BlurTint.swift +116 -0
  67. package/nitrogen/generated/ios/swift/HybridNitroBlurSpec.swift +59 -0
  68. package/nitrogen/generated/ios/swift/HybridNitroBlurSpec_cxx.swift +200 -0
  69. package/nitrogen/generated/ios/swift/HybridNitroBlurTargetSpec.swift +55 -0
  70. package/nitrogen/generated/ios/swift/HybridNitroBlurTargetSpec_cxx.swift +147 -0
  71. package/nitrogen/generated/shared/c++/BlurMethod.hpp +80 -0
  72. package/nitrogen/generated/shared/c++/BlurTint.hpp +152 -0
  73. package/nitrogen/generated/shared/c++/HybridNitroBlurSpec.cpp +30 -0
  74. package/nitrogen/generated/shared/c++/HybridNitroBlurSpec.hpp +75 -0
  75. package/nitrogen/generated/shared/c++/HybridNitroBlurTargetSpec.cpp +21 -0
  76. package/nitrogen/generated/shared/c++/HybridNitroBlurTargetSpec.hpp +62 -0
  77. package/nitrogen/generated/shared/c++/views/HybridNitroBlurComponent.cpp +127 -0
  78. package/nitrogen/generated/shared/c++/views/HybridNitroBlurComponent.hpp +116 -0
  79. package/nitrogen/generated/shared/c++/views/HybridNitroBlurTargetComponent.cpp +72 -0
  80. package/nitrogen/generated/shared/c++/views/HybridNitroBlurTargetComponent.hpp +109 -0
  81. package/nitrogen/generated/shared/json/NitroBlurConfig.json +14 -0
  82. package/nitrogen/generated/shared/json/NitroBlurTargetConfig.json +9 -0
  83. package/package.json +174 -0
  84. package/src/NitroBlur.nitro.ts +56 -0
  85. package/src/NitroBlurTarget.nitro.ts +13 -0
  86. package/src/index.tsx +215 -0
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 huynq2
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
@@ -0,0 +1,29 @@
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 = "NitroBlur"
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 }
14
+ s.source = { :git => "https://github.com/huynq1175/react-native-nitro-blur.git", :tag => "#{s.version}" }
15
+
16
+ s.source_files = [
17
+ "ios/**/*.{swift}",
18
+ "ios/**/*.{m,mm}",
19
+ "cpp/**/*.{hpp,cpp}",
20
+ ]
21
+
22
+ s.dependency 'React-jsi'
23
+ s.dependency 'React-callinvoker'
24
+
25
+ load 'nitrogen/generated/ios/NitroBlur+autolinking.rb'
26
+ add_nitrogen_files(s)
27
+
28
+ install_modules_dependencies(s)
29
+ end
package/README.md ADDED
@@ -0,0 +1,200 @@
1
+ # @abeman/react-native-nitro-blur
2
+
3
+ A high-performance blur view component for React Native, built with [Nitro Modules](https://nitro.margelo.com/) (JSI). Drop-in alternative to `expo-blur` without any Expo dependency.
4
+
5
+ ## Features
6
+
7
+ - Native `UIVisualEffectView` blur on iOS with adjustable intensity
8
+ - Real blur on Android via [Dimezis BlurView](https://github.com/Dimezis/BlurView) library
9
+ - 21 tint styles matching Apple's iOS blur effects
10
+ - `BlurTargetView` for Android real-blur support (same pattern as expo-blur)
11
+ - Reanimated-compatible style animations
12
+ - Compatible with React Native 0.76+ (New Architecture)
13
+
14
+ ## Installation
15
+
16
+ ```sh
17
+ npm install @abeman/react-native-nitro-blur react-native-nitro-modules
18
+ ```
19
+
20
+ > `react-native-nitro-modules` is a required peer dependency — this library is built on [Nitro Modules](https://nitro.margelo.com/).
21
+
22
+ For iOS, run `pod install` in the `ios/` directory after installing.
23
+
24
+ ## Usage
25
+
26
+ ### Basic (iOS + Android tint overlay)
27
+
28
+ ```tsx
29
+ import { BlurView } from '@abeman/react-native-nitro-blur';
30
+
31
+ function MyComponent() {
32
+ return (
33
+ <View style={{ flex: 1 }}>
34
+ <Image source={{ uri: 'https://example.com/photo.jpg' }} style={StyleSheet.absoluteFill} />
35
+ <BlurView
36
+ tint="light"
37
+ intensity={80}
38
+ style={StyleSheet.absoluteFill}
39
+ />
40
+ </View>
41
+ );
42
+ }
43
+ ```
44
+
45
+ ### With Real Blur on Android (BlurTargetView)
46
+
47
+ To enable real blur on Android, wrap the content you want to blur with `BlurTargetView` and pass a ref to `BlurView`:
48
+
49
+ ```tsx
50
+ import { useRef } from 'react';
51
+ import { View, StyleSheet, Image } from 'react-native';
52
+ import { BlurView, BlurTargetView } from '@abeman/react-native-nitro-blur';
53
+
54
+ function MyComponent() {
55
+ const blurTargetRef = useRef(null);
56
+
57
+ return (
58
+ <BlurTargetView ref={blurTargetRef} style={{ flex: 1 }}>
59
+ <Image source={{ uri: 'https://example.com/photo.jpg' }} style={StyleSheet.absoluteFill} />
60
+ <BlurView
61
+ tint="light"
62
+ intensity={80}
63
+ blurMethod="dimezisBlurView"
64
+ blurTarget={blurTargetRef}
65
+ style={StyleSheet.absoluteFill}
66
+ />
67
+ </BlurTargetView>
68
+ );
69
+ }
70
+ ```
71
+
72
+ > On iOS, `BlurTargetView` is just a regular `View` and `blurTarget`/`blurMethod` are no-ops — iOS uses `UIVisualEffectView` which naturally blurs whatever is behind it.
73
+
74
+ ## Props
75
+
76
+ ### `BlurView`
77
+
78
+ | Prop | Type | Default | Platform | Description |
79
+ |------|------|---------|----------|-------------|
80
+ | `tint` | `BlurTint` | `'default'` | iOS + Android | The tint style applied to the blur effect. |
81
+ | `intensity` | `number` | `50` | iOS + Android | Blur intensity from `1` to `100`. |
82
+ | `blurReductionFactor` | `number` | `4` | Android | Divides blur intensity on Android to match iOS. |
83
+ | `blurMethod` | `BlurMethod` | `'none'` | Android | Blur implementation to use on Android. |
84
+ | `blurTarget` | `RefObject<View>` | — | Android | Ref to a `BlurTargetView` wrapping content to blur. |
85
+
86
+ Plus all standard `View` props (`style`, `children`, etc.).
87
+
88
+ ### `BlurTargetView`
89
+
90
+ Accepts all standard `View` props. On Android, this is a native container view that enables the Dimezis BlurView to capture and blur its content. On iOS, it's just a regular `View`.
91
+
92
+ ### `BlurTint` values
93
+
94
+ `'light'` | `'dark'` | `'default'` | `'extraLight'` | `'regular'` | `'prominent'` | `'systemUltraThinMaterial'` | `'systemThinMaterial'` | `'systemMaterial'` | `'systemThickMaterial'` | `'systemChromeMaterial'` | `'systemUltraThinMaterialLight'` | `'systemThinMaterialLight'` | `'systemMaterialLight'` | `'systemThickMaterialLight'` | `'systemChromeMaterialLight'` | `'systemUltraThinMaterialDark'` | `'systemThinMaterialDark'` | `'systemMaterialDark'` | `'systemThickMaterialDark'` | `'systemChromeMaterialDark'`
95
+
96
+ ### `BlurMethod` values (Android only)
97
+
98
+ | Method | Description |
99
+ |--------|-------------|
100
+ | `'none'` | Semi-transparent tint overlay only (no real blur). Default. |
101
+ | `'dimezisBlurView'` | Real blur via [Dimezis BlurView](https://github.com/Dimezis/BlurView). Requires `blurTarget`. May decrease performance on SDK 30 and below. |
102
+ | `'dimezisBlurViewSdk31Plus'` | Real blur on SDK 31+ only, falls back to `'none'` on older versions. Requires `blurTarget`. |
103
+
104
+ ## Animating with Reanimated
105
+
106
+ ### Style animations (works)
107
+
108
+ `useAnimatedStyle` works normally for style props (transform, opacity, etc.):
109
+
110
+ ```tsx
111
+ import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
112
+ import { BlurView } from '@abeman/react-native-nitro-blur';
113
+
114
+ const AnimatedBlurView = Animated.createAnimatedComponent(BlurView);
115
+
116
+ function MyComponent() {
117
+ const opacity = useSharedValue(1);
118
+ const animatedStyle = useAnimatedStyle(() => ({ opacity: opacity.value }));
119
+
120
+ return (
121
+ <AnimatedBlurView
122
+ tint="light"
123
+ intensity={80}
124
+ style={[styles.blur, animatedStyle]}
125
+ />
126
+ );
127
+ }
128
+ ```
129
+
130
+ ### Animating `intensity` (workaround required)
131
+
132
+ > **`animatedProps` does NOT work with Nitro HybridViews.** Reanimated's `animatedProps` calls native `updateProps` directly on the ShadowNode with `folly::dynamic` values, but Nitro's Fabric component descriptor expects `jsi::Value`. This is a fundamental incompatibility at the C++ level.
133
+
134
+ Use `useAnimatedReaction` with `runOnJS` to bridge animated values to React state:
135
+
136
+ ```tsx
137
+ import { useState } from 'react';
138
+ import Animated, {
139
+ useSharedValue,
140
+ useAnimatedReaction,
141
+ runOnJS,
142
+ withTiming,
143
+ } from 'react-native-reanimated';
144
+ import { BlurView } from '@abeman/react-native-nitro-blur';
145
+
146
+ function MyComponent() {
147
+ const progress = useSharedValue(0);
148
+ const [intensity, setIntensity] = useState(0);
149
+
150
+ useAnimatedReaction(
151
+ () => progress.value * 100,
152
+ (value) => runOnJS(setIntensity)(value)
153
+ );
154
+
155
+ return (
156
+ <BlurView
157
+ tint="light"
158
+ intensity={intensity}
159
+ style={StyleSheet.absoluteFill}
160
+ />
161
+ );
162
+ }
163
+ ```
164
+
165
+ ## Platform behavior
166
+
167
+ ### iOS
168
+ Uses `UIVisualEffectView` with `UIViewPropertyAnimator` for smooth, adjustable blur intensity. All tint styles map directly to native `UIBlurEffect.Style` values.
169
+
170
+ ### Android
171
+ - **`blurMethod: 'none'`** (default): Renders a semi-transparent tinted overlay.
172
+ - **`blurMethod: 'dimezisBlurView'`**: Uses the [Dimezis BlurView](https://github.com/Dimezis/BlurView) library for real blur. Requires wrapping content in `BlurTargetView` and passing a ref via the `blurTarget` prop.
173
+ - **`blurMethod: 'dimezisBlurViewSdk31Plus'`**: Same as above but only on SDK 31+; older versions fall back to tint overlay.
174
+
175
+ The `blurReductionFactor` prop helps match the perceived blur intensity between iOS and Android.
176
+
177
+ ## Migrating from expo-blur
178
+
179
+ | expo-blur | @abeman/react-native-nitro-blur |
180
+ |-----------|------------------------|
181
+ | `import { BlurView } from 'expo-blur'` | `import { BlurView } from '@abeman/react-native-nitro-blur'` |
182
+ | `import { BlurTargetView } from 'expo-blur'` | `import { BlurTargetView } from '@abeman/react-native-nitro-blur'` |
183
+ | `experimentalBlurMethod` | `blurMethod` (deprecated alias supported) |
184
+ | `Animated.createAnimatedComponent(BlurView)` + `animatedProps` | Use `useAnimatedReaction` + `runOnJS` for prop animations (see above) |
185
+
186
+ The API is designed to be compatible. Replace imports and it should work. The only difference is the Reanimated `animatedProps` limitation — use `useAnimatedReaction` instead.
187
+
188
+ ## Contributing
189
+
190
+ - [Development workflow](CONTRIBUTING.md#development-workflow)
191
+ - [Sending a pull request](CONTRIBUTING.md#sending-a-pull-request)
192
+ - [Code of conduct](CODE_OF_CONDUCT.md)
193
+
194
+ ## License
195
+
196
+ MIT
197
+
198
+ ---
199
+
200
+ Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
@@ -0,0 +1,24 @@
1
+ project(nitroblur)
2
+ cmake_minimum_required(VERSION 3.9.0)
3
+
4
+ set(PACKAGE_NAME nitroblur)
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 src/main/cpp/cpp-adapter.cpp)
10
+
11
+ # Add Nitrogen specs :)
12
+ include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/nitroblur+autolinking.cmake)
13
+
14
+ # Set up local includes
15
+ include_directories("src/main/cpp" "../cpp")
16
+
17
+ find_library(LOG_LIB log)
18
+
19
+ # Link all libraries together
20
+ target_link_libraries(
21
+ ${PACKAGE_NAME}
22
+ ${LOG_LIB}
23
+ android # <-- Android core
24
+ )
@@ -0,0 +1,120 @@
1
+ buildscript {
2
+ ext.NitroBlur = [
3
+ kotlinVersion: "2.0.21",
4
+ minSdkVersion: 24,
5
+ compileSdkVersion: 36,
6
+ targetSdkVersion: 36
7
+ ]
8
+
9
+ ext.getExtOrDefault = { prop ->
10
+ if (rootProject.ext.has(prop)) {
11
+ return rootProject.ext.get(prop)
12
+ }
13
+
14
+ return NitroBlur[prop]
15
+ }
16
+
17
+ repositories {
18
+ google()
19
+ mavenCentral()
20
+ maven { url 'https://jitpack.io' }
21
+ }
22
+
23
+ dependencies {
24
+ classpath "com.android.tools.build:gradle:8.7.2"
25
+ // noinspection DifferentKotlinGradleVersion
26
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
27
+ }
28
+ }
29
+
30
+ def reactNativeArchitectures() {
31
+ def value = rootProject.getProperties().get("reactNativeArchitectures")
32
+ return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
33
+ }
34
+
35
+ apply plugin: "com.android.library"
36
+ apply plugin: "kotlin-android"
37
+ apply from: '../nitrogen/generated/android/nitroblur+autolinking.gradle'
38
+
39
+ apply plugin: "com.facebook.react"
40
+
41
+ android {
42
+ namespace "com.margelo.nitro.nitroblur"
43
+
44
+ compileSdkVersion getExtOrDefault("compileSdkVersion")
45
+
46
+ defaultConfig {
47
+ minSdkVersion getExtOrDefault("minSdkVersion")
48
+ targetSdkVersion getExtOrDefault("targetSdkVersion")
49
+
50
+ externalNativeBuild {
51
+ cmake {
52
+ cppFlags "-frtti -fexceptions -Wall -fstack-protector-all"
53
+ arguments "-DANDROID_STL=c++_shared", "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
54
+ abiFilters (*reactNativeArchitectures())
55
+
56
+ buildTypes {
57
+ debug {
58
+ cppFlags "-O1 -g"
59
+ }
60
+ release {
61
+ cppFlags "-O2"
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
67
+
68
+ externalNativeBuild {
69
+ cmake {
70
+ path "CMakeLists.txt"
71
+ }
72
+ }
73
+
74
+ packagingOptions {
75
+ excludes = [
76
+ "META-INF",
77
+ "META-INF/**",
78
+ "**/libc++_shared.so",
79
+ "**/libfbjni.so",
80
+ "**/libjsi.so",
81
+ "**/libfolly_json.so",
82
+ "**/libfolly_runtime.so",
83
+ "**/libglog.so",
84
+ "**/libhermes.so",
85
+ "**/libhermes-executor-debug.so",
86
+ "**/libhermes_executor.so",
87
+ "**/libreactnative.so",
88
+ "**/libreactnativejni.so",
89
+ "**/libturbomodulejsijni.so",
90
+ "**/libreact_nativemodule_core.so",
91
+ "**/libjscexecutor.so"
92
+ ]
93
+ }
94
+
95
+ buildFeatures {
96
+ buildConfig true
97
+ prefab true
98
+ }
99
+
100
+ buildTypes {
101
+ release {
102
+ minifyEnabled false
103
+ }
104
+ }
105
+
106
+ lint {
107
+ disable "GradleCompatible"
108
+ }
109
+
110
+ compileOptions {
111
+ sourceCompatibility JavaVersion.VERSION_1_8
112
+ targetCompatibility JavaVersion.VERSION_1_8
113
+ }
114
+ }
115
+
116
+ dependencies {
117
+ implementation "com.facebook.react:react-android"
118
+ implementation project(":react-native-nitro-modules")
119
+ implementation 'com.github.Dimezis:BlurView:version-3.1.0'
120
+ }
@@ -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 "nitroblurOnLoad.hpp"
3
+
4
+ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
5
+ return margelo::nitro::nitroblur::initialize(vm);
6
+ }
@@ -0,0 +1,229 @@
1
+ package com.margelo.nitro.nitroblur
2
+
3
+ import android.graphics.Color
4
+ import android.os.Build
5
+ import android.view.View
6
+ import android.view.ViewGroup
7
+ import com.facebook.proguard.annotations.DoNotStrip
8
+ import com.facebook.react.uimanager.ThemedReactContext
9
+ import eightbitlab.com.blurview.BlurView
10
+
11
+ private enum class BlurViewConfiguration {
12
+ /** BlurView is yet to be configured. */
13
+ UNCONFIGURED,
14
+ /** BlurView has been configured to use the NONE blur method. */
15
+ NONE,
16
+ /** BlurView has been configured to use the DIMEZIS blur method. */
17
+ DIMEZIS
18
+ }
19
+
20
+ @DoNotStrip
21
+ class HybridNitroBlur(val context: ThemedReactContext) : HybridNitroBlurSpec() {
22
+
23
+ private val containerView = BlurContainerView(context)
24
+
25
+ private val blurView = BlurView(context).also {
26
+ it.layoutParams = ViewGroup.LayoutParams(
27
+ ViewGroup.LayoutParams.MATCH_PARENT,
28
+ ViewGroup.LayoutParams.MATCH_PARENT
29
+ )
30
+ containerView.addView(it)
31
+ }
32
+
33
+ override val view: View get() = containerView
34
+
35
+ // Internal state
36
+ private var _blurMethod: BlurMethod = BlurMethod.NONE
37
+ private var _blurReduction = 4.0
38
+ private var _blurRadius = 50.0
39
+ private var _tint: BlurTint = BlurTint.DEFAULT
40
+ private var _blurTargetId = 0.0
41
+ private var blurConfiguration = BlurViewConfiguration.NONE
42
+ private var blurTargetView: eightbitlab.com.blurview.BlurTarget? = null
43
+
44
+ // region Props
45
+
46
+ override var tint: BlurTint
47
+ get() = _tint
48
+ set(value) {
49
+ _tint = value
50
+ applyTint()
51
+ }
52
+
53
+ override var intensity: Double
54
+ get() = _blurRadius
55
+ set(value) {
56
+ _blurRadius = value
57
+ setBlurRadius(value)
58
+ }
59
+
60
+ override var blurReductionFactor: Double
61
+ get() = _blurReduction
62
+ set(value) {
63
+ _blurReduction = value
64
+ setBlurRadius(_blurRadius)
65
+ }
66
+
67
+ override var blurTargetId: Double
68
+ get() = _blurTargetId
69
+ set(value) {
70
+ val intId = value.toInt()
71
+ val currentIntId = _blurTargetId.toInt()
72
+ if (intId == currentIntId) return
73
+
74
+ _blurTargetId = value
75
+
76
+ if (intId <= 0) {
77
+ blurTargetView = null
78
+ } else {
79
+ // Find the blur target view by its React Native tag (view ID)
80
+ val rootView = context.currentActivity?.window?.decorView
81
+ val targetView = rootView?.findViewById<View>(intId)
82
+ val targetContainer = targetView as? BlurTargetContainer
83
+ blurTargetView = targetContainer?.blurTargetView
84
+ }
85
+
86
+ configureBlurView()
87
+ }
88
+
89
+ override var blurMethod: BlurMethod
90
+ get() = _blurMethod
91
+ set(value) {
92
+ _blurMethod = value
93
+
94
+ // Re-configure if the method was changed from none -> dimezis at runtime
95
+ if (value != BlurMethod.NONE && blurConfiguration != BlurViewConfiguration.DIMEZIS) {
96
+ configureBlurView()
97
+ applyTint()
98
+ setBlurRadius(_blurRadius)
99
+ }
100
+
101
+ val safeMethod = if (blurTargetView != null) value else BlurMethod.NONE
102
+
103
+ if (blurConfiguration == BlurViewConfiguration.UNCONFIGURED) return
104
+
105
+ when (safeMethod) {
106
+ BlurMethod.NONE -> {
107
+ blurView.setBlurEnabled(false)
108
+ }
109
+ BlurMethod.DIMEZISBLURVIEW -> {
110
+ blurView.setBlurEnabled(true)
111
+ containerView.setBackgroundColor(Color.TRANSPARENT)
112
+ }
113
+ BlurMethod.DIMEZISBLURVIEWSDK31PLUS -> {
114
+ val isNewSdk = Build.VERSION.SDK_INT >= 31
115
+ blurView.setBlurEnabled(isNewSdk)
116
+ if (isNewSdk) {
117
+ containerView.setBackgroundColor(Color.TRANSPARENT)
118
+ }
119
+ }
120
+ }
121
+ // Update blur to the current blurRadius value
122
+ setBlurRadius(_blurRadius)
123
+ }
124
+
125
+ // endregion
126
+
127
+ // region Configuration
128
+
129
+ private fun configureBlurView() {
130
+ val target = blurTargetView
131
+ if (target == null || _blurMethod == BlurMethod.NONE) {
132
+ blurView.setBlurEnabled(false)
133
+ blurConfiguration = BlurViewConfiguration.NONE
134
+ return
135
+ }
136
+
137
+ val decorView = context.currentActivity?.window?.decorView ?: run {
138
+ blurConfiguration = BlurViewConfiguration.NONE
139
+ return
140
+ }
141
+
142
+ blurView.setupWith(target)
143
+ .setFrameClearDrawable(decorView.background)
144
+ .setBlurRadius(_blurRadius.toFloat())
145
+
146
+ blurConfiguration = BlurViewConfiguration.DIMEZIS
147
+ }
148
+
149
+ /**
150
+ * Apply blur settings that may have been set before the BlurView was configured.
151
+ */
152
+ private fun applyCurrentBlurSettings() {
153
+ setBlurRadius(_blurRadius)
154
+ this.blurMethod = _blurMethod
155
+ applyTint()
156
+ }
157
+
158
+ // endregion
159
+
160
+ // region Blur application
161
+
162
+ private fun setBlurRadius(radius: Double) {
163
+ if (blurConfiguration == BlurViewConfiguration.UNCONFIGURED) return
164
+
165
+ when (_blurMethod) {
166
+ BlurMethod.NONE -> {
167
+ applyBlurViewRadiusCompat(useBlur = false, radius = radius)
168
+ }
169
+ BlurMethod.DIMEZISBLURVIEW -> {
170
+ applyBlurViewRadiusCompat(useBlur = true, radius = radius)
171
+ }
172
+ BlurMethod.DIMEZISBLURVIEWSDK31PLUS -> {
173
+ applyBlurViewRadiusCompat(useBlur = Build.VERSION.SDK_INT >= 31, radius = radius)
174
+ }
175
+ }
176
+ }
177
+
178
+ fun applyTint() {
179
+ if (blurConfiguration == BlurViewConfiguration.UNCONFIGURED) return
180
+
181
+ when (_blurMethod) {
182
+ BlurMethod.NONE -> {
183
+ applyBlurViewOverlayColorCompat(useBlurView = false)
184
+ }
185
+ BlurMethod.DIMEZISBLURVIEW -> {
186
+ applyBlurViewOverlayColorCompat(useBlurView = true)
187
+ }
188
+ BlurMethod.DIMEZISBLURVIEWSDK31PLUS -> {
189
+ applyBlurViewOverlayColorCompat(useBlurView = Build.VERSION.SDK_INT >= 31)
190
+ }
191
+ }
192
+ blurView.invalidate()
193
+ }
194
+
195
+ private fun applyBlurViewRadiusCompat(useBlur: Boolean, radius: Double) {
196
+ if (useBlur && blurTargetView != null) {
197
+ // When setting a blur directly to 0 a "nativePtr is null" exception is thrown
198
+ // https://issuetracker.google.com/issues/241546169
199
+ blurView.setBlurEnabled(radius != 0.0)
200
+ if (radius > 0) {
201
+ blurView.setBlurRadius((radius / _blurReduction).toFloat())
202
+ blurView.invalidate()
203
+ }
204
+ } else {
205
+ containerView.setBackgroundColor(_tint.toOverlayColor(_blurRadius))
206
+ }
207
+ }
208
+
209
+ private fun applyBlurViewOverlayColorCompat(useBlurView: Boolean) {
210
+ if (useBlurView && blurTargetView != null) {
211
+ blurView.setOverlayColor(_tint.toOverlayColor(_blurRadius))
212
+ } else {
213
+ containerView.setBackgroundColor(_tint.toOverlayColor(_blurRadius))
214
+ }
215
+ }
216
+
217
+ // endregion
218
+ }
219
+
220
+ /**
221
+ * Simple container ViewGroup that lays out children to fill bounds.
222
+ */
223
+ private class BlurContainerView(context: android.content.Context) : ViewGroup(context) {
224
+ override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
225
+ for (i in 0 until childCount) {
226
+ getChildAt(i).layout(0, 0, r - l, b - t)
227
+ }
228
+ }
229
+ }
@@ -0,0 +1,31 @@
1
+ package com.margelo.nitro.nitroblur
2
+
3
+ import com.facebook.react.BaseReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfoProvider
7
+ import com.facebook.react.uimanager.ViewManager
8
+
9
+ import com.margelo.nitro.nitroblur.views.HybridNitroBlurManager
10
+
11
+ class NitroBlurPackage : BaseReactPackage() {
12
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
13
+ return null
14
+ }
15
+
16
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
17
+ return ReactModuleInfoProvider { HashMap() }
18
+ }
19
+
20
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
21
+ // Use custom NitroBlurTargetViewGroupManager instead of generated HybridNitroBlurTargetManager
22
+ // because BlurTargetView needs ViewGroupManager (supports children), not SimpleViewManager
23
+ return listOf(HybridNitroBlurManager(), NitroBlurTargetViewGroupManager())
24
+ }
25
+
26
+ companion object {
27
+ init {
28
+ System.loadLibrary("nitroblur")
29
+ }
30
+ }
31
+ }