react-native-unistyles 2.4.0-rc.1 → 2.4.0-rc.2
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/README.md +5 -2
- package/android/src/main/cxx/cpp-adapter.cpp +28 -13
- package/android/src/main/cxx/helpers.cpp +21 -56
- package/android/src/main/cxx/helpers.h +3 -3
- package/android/src/main/java/com/unistyles/Config.kt +116 -0
- package/android/src/main/java/com/unistyles/Insets.kt +138 -0
- package/android/src/main/java/com/unistyles/Models.kt +85 -0
- package/android/src/main/java/com/unistyles/Platform.kt +10 -79
- package/android/src/main/java/com/unistyles/UnistylesModule.kt +85 -25
- package/cxx/UnistylesRuntime.cpp +57 -42
- package/cxx/UnistylesRuntime.h +30 -19
- package/ios/UnistylesModule.mm +20 -6
- package/ios/platform/Platform_iOS.h +5 -4
- package/ios/platform/Platform_iOS.mm +35 -22
- package/ios/platform/Platform_macOS.h +5 -4
- package/ios/platform/Platform_macOS.mm +18 -25
- package/lib/commonjs/common.js +7 -0
- package/lib/commonjs/common.js.map +1 -1
- package/lib/commonjs/core/UnistylesModule.js +6 -0
- package/lib/commonjs/core/UnistylesModule.js.map +1 -1
- package/lib/commonjs/core/UnistylesRuntime.js +8 -0
- package/lib/commonjs/core/UnistylesRuntime.js.map +1 -1
- package/lib/commonjs/hooks/useUnistyles.js +18 -1
- package/lib/commonjs/hooks/useUnistyles.js.map +1 -1
- package/lib/module/common.js +7 -0
- package/lib/module/common.js.map +1 -1
- package/lib/module/core/UnistylesModule.js +6 -0
- package/lib/module/core/UnistylesModule.js.map +1 -1
- package/lib/module/core/UnistylesRuntime.js +8 -0
- package/lib/module/core/UnistylesRuntime.js.map +1 -1
- package/lib/module/hooks/useUnistyles.js +18 -1
- package/lib/module/hooks/useUnistyles.js.map +1 -1
- package/lib/typescript/src/common.d.ts +8 -1
- package/lib/typescript/src/common.d.ts.map +1 -1
- package/lib/typescript/src/core/UnistylesModule.d.ts.map +1 -1
- package/lib/typescript/src/core/UnistylesRuntime.d.ts +6 -1
- package/lib/typescript/src/core/UnistylesRuntime.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useUnistyles.d.ts +14 -0
- package/lib/typescript/src/hooks/useUnistyles.d.ts.map +1 -1
- package/lib/typescript/src/types/unistyles.d.ts +6 -2
- package/lib/typescript/src/types/unistyles.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/common.ts +8 -1
- package/src/core/UnistylesModule.ts +8 -2
- package/src/core/UnistylesRuntime.ts +8 -0
- package/src/hooks/useUnistyles.ts +18 -1
- package/src/types/unistyles.ts +6 -2
package/README.md
CHANGED
@@ -48,10 +48,13 @@
|
|
48
48
|
[How to become a sponsor?](https://reactnativeunistyles.vercel.app/other/for-sponsors/)
|
49
49
|
|
50
50
|
<a href="https://codemask.com">
|
51
|
-
|
51
|
+
<img src="https://avatars.githubusercontent.com/u/51229884?s=200&v=4" height="70px" width="70px" alt="codemask" />
|
52
52
|
</a>
|
53
53
|
<a href="https://galaxies.dev">
|
54
|
-
<img src="https://avatars.githubusercontent.com/u/118431096?s=200&v=4" height="70px" width="70px" />
|
54
|
+
<img src="https://avatars.githubusercontent.com/u/118431096?s=200&v=4" height="70px" width="70px" alt="galaxies-dev" />
|
55
|
+
</a>
|
56
|
+
<a href="https://github.com/kmartinezmedia">
|
57
|
+
<img src="https://avatars.githubusercontent.com/u/6308123?s=200&v=4" height="70px" width="70px" alt="kmartinezmedia" />
|
55
58
|
</a>
|
56
59
|
|
57
60
|
|
@@ -15,12 +15,12 @@ Java_com_unistyles_UnistylesModule_nativeInstall(
|
|
15
15
|
JNIEnv *env,
|
16
16
|
jobject thiz,
|
17
17
|
jlong jsi,
|
18
|
-
|
19
|
-
jint screenHeight,
|
18
|
+
jobject screen,
|
20
19
|
jstring colorScheme,
|
21
20
|
jstring contentSizeCategory,
|
22
21
|
jobject insets,
|
23
|
-
jobject statusBar
|
22
|
+
jobject statusBar,
|
23
|
+
jobject navigationBar
|
24
24
|
) {
|
25
25
|
auto runtime = reinterpret_cast<facebook::jsi::Runtime *>(jsi);
|
26
26
|
|
@@ -41,12 +41,12 @@ Java_com_unistyles_UnistylesModule_nativeInstall(
|
|
41
41
|
env->ReleaseStringUTFChars(contentSizeCategory, contentSizeCategoryChars);
|
42
42
|
|
43
43
|
unistylesRuntime = std::make_shared<UnistylesRuntime>(
|
44
|
-
|
45
|
-
screenHeight,
|
44
|
+
jobjectToDimensions(env, screen),
|
46
45
|
colorSchemeStr,
|
47
46
|
contentSizeCategoryStr,
|
48
|
-
|
49
|
-
|
47
|
+
jobjectToInsets(env, insets),
|
48
|
+
jobjectToDimensions(env, statusBar),
|
49
|
+
jobjectToDimensions(env, navigationBar)
|
50
50
|
);
|
51
51
|
|
52
52
|
unistylesRuntime->onThemeChange([=](const std::string &theme) {
|
@@ -59,13 +59,23 @@ Java_com_unistyles_UnistylesModule_nativeInstall(
|
|
59
59
|
env->DeleteLocalRef(cls);
|
60
60
|
});
|
61
61
|
|
62
|
-
unistylesRuntime->onLayoutChange([=](const std::string &breakpoint, const std::string &orientation,
|
62
|
+
unistylesRuntime->onLayoutChange([=](const std::string &breakpoint, const std::string &orientation, Dimensions& screen, Dimensions& statusBar, Insets& insets, Dimensions& navigationBar) {
|
63
63
|
jstring breakpointStr = env->NewStringUTF(breakpoint.c_str());
|
64
64
|
jstring orientationStr = env->NewStringUTF(orientation.c_str());
|
65
65
|
jclass cls = env->GetObjectClass(unistylesModule);
|
66
|
-
|
67
|
-
|
68
|
-
env->
|
66
|
+
jclass dimensionsClass = env->FindClass("com/unistyles/Dimensions");
|
67
|
+
jmethodID dimensionsConstructor = env->GetMethodID(dimensionsClass, "<init>", "(II)V");
|
68
|
+
jobject screenObj = env->NewObject(dimensionsClass, dimensionsConstructor, screen.width, screen.height);
|
69
|
+
jobject statusBarObj = env->NewObject(dimensionsClass, dimensionsConstructor, statusBar.width, statusBar.height);
|
70
|
+
jobject navigationBarObj = env->NewObject(dimensionsClass, dimensionsConstructor, navigationBar.width, navigationBar.height);
|
71
|
+
|
72
|
+
jclass insetsClass = env->FindClass("com/unistyles/Insets");
|
73
|
+
jmethodID insetsConstructor = env->GetMethodID(insetsClass, "<init>", "(IIII)V");
|
74
|
+
jobject insetsObj = env->NewObject(insetsClass, insetsConstructor, insets.left, insets.top, insets.right, insets.bottom);
|
75
|
+
jmethodID methodId = env->GetMethodID(cls, "onLayoutChange",
|
76
|
+
"(Ljava/lang/String;Ljava/lang/String;Lcom/unistyles/Dimensions;Lcom/unistyles/Dimensions;Lcom/unistyles/Insets;Lcom/unistyles/Dimensions;)V");
|
77
|
+
|
78
|
+
env->CallVoidMethod(unistylesModule, methodId, breakpointStr, orientationStr, screenObj, statusBarObj, insetsObj, navigationBarObj);
|
69
79
|
env->DeleteLocalRef(breakpointStr);
|
70
80
|
env->DeleteLocalRef(orientationStr);
|
71
81
|
env->DeleteLocalRef(cls);
|
@@ -103,9 +113,14 @@ Java_com_unistyles_UnistylesModule_nativeDestroy(JNIEnv *env, jobject thiz) {
|
|
103
113
|
|
104
114
|
extern "C"
|
105
115
|
JNIEXPORT void JNICALL
|
106
|
-
Java_com_unistyles_UnistylesModule_nativeOnOrientationChange(JNIEnv *env, jobject thiz,
|
116
|
+
Java_com_unistyles_UnistylesModule_nativeOnOrientationChange(JNIEnv *env, jobject thiz, jobject screen, jobject insets, jobject statusBar, jobject navigationBar) {
|
107
117
|
if (unistylesRuntime != nullptr) {
|
108
|
-
|
118
|
+
Dimensions screenDimensions = jobjectToDimensions(env, screen);
|
119
|
+
Dimensions statusBarDimensions = jobjectToDimensions(env, statusBar);
|
120
|
+
Insets screenInsets = jobjectToInsets(env, insets);
|
121
|
+
Dimensions navigationBarDimensions = jobjectToDimensions(env, navigationBar);
|
122
|
+
|
123
|
+
unistylesRuntime->handleScreenSizeChange(screenDimensions, screenInsets, statusBarDimensions, navigationBarDimensions);
|
109
124
|
}
|
110
125
|
}
|
111
126
|
|
@@ -1,69 +1,34 @@
|
|
1
1
|
#include "helpers.h"
|
2
|
+
#include "UnistylesRuntime.h"
|
2
3
|
|
3
|
-
|
4
|
-
jclass
|
5
|
-
|
6
|
-
|
4
|
+
Dimensions jobjectToDimensions(JNIEnv *env, jobject dimensionObj) {
|
5
|
+
jclass dimensionClass = env->FindClass("com/unistyles/Dimensions");
|
6
|
+
jfieldID widthFieldID = env->GetFieldID(dimensionClass, "width", "I");
|
7
|
+
jfieldID heightFieldID = env->GetFieldID(dimensionClass, "height", "I");
|
7
8
|
|
8
|
-
env->
|
9
|
+
int width = env->GetIntField(dimensionObj, widthFieldID);
|
10
|
+
int height = env->GetIntField(dimensionObj, heightFieldID);
|
9
11
|
|
10
|
-
|
11
|
-
}
|
12
|
-
|
13
|
-
std::string jstringToStdString(JNIEnv *env, jstring jStr) {
|
14
|
-
if (!jStr) {
|
15
|
-
return "";
|
16
|
-
}
|
17
|
-
|
18
|
-
const jclass stringClass = env->GetObjectClass(jStr);
|
19
|
-
const jmethodID getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B");
|
20
|
-
const jbyteArray stringJbytes = (jbyteArray) env->CallObjectMethod(jStr, getBytes, env->NewStringUTF("UTF-8"));
|
21
|
-
|
22
|
-
size_t length = (size_t) env->GetArrayLength(stringJbytes);
|
23
|
-
jbyte* pBytes = env->GetByteArrayElements(stringJbytes, NULL);
|
24
|
-
|
25
|
-
std::string ret = std::string((char *)pBytes, length);
|
26
|
-
env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT);
|
12
|
+
env->DeleteLocalRef(dimensionClass);
|
27
13
|
|
28
|
-
|
29
|
-
env->DeleteLocalRef(stringClass);
|
30
|
-
|
31
|
-
return ret;
|
14
|
+
return Dimensions{width, height};
|
32
15
|
}
|
33
16
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
jmethodID iteratorMethod = env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
|
41
|
-
jobject set = env->CallObjectMethod(map, entrySetMethod);
|
42
|
-
jobject iterator = env->CallObjectMethod(set, iteratorMethod);
|
43
|
-
jmethodID hasNextMethod = env->GetMethodID(iteratorClass, "hasNext", "()Z");
|
44
|
-
jmethodID nextMethod = env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
|
45
|
-
|
46
|
-
while (env->CallBooleanMethod(iterator, hasNextMethod)) {
|
47
|
-
jobject entry = env->CallObjectMethod(iterator, nextMethod);
|
17
|
+
Insets jobjectToInsets(JNIEnv *env, jobject insetsObj) {
|
18
|
+
jclass insetsClass = env->FindClass("com/unistyles/Insets");
|
19
|
+
jfieldID leftFieldID = env->GetFieldID(insetsClass, "left", "I");
|
20
|
+
jfieldID topFieldID = env->GetFieldID(insetsClass, "top", "I");
|
21
|
+
jfieldID rightFieldID = env->GetFieldID(insetsClass, "right", "I");
|
22
|
+
jfieldID bottomFieldID = env->GetFieldID(insetsClass, "bottom", "I");
|
48
23
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
result[jstringToStdString(env, key)] = jobjectToInt(env, value);
|
55
|
-
|
56
|
-
env->DeleteLocalRef(entry);
|
57
|
-
env->DeleteLocalRef(key);
|
58
|
-
env->DeleteLocalRef(value);
|
59
|
-
}
|
24
|
+
int left = env->GetIntField(insetsObj, leftFieldID);
|
25
|
+
int top = env->GetIntField(insetsObj, topFieldID);
|
26
|
+
int right = env->GetIntField(insetsObj, rightFieldID);
|
27
|
+
int bottom = env->GetIntField(insetsObj, bottomFieldID);
|
60
28
|
|
61
|
-
env->DeleteLocalRef(
|
62
|
-
env->DeleteLocalRef(iterator);
|
63
|
-
env->DeleteLocalRef(setClass);
|
64
|
-
env->DeleteLocalRef(iteratorClass);
|
29
|
+
env->DeleteLocalRef(insetsClass);
|
65
30
|
|
66
|
-
return
|
31
|
+
return Insets{top, bottom, left, right};
|
67
32
|
}
|
68
33
|
|
69
34
|
void throwKotlinException(
|
@@ -1,9 +1,9 @@
|
|
1
1
|
#include <jni.h>
|
2
2
|
#include <string>
|
3
3
|
#include <map>
|
4
|
+
#include <UnistylesRuntime.h>
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
std::map<std::string, int> jobjectToStdMap(JNIEnv *env, jobject map);
|
6
|
+
Dimensions jobjectToDimensions(JNIEnv *env, jobject dimensionObj);
|
7
|
+
Insets jobjectToInsets(JNIEnv *env, jobject insetsObj);
|
8
8
|
|
9
9
|
void throwKotlinException(JNIEnv *env, const char *message);
|
@@ -0,0 +1,116 @@
|
|
1
|
+
package com.unistyles
|
2
|
+
|
3
|
+
import android.annotation.SuppressLint
|
4
|
+
import android.content.res.Configuration
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
6
|
+
|
7
|
+
class UnistylesConfig(private val reactApplicationContext: ReactApplicationContext) {
|
8
|
+
private val insets: UnistylesInsets = UnistylesInsets(reactApplicationContext)
|
9
|
+
private val density: Float = reactApplicationContext.resources.displayMetrics.density
|
10
|
+
private var lastConfig: Config = this.getAppConfig()
|
11
|
+
private var lastLayoutConfig: LayoutConfig = this.getAppLayoutConfig()
|
12
|
+
|
13
|
+
fun hasNewConfig(): Boolean {
|
14
|
+
val newConfig = this.getAppConfig()
|
15
|
+
val newContentSizeCategory = newConfig.contentSizeCategory != lastConfig.contentSizeCategory
|
16
|
+
val newColorScheme = newConfig.colorScheme != lastConfig.colorScheme
|
17
|
+
|
18
|
+
if (!newContentSizeCategory && !newColorScheme) {
|
19
|
+
return false
|
20
|
+
}
|
21
|
+
|
22
|
+
lastConfig = newConfig
|
23
|
+
lastConfig.hasNewContentSizeCategory = newContentSizeCategory
|
24
|
+
lastConfig.hasNewColorScheme = newColorScheme
|
25
|
+
|
26
|
+
return true
|
27
|
+
}
|
28
|
+
|
29
|
+
fun hasNewLayoutConfig(): Boolean {
|
30
|
+
val newConfig = this.getAppLayoutConfig()
|
31
|
+
|
32
|
+
if (newConfig.isEqual(lastLayoutConfig)) {
|
33
|
+
return false
|
34
|
+
}
|
35
|
+
|
36
|
+
lastLayoutConfig = newConfig
|
37
|
+
|
38
|
+
return true
|
39
|
+
}
|
40
|
+
|
41
|
+
fun getConfig(): Config {
|
42
|
+
return this.lastConfig
|
43
|
+
}
|
44
|
+
|
45
|
+
fun getLayoutConfig(): LayoutConfig {
|
46
|
+
return this.lastLayoutConfig
|
47
|
+
}
|
48
|
+
|
49
|
+
private fun getAppConfig(): Config {
|
50
|
+
val fontScale = reactApplicationContext.resources.configuration.fontScale
|
51
|
+
|
52
|
+
return Config(
|
53
|
+
this.getColorScheme(),
|
54
|
+
this.getContentSizeCategory(fontScale),
|
55
|
+
)
|
56
|
+
}
|
57
|
+
|
58
|
+
private fun getAppLayoutConfig(): LayoutConfig {
|
59
|
+
val displayMetrics = reactApplicationContext.resources.displayMetrics
|
60
|
+
val screenWidth = (displayMetrics.widthPixels / density).toInt()
|
61
|
+
val screenHeight = (displayMetrics.heightPixels / density).toInt()
|
62
|
+
|
63
|
+
return LayoutConfig(
|
64
|
+
Dimensions(screenWidth, screenHeight),
|
65
|
+
this.insets.get(),
|
66
|
+
Dimensions(screenWidth, getStatusBarHeight()),
|
67
|
+
Dimensions(screenWidth, getNavigationBarHeight())
|
68
|
+
)
|
69
|
+
}
|
70
|
+
|
71
|
+
private fun getContentSizeCategory(fontScale: Float): String {
|
72
|
+
val contentSizeCategory = when {
|
73
|
+
fontScale <= 0.85f -> "Small"
|
74
|
+
fontScale <= 1.0f -> "Default"
|
75
|
+
fontScale <= 1.15f -> "Large"
|
76
|
+
fontScale <= 1.3f -> "ExtraLarge"
|
77
|
+
fontScale <= 1.5f -> "Huge"
|
78
|
+
fontScale <= 1.8 -> "ExtraHuge"
|
79
|
+
else -> "ExtraExtraHuge"
|
80
|
+
}
|
81
|
+
|
82
|
+
return contentSizeCategory
|
83
|
+
}
|
84
|
+
|
85
|
+
private fun getColorScheme(): String {
|
86
|
+
val colorScheme = when (reactApplicationContext.resources.configuration.uiMode.and(Configuration.UI_MODE_NIGHT_MASK)) {
|
87
|
+
Configuration.UI_MODE_NIGHT_YES -> "dark"
|
88
|
+
Configuration.UI_MODE_NIGHT_NO -> "light"
|
89
|
+
else -> "unspecified"
|
90
|
+
}
|
91
|
+
|
92
|
+
return colorScheme
|
93
|
+
}
|
94
|
+
|
95
|
+
@SuppressLint("InternalInsetResource", "DiscouragedApi")
|
96
|
+
private fun getStatusBarHeight(): Int {
|
97
|
+
val heightResId = reactApplicationContext.resources.getIdentifier("status_bar_height", "dimen", "android")
|
98
|
+
|
99
|
+
if (heightResId > 0) {
|
100
|
+
return (reactApplicationContext.resources.getDimensionPixelSize(heightResId) / density).toInt()
|
101
|
+
}
|
102
|
+
|
103
|
+
return 0
|
104
|
+
}
|
105
|
+
|
106
|
+
@SuppressLint("InternalInsetResource", "DiscouragedApi")
|
107
|
+
private fun getNavigationBarHeight(): Int {
|
108
|
+
val heightResId = reactApplicationContext.resources.getIdentifier("navigation_bar_height", "dimen", "android")
|
109
|
+
|
110
|
+
if (heightResId > 0) {
|
111
|
+
return (reactApplicationContext.resources.getDimensionPixelSize(heightResId) / density).toInt()
|
112
|
+
}
|
113
|
+
|
114
|
+
return 0
|
115
|
+
}
|
116
|
+
}
|
@@ -0,0 +1,138 @@
|
|
1
|
+
package com.unistyles
|
2
|
+
|
3
|
+
import android.content.Context
|
4
|
+
import android.graphics.Rect
|
5
|
+
import android.os.Build
|
6
|
+
import android.view.View
|
7
|
+
import android.view.Window
|
8
|
+
import android.view.WindowInsets
|
9
|
+
import android.view.WindowManager
|
10
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
11
|
+
import kotlin.math.roundToInt
|
12
|
+
|
13
|
+
class UnistylesInsets(private val reactApplicationContext: ReactApplicationContext) {
|
14
|
+
private val density: Float = reactApplicationContext.resources.displayMetrics.density
|
15
|
+
|
16
|
+
fun get(): Insets {
|
17
|
+
return this.getCurrentInsets()
|
18
|
+
}
|
19
|
+
|
20
|
+
private fun getCurrentInsets(): Insets {
|
21
|
+
val baseInsets = this.getBaseInsets()
|
22
|
+
val statusBarTranslucent = this.hasTranslucentStatusBar(baseInsets) ?: return baseInsets
|
23
|
+
val window = reactApplicationContext.currentActivity?.window ?: return baseInsets
|
24
|
+
val shouldModifyLandscapeInsets = this.forceLandscapeInsets(baseInsets, window)
|
25
|
+
|
26
|
+
val topInset = this.getTopInset(baseInsets, statusBarTranslucent, window)
|
27
|
+
val bottomInset = this.getBottomInset(baseInsets, window)
|
28
|
+
val leftInset = if (shouldModifyLandscapeInsets) 0 else baseInsets.left
|
29
|
+
val rightInset = if (shouldModifyLandscapeInsets) 0 else baseInsets.right
|
30
|
+
|
31
|
+
return Insets(topInset, bottomInset, leftInset, rightInset)
|
32
|
+
}
|
33
|
+
|
34
|
+
@Suppress("DEPRECATION")
|
35
|
+
private fun getBaseInsets(): Insets {
|
36
|
+
// this is the best API, but it's available from Android 11
|
37
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
38
|
+
val windowManager = reactApplicationContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
39
|
+
val systemBarsInsets = windowManager.currentWindowMetrics.windowInsets.getInsets(WindowInsets.Type.systemBars())
|
40
|
+
|
41
|
+
val top = (systemBarsInsets.top / density).roundToInt()
|
42
|
+
val bottom = (systemBarsInsets.bottom / density).roundToInt()
|
43
|
+
val left = (systemBarsInsets.left / density).roundToInt()
|
44
|
+
val right = (systemBarsInsets.right / density).roundToInt()
|
45
|
+
|
46
|
+
return Insets(top, bottom, left, right)
|
47
|
+
}
|
48
|
+
|
49
|
+
// available from Android 6.0
|
50
|
+
val window = reactApplicationContext.currentActivity?.window ?: return Insets(0, 0, 0, 0)
|
51
|
+
val systemInsets = window.decorView.rootWindowInsets
|
52
|
+
|
53
|
+
val top = (systemInsets.systemWindowInsetTop / density).roundToInt()
|
54
|
+
val bottom = (systemInsets.systemWindowInsetBottom / density).roundToInt()
|
55
|
+
val left = (systemInsets.systemWindowInsetLeft / density).roundToInt()
|
56
|
+
val right = (systemInsets.systemWindowInsetRight / density).roundToInt()
|
57
|
+
|
58
|
+
return Insets(top, bottom, left, right)
|
59
|
+
}
|
60
|
+
|
61
|
+
// this function helps to detect statusBar translucent, as React Native is using weird API instead of windows flags
|
62
|
+
private fun hasTranslucentStatusBar(baseInsets: Insets): Boolean? {
|
63
|
+
val window = reactApplicationContext.currentActivity?.window ?: return null
|
64
|
+
val contentView = window.decorView.findViewById<View>(android.R.id.content) ?: return null
|
65
|
+
val decorViewLocation = IntArray(2)
|
66
|
+
val contentViewLocation = IntArray(2)
|
67
|
+
|
68
|
+
// decor view is a top level view with navigationBar and statusBar
|
69
|
+
window.decorView.getLocationOnScreen(decorViewLocation)
|
70
|
+
// content view is view without navigationBar and statusBar
|
71
|
+
contentView.getLocationOnScreen(contentViewLocation)
|
72
|
+
|
73
|
+
val statusBarHeight = contentViewLocation[1] - decorViewLocation[1]
|
74
|
+
|
75
|
+
// if positions are the same, then the status bar is translucent
|
76
|
+
return statusBarHeight == 0
|
77
|
+
}
|
78
|
+
|
79
|
+
private fun getTopInset(baseInsets: Insets, statusBarTranslucent: Boolean, window: Window): Int {
|
80
|
+
if (!statusBarTranslucent) {
|
81
|
+
return 0
|
82
|
+
}
|
83
|
+
|
84
|
+
return baseInsets.top
|
85
|
+
}
|
86
|
+
|
87
|
+
@Suppress("DEPRECATION")
|
88
|
+
private fun getBottomInset(baseInsets: Insets, window: Window): Int {
|
89
|
+
val translucentNavigation = hasTranslucentNavigation(window)
|
90
|
+
|
91
|
+
// Android 11 has inconsistent FLAG_LAYOUT_NO_LIMITS, which alone does nothing
|
92
|
+
// https://stackoverflow.com/questions/64153785/android-11-window-setdecorfitssystemwindow-doesnt-show-screen-behind-status-a
|
93
|
+
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
|
94
|
+
if ((hasFullScreenMode(window) && translucentNavigation) || translucentNavigation) {
|
95
|
+
return baseInsets.bottom
|
96
|
+
}
|
97
|
+
|
98
|
+
return 0
|
99
|
+
}
|
100
|
+
|
101
|
+
return if (hasTranslucentNavigation(window) || hasFullScreenMode(window)) baseInsets.bottom else 0
|
102
|
+
}
|
103
|
+
|
104
|
+
private fun forceLandscapeInsets(baseInsets: Insets, window: Window): Boolean {
|
105
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
106
|
+
return false
|
107
|
+
}
|
108
|
+
|
109
|
+
val displayMetrics = reactApplicationContext.resources.displayMetrics
|
110
|
+
val isLandscape = displayMetrics.widthPixels > displayMetrics.heightPixels
|
111
|
+
|
112
|
+
if (!isLandscape) {
|
113
|
+
return false
|
114
|
+
}
|
115
|
+
|
116
|
+
val contentView = window.decorView.findViewById<View>(android.R.id.content) ?: return false
|
117
|
+
val visibleRect = Rect()
|
118
|
+
val drawingRect = Rect()
|
119
|
+
|
120
|
+
window.decorView.getGlobalVisibleRect(visibleRect)
|
121
|
+
contentView.getDrawingRect(drawingRect)
|
122
|
+
|
123
|
+
// width is equal to navigationBarHeight + statusBarHeight (in landscape)
|
124
|
+
val width = ((visibleRect.width() - contentView.width) / density).roundToInt()
|
125
|
+
|
126
|
+
// we should correct landscape if insets are equal to width
|
127
|
+
return (baseInsets.left + baseInsets.right) == width
|
128
|
+
}
|
129
|
+
|
130
|
+
@Suppress("DEPRECATION")
|
131
|
+
private fun hasTranslucentNavigation(window: Window): Boolean {
|
132
|
+
return (window.attributes.flags and WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) == WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
|
133
|
+
}
|
134
|
+
|
135
|
+
private fun hasFullScreenMode(window: Window): Boolean {
|
136
|
+
return (window.attributes.flags and WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS) == WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
|
137
|
+
}
|
138
|
+
}
|
@@ -0,0 +1,85 @@
|
|
1
|
+
package com.unistyles
|
2
|
+
|
3
|
+
class Dimensions(var width: Int, var height: Int) {
|
4
|
+
fun isEqual(dimensions: Dimensions): Boolean {
|
5
|
+
if (this.width != dimensions.width) {
|
6
|
+
return false
|
7
|
+
}
|
8
|
+
|
9
|
+
return this.height == dimensions.height
|
10
|
+
}
|
11
|
+
|
12
|
+
override fun toString(): String {
|
13
|
+
return "${width}x${height}"
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
class Insets(var top: Int, var bottom: Int, var left: Int, var right: Int) {
|
18
|
+
fun isEqual(insets: Insets): Boolean {
|
19
|
+
if (this.top != insets.top) {
|
20
|
+
return false
|
21
|
+
}
|
22
|
+
|
23
|
+
if (this.bottom != insets.bottom) {
|
24
|
+
return false
|
25
|
+
}
|
26
|
+
|
27
|
+
if (this.left != insets.left) {
|
28
|
+
return false
|
29
|
+
}
|
30
|
+
|
31
|
+
return this.right == insets.right
|
32
|
+
}
|
33
|
+
|
34
|
+
override fun toString(): String {
|
35
|
+
return "T:${top}B:${bottom}L:${left}R:${right}"
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
class LayoutConfig(
|
40
|
+
val screen: Dimensions,
|
41
|
+
val insets: Insets,
|
42
|
+
val statusBar: Dimensions,
|
43
|
+
val navigationBar: Dimensions
|
44
|
+
) {
|
45
|
+
fun isEqual(config: LayoutConfig): Boolean {
|
46
|
+
if (!this.screen.isEqual(config.screen)) {
|
47
|
+
return false
|
48
|
+
}
|
49
|
+
|
50
|
+
if (!this.insets.isEqual(config.insets)) {
|
51
|
+
return false
|
52
|
+
}
|
53
|
+
|
54
|
+
if (!this.statusBar.isEqual(config.statusBar)) {
|
55
|
+
return false
|
56
|
+
}
|
57
|
+
|
58
|
+
return this.navigationBar.isEqual(config.navigationBar)
|
59
|
+
}
|
60
|
+
|
61
|
+
override fun toString(): String {
|
62
|
+
return buildString {
|
63
|
+
append("screen=")
|
64
|
+
append(screen)
|
65
|
+
append(" insets=")
|
66
|
+
append(insets)
|
67
|
+
append(" statusBar=")
|
68
|
+
append(statusBar)
|
69
|
+
append(" navigationBar=")
|
70
|
+
append(navigationBar)
|
71
|
+
}
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
class Config(
|
76
|
+
val colorScheme: String,
|
77
|
+
val contentSizeCategory: String,
|
78
|
+
) {
|
79
|
+
var hasNewColorScheme: Boolean = false
|
80
|
+
var hasNewContentSizeCategory: Boolean = false
|
81
|
+
|
82
|
+
override fun toString(): String {
|
83
|
+
return "colorScheme=${colorScheme} contentSizeCategory:${contentSizeCategory}"
|
84
|
+
}
|
85
|
+
}
|
@@ -1,92 +1,23 @@
|
|
1
1
|
package com.unistyles
|
2
2
|
|
3
|
-
import android.annotation.SuppressLint
|
4
|
-
import android.content.res.Configuration
|
5
|
-
import android.os.Build
|
6
|
-
import android.view.WindowInsets
|
7
3
|
import com.facebook.react.bridge.ReactApplicationContext
|
8
4
|
|
9
|
-
class Platform(
|
10
|
-
|
11
|
-
fun getConfig(): Map<String, Any> {
|
12
|
-
val displayMetrics = reactApplicationContext.resources.displayMetrics
|
13
|
-
val fontScale = reactApplicationContext.resources.configuration.fontScale
|
14
|
-
val screenWidth = (displayMetrics.widthPixels / displayMetrics.density).toInt()
|
15
|
-
val screenHeight = (displayMetrics.heightPixels / displayMetrics.density).toInt()
|
5
|
+
class Platform(reactApplicationContext: ReactApplicationContext) {
|
6
|
+
private val config: UnistylesConfig = UnistylesConfig(reactApplicationContext)
|
16
7
|
|
17
|
-
|
18
|
-
|
19
|
-
"height" to screenHeight,
|
20
|
-
"colorScheme" to getColorScheme(),
|
21
|
-
"contentSizeCategory" to getContentSizeCategory(fontScale),
|
22
|
-
"insets" to getScreenInsets(displayMetrics.density),
|
23
|
-
"statusBar" to mapOf(
|
24
|
-
"height" to getStatusBarHeight(displayMetrics.density),
|
25
|
-
"width" to screenWidth
|
26
|
-
)
|
27
|
-
)
|
8
|
+
fun hasNewLayoutConfig(): Boolean {
|
9
|
+
return this.config.hasNewLayoutConfig()
|
28
10
|
}
|
29
11
|
|
30
|
-
|
31
|
-
|
32
|
-
fontScale <= 0.85f -> "Small"
|
33
|
-
fontScale <= 1.0f -> "Default"
|
34
|
-
fontScale <= 1.15f -> "Large"
|
35
|
-
fontScale <= 1.3f -> "ExtraLarge"
|
36
|
-
else -> "Huge"
|
37
|
-
}
|
38
|
-
|
39
|
-
return contentSizeCategory
|
40
|
-
}
|
41
|
-
|
42
|
-
private fun getColorScheme(): String {
|
43
|
-
val colorScheme = when (reactApplicationContext.resources.configuration.uiMode.and(Configuration.UI_MODE_NIGHT_MASK)) {
|
44
|
-
Configuration.UI_MODE_NIGHT_YES -> "dark"
|
45
|
-
Configuration.UI_MODE_NIGHT_NO -> "light"
|
46
|
-
else -> "unspecified"
|
47
|
-
}
|
48
|
-
|
49
|
-
return colorScheme
|
12
|
+
fun hasNewConfig(): Boolean {
|
13
|
+
return this.config.hasNewConfig()
|
50
14
|
}
|
51
15
|
|
52
|
-
|
53
|
-
|
54
|
-
val insets = mutableMapOf(
|
55
|
-
"top" to 0,
|
56
|
-
"bottom" to 0,
|
57
|
-
"left" to 0,
|
58
|
-
"right" to 0
|
59
|
-
)
|
60
|
-
|
61
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
62
|
-
val systemInsets = reactApplicationContext.currentActivity?.window?.decorView?.rootWindowInsets?.getInsets(WindowInsets.Type.displayCutout())
|
63
|
-
|
64
|
-
insets["top"] = ((systemInsets?.top ?: 0) / density).toInt()
|
65
|
-
insets["bottom"] = ((systemInsets?.bottom ?: 0) / density).toInt()
|
66
|
-
insets["left"] = ((systemInsets?.left ?: 0) / density).toInt()
|
67
|
-
insets["right"] = ((systemInsets?.right ?: 0) / density).toInt()
|
68
|
-
|
69
|
-
return insets
|
70
|
-
}
|
71
|
-
|
72
|
-
val systemInsets = reactApplicationContext.currentActivity?.window?.decorView?.rootWindowInsets
|
73
|
-
|
74
|
-
insets["top"] = ((systemInsets?.systemWindowInsetTop ?: 0) / density).toInt()
|
75
|
-
insets["bottom"] = ((systemInsets?.systemWindowInsetBottom ?: 0) / density).toInt()
|
76
|
-
insets["left"] = ((systemInsets?.systemWindowInsetLeft ?: 0) / density).toInt()
|
77
|
-
insets["right"] = ((systemInsets?.systemWindowInsetRight ?: 0) / density).toInt()
|
78
|
-
|
79
|
-
return insets
|
16
|
+
fun getConfig(): Config {
|
17
|
+
return this.config.getConfig()
|
80
18
|
}
|
81
19
|
|
82
|
-
|
83
|
-
|
84
|
-
val heightResId = reactApplicationContext.resources.getIdentifier("status_bar_height", "dimen", "android")
|
85
|
-
|
86
|
-
if (heightResId > 0) {
|
87
|
-
return (reactApplicationContext.resources.getDimensionPixelSize(heightResId) / density).toInt()
|
88
|
-
}
|
89
|
-
|
90
|
-
return 0
|
20
|
+
fun getLayoutConfig(): LayoutConfig {
|
21
|
+
return this.config.getLayoutConfig()
|
91
22
|
}
|
92
23
|
}
|