@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.
- package/LICENSE +20 -0
- package/NitroBlur.podspec +29 -0
- package/README.md +200 -0
- package/android/CMakeLists.txt +24 -0
- package/android/build.gradle +120 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/cpp-adapter.cpp +6 -0
- package/android/src/main/java/com/margelo/nitro/nitroblur/NitroBlur.kt +229 -0
- package/android/src/main/java/com/margelo/nitro/nitroblur/NitroBlurPackage.kt +31 -0
- package/android/src/main/java/com/margelo/nitro/nitroblur/NitroBlurTarget.kt +149 -0
- package/android/src/main/java/com/margelo/nitro/nitroblur/NitroBlurTargetViewGroupManager.kt +47 -0
- package/android/src/main/java/com/margelo/nitro/nitroblur/TintStyle.kt +85 -0
- package/ios/NitroBlur.swift +173 -0
- package/ios/NitroBlurTarget.swift +5 -0
- package/lib/module/NitroBlur.nitro.js +4 -0
- package/lib/module/NitroBlur.nitro.js.map +1 -0
- package/lib/module/NitroBlurTarget.nitro.js +4 -0
- package/lib/module/NitroBlurTarget.nitro.js.map +1 -0
- package/lib/module/index.js +114 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NitroBlur.nitro.d.ts +25 -0
- package/lib/typescript/src/NitroBlur.nitro.d.ts.map +1 -0
- package/lib/typescript/src/NitroBlurTarget.nitro.d.ts +7 -0
- package/lib/typescript/src/NitroBlurTarget.nitro.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +201 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/nitro.json +33 -0
- package/nitrogen/generated/android/c++/JBlurMethod.hpp +61 -0
- package/nitrogen/generated/android/c++/JBlurTint.hpp +115 -0
- package/nitrogen/generated/android/c++/JHybridNitroBlurSpec.cpp +99 -0
- package/nitrogen/generated/android/c++/JHybridNitroBlurSpec.hpp +72 -0
- package/nitrogen/generated/android/c++/JHybridNitroBlurTargetSpec.cpp +49 -0
- package/nitrogen/generated/android/c++/JHybridNitroBlurTargetSpec.hpp +63 -0
- package/nitrogen/generated/android/c++/views/JHybridNitroBlurStateUpdater.cpp +72 -0
- package/nitrogen/generated/android/c++/views/JHybridNitroBlurStateUpdater.hpp +49 -0
- package/nitrogen/generated/android/c++/views/JHybridNitroBlurTargetStateUpdater.cpp +53 -0
- package/nitrogen/generated/android/c++/views/JHybridNitroBlurTargetStateUpdater.hpp +49 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/BlurMethod.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/BlurTint.kt +42 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/HybridNitroBlurSpec.kt +81 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/HybridNitroBlurTargetSpec.kt +53 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/nitroblurOnLoad.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/views/HybridNitroBlurManager.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/views/HybridNitroBlurStateUpdater.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/views/HybridNitroBlurTargetManager.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroblur/views/HybridNitroBlurTargetStateUpdater.kt +23 -0
- package/nitrogen/generated/android/nitroblur+autolinking.cmake +87 -0
- package/nitrogen/generated/android/nitroblur+autolinking.gradle +27 -0
- package/nitrogen/generated/android/nitroblurOnLoad.cpp +74 -0
- package/nitrogen/generated/android/nitroblurOnLoad.hpp +34 -0
- package/nitrogen/generated/ios/NitroBlur+autolinking.rb +60 -0
- package/nitrogen/generated/ios/NitroBlur-Swift-Cxx-Bridge.cpp +50 -0
- package/nitrogen/generated/ios/NitroBlur-Swift-Cxx-Bridge.hpp +57 -0
- package/nitrogen/generated/ios/NitroBlur-Swift-Cxx-Umbrella.hpp +52 -0
- package/nitrogen/generated/ios/NitroBlurAutolinking.mm +41 -0
- package/nitrogen/generated/ios/NitroBlurAutolinking.swift +38 -0
- package/nitrogen/generated/ios/c++/HybridNitroBlurSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNitroBlurSpecSwift.hpp +110 -0
- package/nitrogen/generated/ios/c++/HybridNitroBlurTargetSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNitroBlurTargetSpecSwift.hpp +75 -0
- package/nitrogen/generated/ios/c++/views/HybridNitroBlurComponent.mm +142 -0
- package/nitrogen/generated/ios/c++/views/HybridNitroBlurTargetComponent.mm +118 -0
- package/nitrogen/generated/ios/swift/BlurMethod.swift +44 -0
- package/nitrogen/generated/ios/swift/BlurTint.swift +116 -0
- package/nitrogen/generated/ios/swift/HybridNitroBlurSpec.swift +59 -0
- package/nitrogen/generated/ios/swift/HybridNitroBlurSpec_cxx.swift +200 -0
- package/nitrogen/generated/ios/swift/HybridNitroBlurTargetSpec.swift +55 -0
- package/nitrogen/generated/ios/swift/HybridNitroBlurTargetSpec_cxx.swift +147 -0
- package/nitrogen/generated/shared/c++/BlurMethod.hpp +80 -0
- package/nitrogen/generated/shared/c++/BlurTint.hpp +152 -0
- package/nitrogen/generated/shared/c++/HybridNitroBlurSpec.cpp +30 -0
- package/nitrogen/generated/shared/c++/HybridNitroBlurSpec.hpp +75 -0
- package/nitrogen/generated/shared/c++/HybridNitroBlurTargetSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridNitroBlurTargetSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/views/HybridNitroBlurComponent.cpp +127 -0
- package/nitrogen/generated/shared/c++/views/HybridNitroBlurComponent.hpp +116 -0
- package/nitrogen/generated/shared/c++/views/HybridNitroBlurTargetComponent.cpp +72 -0
- package/nitrogen/generated/shared/c++/views/HybridNitroBlurTargetComponent.hpp +109 -0
- package/nitrogen/generated/shared/json/NitroBlurConfig.json +14 -0
- package/nitrogen/generated/shared/json/NitroBlurTargetConfig.json +9 -0
- package/package.json +174 -0
- package/src/NitroBlur.nitro.ts +56 -0
- package/src/NitroBlurTarget.nitro.ts +13 -0
- 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,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
|
+
}
|