@sbaiahmed1/react-native-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/README.md +222 -0
- package/ReactNativeBlur.podspec +20 -0
- package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/ReactNativeBlurViewManagerDelegate.java +38 -0
- package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/ReactNativeBlurViewManagerInterface.java +20 -0
- package/android/app/build/generated/source/codegen/jni/CMakeLists.txt +36 -0
- package/android/app/build/generated/source/codegen/jni/ReactNativeBlurViewSpec-generated.cpp +22 -0
- package/android/app/build/generated/source/codegen/jni/ReactNativeBlurViewSpec.h +24 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ComponentDescriptors.cpp +22 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ComponentDescriptors.h +24 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/EventEmitters.cpp +16 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/EventEmitters.h +23 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/Props.cpp +27 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/Props.h +63 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ReactNativeBlurViewSpecJSI-generated.cpp +17 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ReactNativeBlurViewSpecJSI.h +19 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ShadowNodes.cpp +17 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ShadowNodes.h +32 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/States.cpp +16 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/States.h +29 -0
- package/android/build.gradle +85 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurPackage.kt +19 -0
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurView.kt +369 -0
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurViewManager.kt +50 -0
- package/ios/ReactNativeBlurView.h +14 -0
- package/ios/ReactNativeBlurView.mm +311 -0
- package/ios/ReactNativeBlurViewManager.mm +23 -0
- package/lib/module/BlurView.js +41 -0
- package/lib/module/BlurView.js.map +1 -0
- package/lib/module/ReactNativeBlurViewNativeComponent.ts +27 -0
- package/lib/module/index.js +6 -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/BlurView.d.ts +48 -0
- package/lib/typescript/src/BlurView.d.ts.map +1 -0
- package/lib/typescript/src/ReactNativeBlurViewNativeComponent.d.ts +11 -0
- package/lib/typescript/src/ReactNativeBlurViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +5 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/package.json +170 -0
- package/src/BlurView.tsx +75 -0
- package/src/ReactNativeBlurViewNativeComponent.ts +27 -0
- package/src/index.tsx +5 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
|
4
|
+
*
|
|
5
|
+
* Do not edit this file as changes may cause incorrect behavior and will be lost
|
|
6
|
+
* once the code is regenerated.
|
|
7
|
+
*
|
|
8
|
+
* @generated by codegen project: GenerateShadowNodeH.js
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
#pragma once
|
|
12
|
+
|
|
13
|
+
#include <react/renderer/components/ReactNativeBlurViewSpec/EventEmitters.h>
|
|
14
|
+
#include <react/renderer/components/ReactNativeBlurViewSpec/Props.h>
|
|
15
|
+
#include <react/renderer/components/ReactNativeBlurViewSpec/States.h>
|
|
16
|
+
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
|
|
17
|
+
#include <jsi/jsi.h>
|
|
18
|
+
|
|
19
|
+
namespace facebook::react {
|
|
20
|
+
|
|
21
|
+
JSI_EXPORT extern const char ReactNativeBlurViewComponentName[];
|
|
22
|
+
|
|
23
|
+
/*
|
|
24
|
+
* `ShadowNode` for <ReactNativeBlurView> component.
|
|
25
|
+
*/
|
|
26
|
+
using ReactNativeBlurViewShadowNode = ConcreteViewShadowNode<
|
|
27
|
+
ReactNativeBlurViewComponentName,
|
|
28
|
+
ReactNativeBlurViewProps,
|
|
29
|
+
ReactNativeBlurViewEventEmitter,
|
|
30
|
+
ReactNativeBlurViewState>;
|
|
31
|
+
|
|
32
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
|
4
|
+
*
|
|
5
|
+
* Do not edit this file as changes may cause incorrect behavior and will be lost
|
|
6
|
+
* once the code is regenerated.
|
|
7
|
+
*
|
|
8
|
+
* @generated by codegen project: GenerateStateCpp.js
|
|
9
|
+
*/
|
|
10
|
+
#include <react/renderer/components/ReactNativeBlurViewSpec/States.h>
|
|
11
|
+
|
|
12
|
+
namespace facebook::react {
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
|
3
|
+
*
|
|
4
|
+
* Do not edit this file as changes may cause incorrect behavior and will be lost
|
|
5
|
+
* once the code is regenerated.
|
|
6
|
+
*
|
|
7
|
+
* @generated by codegen project: GenerateStateH.js
|
|
8
|
+
*/
|
|
9
|
+
#pragma once
|
|
10
|
+
|
|
11
|
+
#ifdef ANDROID
|
|
12
|
+
#include <folly/dynamic.h>
|
|
13
|
+
#endif
|
|
14
|
+
|
|
15
|
+
namespace facebook::react {
|
|
16
|
+
|
|
17
|
+
class ReactNativeBlurViewState {
|
|
18
|
+
public:
|
|
19
|
+
ReactNativeBlurViewState() = default;
|
|
20
|
+
|
|
21
|
+
#ifdef ANDROID
|
|
22
|
+
ReactNativeBlurViewState(ReactNativeBlurViewState const &previousState, folly::dynamic data){};
|
|
23
|
+
folly::dynamic getDynamic() const {
|
|
24
|
+
return {};
|
|
25
|
+
};
|
|
26
|
+
#endif
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
ext.getExtOrDefault = {name ->
|
|
3
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['ReactNativeBlur_' + name]
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
repositories {
|
|
7
|
+
google()
|
|
8
|
+
mavenCentral()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
dependencies {
|
|
12
|
+
classpath "com.android.tools.build:gradle:8.7.2"
|
|
13
|
+
// noinspection DifferentKotlinGradleVersion
|
|
14
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
apply plugin: "com.android.library"
|
|
20
|
+
apply plugin: "kotlin-android"
|
|
21
|
+
|
|
22
|
+
apply plugin: "com.facebook.react"
|
|
23
|
+
|
|
24
|
+
def getExtOrIntegerDefault(name) {
|
|
25
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["ReactNativeBlur_" + name]).toInteger()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
android {
|
|
29
|
+
namespace "com.sbaiahmed1.reactnativeblur"
|
|
30
|
+
|
|
31
|
+
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
|
|
32
|
+
|
|
33
|
+
defaultConfig {
|
|
34
|
+
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
|
|
35
|
+
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
buildFeatures {
|
|
39
|
+
buildConfig true
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
buildTypes {
|
|
43
|
+
release {
|
|
44
|
+
minifyEnabled false
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
lintOptions {
|
|
49
|
+
disable "GradleCompatible"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
compileOptions {
|
|
53
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
54
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
sourceSets {
|
|
58
|
+
main {
|
|
59
|
+
java.srcDirs += [
|
|
60
|
+
"generated/java",
|
|
61
|
+
"generated/jni"
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
repositories {
|
|
68
|
+
mavenCentral()
|
|
69
|
+
google()
|
|
70
|
+
maven { url 'https://jitpack.io' }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
def kotlin_version = getExtOrDefault("kotlinVersion")
|
|
74
|
+
|
|
75
|
+
dependencies {
|
|
76
|
+
implementation "com.facebook.react:react-android"
|
|
77
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
78
|
+
implementation 'com.github.Dimezis:BlurView:version-2.0.6'
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
react {
|
|
82
|
+
jsRootDir = file("../src/")
|
|
83
|
+
libraryName = "ReactNativeBlurView"
|
|
84
|
+
codegenJavaPackageName = "com.sbaiahmed1.reactnativeblur"
|
|
85
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
package com.sbaiahmed1.reactnativeblur
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager
|
|
7
|
+
import java.util.ArrayList
|
|
8
|
+
|
|
9
|
+
class ReactNativeBlurViewPackage : ReactPackage {
|
|
10
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
|
11
|
+
val viewManagers: MutableList<ViewManager<*, *>> = ArrayList()
|
|
12
|
+
viewManagers.add(ReactNativeBlurViewManager())
|
|
13
|
+
return viewManagers
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
|
|
17
|
+
return emptyList()
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
package com.sbaiahmed1.reactnativeblur
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.graphics.Color
|
|
5
|
+
import android.graphics.drawable.ColorDrawable
|
|
6
|
+
import android.util.AttributeSet
|
|
7
|
+
import android.util.Log
|
|
8
|
+
import android.view.ViewGroup
|
|
9
|
+
import eightbitlab.com.blurview.BlurView
|
|
10
|
+
import eightbitlab.com.blurview.RenderEffectBlur
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Android implementation of React Native BlurView component.
|
|
14
|
+
* Provides cross-platform blur effects using the BlurView library.
|
|
15
|
+
*/
|
|
16
|
+
class ReactNativeBlurView : BlurView {
|
|
17
|
+
private var blurRadius = mapBlurAmountToRadius(DEFAULT_BLUR_AMOUNT)
|
|
18
|
+
private var overlayColor = Color.TRANSPARENT
|
|
19
|
+
private var isSetup = false
|
|
20
|
+
private var pendingStyleUpdate: Boolean = false
|
|
21
|
+
private var originalBackgroundColor: Int? = null
|
|
22
|
+
private var hasExplicitBackground: Boolean = false
|
|
23
|
+
|
|
24
|
+
companion object {
|
|
25
|
+
private const val TAG = "ReactNativeBlurView"
|
|
26
|
+
private const val MIN_BLUR_RADIUS = 0f
|
|
27
|
+
private const val MAX_BLUR_RADIUS = 25f
|
|
28
|
+
private const val DEFAULT_BLUR_RADIUS = 10f
|
|
29
|
+
private const val DEBUG = false // Set to true for debug builds
|
|
30
|
+
|
|
31
|
+
// Cross-platform blur amount constants
|
|
32
|
+
private const val MIN_BLUR_AMOUNT = 0f
|
|
33
|
+
private const val MAX_BLUR_AMOUNT = 100f
|
|
34
|
+
private const val DEFAULT_BLUR_AMOUNT = 10f
|
|
35
|
+
|
|
36
|
+
private fun logDebug(message: String) {
|
|
37
|
+
if (DEBUG) {
|
|
38
|
+
Log.d(TAG, message)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private fun logWarning(message: String) {
|
|
43
|
+
Log.w(TAG, message)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private fun logError(message: String, throwable: Throwable? = null) {
|
|
47
|
+
Log.e(TAG, message, throwable)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Maps blur amount (0-100) to Android blur radius (0-25).
|
|
52
|
+
* This ensures cross-platform consistency while respecting Android's limitations.
|
|
53
|
+
* @param amount The blur amount from 0-100
|
|
54
|
+
* @return The corresponding blur radius from 0-25
|
|
55
|
+
*/
|
|
56
|
+
private fun mapBlurAmountToRadius(amount: Float): Float {
|
|
57
|
+
val clampedAmount = amount.coerceIn(MIN_BLUR_AMOUNT, MAX_BLUR_AMOUNT)
|
|
58
|
+
return (clampedAmount / MAX_BLUR_AMOUNT) * MAX_BLUR_RADIUS
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
constructor(context: Context?) : super(context) {
|
|
63
|
+
initializeBlur()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
|
|
67
|
+
initializeBlur()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
|
71
|
+
context,
|
|
72
|
+
attrs,
|
|
73
|
+
defStyleAttr
|
|
74
|
+
) {
|
|
75
|
+
initializeBlur()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Initialize the blur view with default settings.
|
|
80
|
+
* Sets transparent background to prevent visual artifacts.
|
|
81
|
+
*/
|
|
82
|
+
private fun initializeBlur() {
|
|
83
|
+
// Set transparent background initially to avoid yellow tint - use super to avoid recursion
|
|
84
|
+
super.setBackgroundColor(Color.TRANSPARENT)
|
|
85
|
+
logDebug("ReactNativeBlurView initialized")
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Override setBackgroundColor to handle blur setup timing and background preservation.
|
|
90
|
+
* @param color The background color to apply
|
|
91
|
+
*/
|
|
92
|
+
override fun setBackgroundColor(color: Int) {
|
|
93
|
+
logDebug("setBackgroundColor called: $color (isSetup: $isSetup)")
|
|
94
|
+
|
|
95
|
+
// Store the original background color if it's not transparent
|
|
96
|
+
if (color != Color.TRANSPARENT) {
|
|
97
|
+
originalBackgroundColor = color
|
|
98
|
+
hasExplicitBackground = true
|
|
99
|
+
logDebug("Stored explicit background color: $color")
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// If blur is not setup yet, defer setting the background
|
|
103
|
+
if (!isSetup) {
|
|
104
|
+
logDebug("Blur not setup, deferring background color")
|
|
105
|
+
pendingStyleUpdate = true
|
|
106
|
+
// Post a setup attempt
|
|
107
|
+
post {
|
|
108
|
+
if (!isSetup && isAttachedToWindow) {
|
|
109
|
+
logDebug("Attempting deferred blur setup from setBackgroundColor")
|
|
110
|
+
setupBlurView()
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// If blur is setup and we have an explicit background, apply it carefully
|
|
117
|
+
if (hasExplicitBackground && color != Color.TRANSPARENT) {
|
|
118
|
+
logDebug("Applying background color over blur: $color")
|
|
119
|
+
super.setBackgroundColor(color)
|
|
120
|
+
} else {
|
|
121
|
+
logDebug("Keeping transparent background for blur effect")
|
|
122
|
+
super.setBackgroundColor(Color.TRANSPARENT)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Override setAlpha to handle blur setup timing.
|
|
128
|
+
* @param alpha The alpha value to apply
|
|
129
|
+
*/
|
|
130
|
+
override fun setAlpha(alpha: Float) {
|
|
131
|
+
logDebug("setAlpha called: $alpha (isSetup: $isSetup)")
|
|
132
|
+
|
|
133
|
+
// Always apply alpha changes immediately as they don't interfere with blur setup
|
|
134
|
+
super.setAlpha(alpha)
|
|
135
|
+
|
|
136
|
+
// If blur is not setup yet, trigger setup attempt
|
|
137
|
+
if (!isSetup && isAttachedToWindow) {
|
|
138
|
+
pendingStyleUpdate = true
|
|
139
|
+
post {
|
|
140
|
+
if (!isSetup && isAttachedToWindow) {
|
|
141
|
+
logDebug("Attempting deferred blur setup from setAlpha")
|
|
142
|
+
setupBlurView()
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Override setElevation to handle blur setup timing.
|
|
150
|
+
* @param elevation The elevation value to apply
|
|
151
|
+
*/
|
|
152
|
+
override fun setElevation(elevation: Float) {
|
|
153
|
+
logDebug("setElevation called: $elevation (isSetup: $isSetup)")
|
|
154
|
+
|
|
155
|
+
// Always apply elevation changes immediately
|
|
156
|
+
super.setElevation(elevation)
|
|
157
|
+
|
|
158
|
+
// If blur is not setup yet, trigger setup attempt
|
|
159
|
+
if (!isSetup && isAttachedToWindow) {
|
|
160
|
+
pendingStyleUpdate = true
|
|
161
|
+
post {
|
|
162
|
+
if (!isSetup && isAttachedToWindow) {
|
|
163
|
+
logDebug("Attempting deferred blur setup from setElevation")
|
|
164
|
+
setupBlurView()
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Called when the view is attached to a window.
|
|
172
|
+
* Triggers blur setup if not already configured.
|
|
173
|
+
*/
|
|
174
|
+
override fun onAttachedToWindow() {
|
|
175
|
+
super.onAttachedToWindow()
|
|
176
|
+
setupBlurView()
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Called when the view is detached from a window.
|
|
181
|
+
* Performs cleanup to prevent memory leaks.
|
|
182
|
+
*/
|
|
183
|
+
override fun onDetachedFromWindow() {
|
|
184
|
+
super.onDetachedFromWindow()
|
|
185
|
+
cleanup()
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Cleanup method to reset state and remove pending callbacks.
|
|
190
|
+
* Helps prevent memory leaks and ensures clean state.
|
|
191
|
+
*/
|
|
192
|
+
private fun cleanup() {
|
|
193
|
+
isSetup = false
|
|
194
|
+
hasExplicitBackground = false
|
|
195
|
+
originalBackgroundColor = null
|
|
196
|
+
pendingStyleUpdate = false
|
|
197
|
+
// Clear any pending runnables to prevent memory leaks
|
|
198
|
+
removeCallbacks(null)
|
|
199
|
+
logDebug("View detached, reset state")
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Setup the blur view with multiple fallback strategies for finding the root view.
|
|
204
|
+
* Uses RenderEffectBlur for optimal performance on modern Android versions.
|
|
205
|
+
*/
|
|
206
|
+
private fun setupBlurView() {
|
|
207
|
+
if (isSetup) return
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
val rootView = findRootView()
|
|
211
|
+
|
|
212
|
+
rootView?.let { root ->
|
|
213
|
+
// Setup the blur view with RenderEffect for better performance and modern API
|
|
214
|
+
this.setupWith(root, RenderEffectBlur())
|
|
215
|
+
.setBlurRadius(blurRadius)
|
|
216
|
+
.setOverlayColor(overlayColor)
|
|
217
|
+
|
|
218
|
+
isSetup = true
|
|
219
|
+
pendingStyleUpdate = false
|
|
220
|
+
|
|
221
|
+
// Apply any pending background color after blur setup
|
|
222
|
+
if (hasExplicitBackground && originalBackgroundColor != null) {
|
|
223
|
+
logDebug("Applying pending background color: $originalBackgroundColor")
|
|
224
|
+
super.setBackgroundColor(originalBackgroundColor!!)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
logDebug("Blur setup successful with root: ${root.javaClass.simpleName}")
|
|
228
|
+
} ?: run {
|
|
229
|
+
logWarning("No suitable root view found for blur setup")
|
|
230
|
+
}
|
|
231
|
+
} catch (e: Exception) {
|
|
232
|
+
// Fallback: set transparent background to avoid yellow tint
|
|
233
|
+
super.setBackgroundColor(Color.TRANSPARENT)
|
|
234
|
+
logError("Failed to setup blur: ${e.message}", e)
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Find the root view using multiple strategies.
|
|
240
|
+
* @return The root ViewGroup or null if not found
|
|
241
|
+
*/
|
|
242
|
+
private fun findRootView(): ViewGroup? {
|
|
243
|
+
// Strategy 1: Look for the content view (most reliable)
|
|
244
|
+
var parent = this.parent
|
|
245
|
+
while (parent != null) {
|
|
246
|
+
if (parent is ViewGroup && parent.id == android.R.id.content) {
|
|
247
|
+
return parent
|
|
248
|
+
}
|
|
249
|
+
parent = parent.parent
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Strategy 2: If content view not found, use the activity's root view
|
|
253
|
+
try {
|
|
254
|
+
val activity = context as? android.app.Activity
|
|
255
|
+
activity?.findViewById<ViewGroup>(android.R.id.content)?.let {
|
|
256
|
+
return it
|
|
257
|
+
}
|
|
258
|
+
} catch (e: Exception) {
|
|
259
|
+
logDebug("Could not access activity root view: ${e.message}")
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Strategy 3: Fallback to immediate parent
|
|
263
|
+
return this.parent as? ViewGroup
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Set the blur amount with cross-platform mapping.
|
|
268
|
+
* @param amount The blur amount value (0-100), will be mapped to Android's 0-25 radius range
|
|
269
|
+
*/
|
|
270
|
+
fun setBlurAmount(amount: Float) {
|
|
271
|
+
blurRadius = mapBlurAmountToRadius(amount)
|
|
272
|
+
logDebug("setBlurAmount: $amount -> $blurRadius (mapped from 0-100 to 0-25 range, isSetup: $isSetup)")
|
|
273
|
+
|
|
274
|
+
if (isSetup) {
|
|
275
|
+
try {
|
|
276
|
+
setBlurRadius(blurRadius)
|
|
277
|
+
} catch (e: Exception) {
|
|
278
|
+
logError("Failed to set blur radius: ${e.message}", e)
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Enum representing different blur types with their corresponding overlay colors.
|
|
285
|
+
* Maps iOS blur types to Android overlay colors to approximate the visual appearance.
|
|
286
|
+
*/
|
|
287
|
+
enum class BlurType(val overlayColor: Int) {
|
|
288
|
+
XLIGHT(Color.argb(25, 255, 255, 255)),
|
|
289
|
+
LIGHT(Color.argb(40, 255, 255, 255)),
|
|
290
|
+
DARK(Color.argb(60, 0, 0, 0)),
|
|
291
|
+
EXTRA_DARK(Color.argb(80, 0, 0, 0)),
|
|
292
|
+
REGULAR(Color.argb(50, 255, 255, 255)),
|
|
293
|
+
PROMINENT(Color.argb(70, 255, 255, 255)),
|
|
294
|
+
SYSTEM_ULTRA_THIN_MATERIAL(Color.argb(20, 255, 255, 255)),
|
|
295
|
+
SYSTEM_THIN_MATERIAL(Color.argb(35, 255, 255, 255)),
|
|
296
|
+
SYSTEM_MATERIAL(Color.argb(50, 255, 255, 255)),
|
|
297
|
+
SYSTEM_THICK_MATERIAL(Color.argb(65, 255, 255, 255)),
|
|
298
|
+
SYSTEM_CHROME_MATERIAL(Color.argb(45, 240, 240, 240));
|
|
299
|
+
|
|
300
|
+
companion object {
|
|
301
|
+
/**
|
|
302
|
+
* Get BlurType from string, with fallback to LIGHT for unknown types.
|
|
303
|
+
*/
|
|
304
|
+
fun fromString(type: String): BlurType {
|
|
305
|
+
return when (type.lowercase()) {
|
|
306
|
+
"xlight" -> XLIGHT
|
|
307
|
+
"light" -> LIGHT
|
|
308
|
+
"dark" -> DARK
|
|
309
|
+
"extradark" -> EXTRA_DARK
|
|
310
|
+
"regular" -> REGULAR
|
|
311
|
+
"prominent" -> PROMINENT
|
|
312
|
+
"systemultrathinmaterial" -> SYSTEM_ULTRA_THIN_MATERIAL
|
|
313
|
+
"systemthinmaterial" -> SYSTEM_THIN_MATERIAL
|
|
314
|
+
"systemmaterial" -> SYSTEM_MATERIAL
|
|
315
|
+
"systemthickmaterial" -> SYSTEM_THICK_MATERIAL
|
|
316
|
+
"systemchromematerial" -> SYSTEM_CHROME_MATERIAL
|
|
317
|
+
else -> LIGHT // default fallback
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Set the blur type which determines the overlay color.
|
|
325
|
+
* @param type The blur type string (case-insensitive)
|
|
326
|
+
*/
|
|
327
|
+
fun setBlurType(type: String) {
|
|
328
|
+
val blurType = BlurType.fromString(type)
|
|
329
|
+
overlayColor = blurType.overlayColor
|
|
330
|
+
logDebug("setBlurType: $type -> ${blurType.name} (isSetup: $isSetup)")
|
|
331
|
+
|
|
332
|
+
if (isSetup) {
|
|
333
|
+
try {
|
|
334
|
+
setOverlayColor(overlayColor)
|
|
335
|
+
} catch (e: Exception) {
|
|
336
|
+
logError("Failed to set overlay color: ${e.message}", e)
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Set the fallback color for reduced transparency accessibility mode.
|
|
343
|
+
* @param color The color string in hex format (e.g., "#FF0000") or null to clear
|
|
344
|
+
*/
|
|
345
|
+
fun setReducedTransparencyFallbackColor(color: String?) {
|
|
346
|
+
color?.let {
|
|
347
|
+
try {
|
|
348
|
+
val fallbackColor = Color.parseColor(it)
|
|
349
|
+
// Use fallback color as overlay when accessibility settings require it
|
|
350
|
+
// This is a simplified implementation - in a full implementation,
|
|
351
|
+
// you'd check system accessibility settings
|
|
352
|
+
overlayColor = fallbackColor
|
|
353
|
+
logDebug("setReducedTransparencyFallbackColor: $color -> $fallbackColor (isSetup: $isSetup)")
|
|
354
|
+
|
|
355
|
+
if (isSetup) {
|
|
356
|
+
try {
|
|
357
|
+
setOverlayColor(overlayColor)
|
|
358
|
+
} catch (e: Exception) {
|
|
359
|
+
logError("Failed to set fallback overlay color: ${e.message}", e)
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
} catch (e: Exception) {
|
|
363
|
+
logWarning("Invalid color format for reduced transparency fallback: $color")
|
|
364
|
+
}
|
|
365
|
+
} ?: run {
|
|
366
|
+
logDebug("Cleared reduced transparency fallback color")
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
package com.sbaiahmed1.reactnativeblur
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
4
|
+
import com.facebook.react.uimanager.ViewGroupManager
|
|
5
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewManagerDelegate
|
|
7
|
+
import com.facebook.react.uimanager.annotations.ReactProp
|
|
8
|
+
import com.facebook.react.viewmanagers.ReactNativeBlurViewManagerInterface
|
|
9
|
+
import com.facebook.react.viewmanagers.ReactNativeBlurViewManagerDelegate
|
|
10
|
+
|
|
11
|
+
@ReactModule(name = ReactNativeBlurViewManager.NAME)
|
|
12
|
+
class ReactNativeBlurViewManager : ViewGroupManager<ReactNativeBlurView>(),
|
|
13
|
+
ReactNativeBlurViewManagerInterface<ReactNativeBlurView> {
|
|
14
|
+
private val mDelegate: ViewManagerDelegate<ReactNativeBlurView>
|
|
15
|
+
|
|
16
|
+
init {
|
|
17
|
+
mDelegate = ReactNativeBlurViewManagerDelegate(this)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
override fun getDelegate(): ViewManagerDelegate<ReactNativeBlurView>? {
|
|
21
|
+
return mDelegate
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
override fun getName(): String {
|
|
25
|
+
return NAME
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public override fun createViewInstance(context: ThemedReactContext): ReactNativeBlurView {
|
|
29
|
+
return ReactNativeBlurView(context)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@ReactProp(name = "blurType")
|
|
33
|
+
override fun setBlurType(view: ReactNativeBlurView?, blurType: String?) {
|
|
34
|
+
view?.setBlurType(blurType ?: "light")
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@ReactProp(name = "blurAmount")
|
|
38
|
+
override fun setBlurAmount(view: ReactNativeBlurView?, blurAmount: Double) {
|
|
39
|
+
view?.setBlurAmount(blurAmount.toFloat())
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@ReactProp(name = "reducedTransparencyFallbackColor")
|
|
43
|
+
override fun setReducedTransparencyFallbackColor(view: ReactNativeBlurView?, reducedTransparencyFallbackColor: String?) {
|
|
44
|
+
view?.setReducedTransparencyFallbackColor(reducedTransparencyFallbackColor)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
companion object {
|
|
48
|
+
const val NAME = "ReactNativeBlurView"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#import <React/RCTViewComponentView.h>
|
|
2
|
+
#import <UIKit/UIKit.h>
|
|
3
|
+
|
|
4
|
+
#ifndef ReactNativeBlurViewNativeComponent_h
|
|
5
|
+
#define ReactNativeBlurViewNativeComponent_h
|
|
6
|
+
|
|
7
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
8
|
+
|
|
9
|
+
@interface ReactNativeBlurView : RCTViewComponentView
|
|
10
|
+
@end
|
|
11
|
+
|
|
12
|
+
NS_ASSUME_NONNULL_END
|
|
13
|
+
|
|
14
|
+
#endif /* ReactNativeBlurViewNativeComponent_h */
|