react-native-navigation-mode 1.2.6 → 1.2.8-beta.1
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 +1 -1
- package/android/src/main/java/com/navigationmode/NavigationModeModule.kt +79 -17
- package/lib/module/NativeNavigationMode.js +4 -1
- package/lib/module/NativeNavigationMode.js.map +1 -1
- package/lib/typescript/src/NativeNavigationMode.d.ts.map +1 -1
- package/package.json +18 -15
- package/src/NativeNavigationMode.ts +8 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
🧭 Detect Android navigation mode (3-button, 2-button, or gesture navigation) with native precision using Turbo modules.
|
|
4
4
|
|
|
5
|
-
[](https://badge.fury.io/js/react-native-navigation-mode) [](https://github.com/JairajJangle/react-native-navigation-mode/blob/main/LICENSE) [](https://github.com/JairajJangle/react-native-navigation-mode/actions/workflows/ci.yml)   [](https://github.com/JairajJangle/react-native-navigation-mode/issues?q=is%3Aopen+is%3Aissue)    
|
|
5
|
+
[](https://badge.fury.io/js/react-native-navigation-mode) [](https://github.com/JairajJangle/react-native-navigation-mode/blob/main/LICENSE) [](https://github.com/JairajJangle/react-native-navigation-mode/actions/workflows/ci.yml)   [](https://github.com/JairajJangle/react-native-navigation-mode/issues?q=is%3Aopen+is%3Aissue)     [](https://github.com/sponsors/JairajJangle)
|
|
6
6
|
|
|
7
7
|
<table align="center">
|
|
8
8
|
<tr>
|
|
@@ -67,12 +67,18 @@ class NavigationModeModule(reactContext: ReactApplicationContext) :
|
|
|
67
67
|
|
|
68
68
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
69
69
|
val navBarInteractionMode = getNavBarInteractionMode(context)
|
|
70
|
+
val isGesture = if (navBarInteractionMode == 2) true else isGestureNavigationBySettings(context)
|
|
70
71
|
result.putInt("interactionMode", navBarInteractionMode)
|
|
71
|
-
result.putString(
|
|
72
|
-
|
|
72
|
+
result.putString(
|
|
73
|
+
"type",
|
|
74
|
+
if (isGesture) "gesture" else getNavigationTypeFromInteractionMode(navBarInteractionMode)
|
|
75
|
+
)
|
|
76
|
+
result.putBoolean("isGestureNavigation", isGesture)
|
|
73
77
|
} else {
|
|
74
|
-
val gestureNavEnabled =
|
|
78
|
+
val gestureNavEnabled = isGestureNavigationBySettings(context)
|
|
75
79
|
result.putBoolean("isGestureNavigation", gestureNavEnabled)
|
|
80
|
+
// Set "type" for pre-Q devices so the field is always present in the result
|
|
81
|
+
result.putString("type", if (gestureNavEnabled) "gesture" else "unknown")
|
|
76
82
|
}
|
|
77
83
|
|
|
78
84
|
promise.resolve(result)
|
|
@@ -87,9 +93,10 @@ class NavigationModeModule(reactContext: ReactApplicationContext) :
|
|
|
87
93
|
|
|
88
94
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
89
95
|
val navBarInteractionMode = getNavBarInteractionMode(context)
|
|
90
|
-
|
|
96
|
+
val isGesture = if (navBarInteractionMode == 2) true else isGestureNavigationBySettings(context)
|
|
97
|
+
promise.resolve(isGesture)
|
|
91
98
|
} else {
|
|
92
|
-
val gestureEnabled =
|
|
99
|
+
val gestureEnabled = isGestureNavigationBySettings(context)
|
|
93
100
|
promise.resolve(gestureEnabled)
|
|
94
101
|
}
|
|
95
102
|
} catch (e: Exception) {
|
|
@@ -120,17 +127,72 @@ class NavigationModeModule(reactContext: ReactApplicationContext) :
|
|
|
120
127
|
}
|
|
121
128
|
}
|
|
122
129
|
|
|
123
|
-
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
return
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
// Detects gesture navigation via Settings providers. Used as:
|
|
131
|
+
// - The sole detection method on pre-Android Q (API < 29) devices.
|
|
132
|
+
// - A supplementary fallback on Android Q+ when config_navBarInteractionMode does not
|
|
133
|
+
// return 2, since some OEM firmwares (e.g. Huawei Mate 30 Pro) leave that resource at
|
|
134
|
+
// its default value of 0 even after the user enables gesture navigation.
|
|
135
|
+
private fun isGestureNavigationBySettings(context: Context): Boolean {
|
|
136
|
+
// Standard AOSP key available on Android 10+ stock and most OEMs.
|
|
137
|
+
// "2" = gesture, "0" = 3-button, "1" = 2-button.
|
|
138
|
+
try {
|
|
139
|
+
val navBarMode = Settings.Secure.getString(
|
|
140
|
+
context.contentResolver,
|
|
141
|
+
"navigation_mode"
|
|
142
|
+
)
|
|
143
|
+
if ("2" == navBarMode) {
|
|
144
|
+
return true
|
|
145
|
+
}
|
|
146
|
+
if ("0" == navBarMode || "1" == navBarMode) {
|
|
147
|
+
return false
|
|
148
|
+
}
|
|
149
|
+
} catch (e: Exception) {
|
|
150
|
+
// Ignore and continue with OEM-specific fallbacks
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Huawei / Honor EMUI: written to Settings.Global when the user collapses the nav bar
|
|
154
|
+
// into the gesture handle. Value 1 = gestures enabled.
|
|
155
|
+
val huaweiNavigationBarMinGlobal = getGlobalIntSetting(context, "navigationbar_is_min")
|
|
156
|
+
if (huaweiNavigationBarMinGlobal != null) {
|
|
157
|
+
return huaweiNavigationBarMinGlobal == 1
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Huawei / Honor EMUI (alternate key seen on some firmware versions).
|
|
161
|
+
// Value 1 = gesture navigation enabled.
|
|
162
|
+
val huaweiSecureGesture = getSecureIntSetting(context, "secure_gesture_navigation")
|
|
163
|
+
if (huaweiSecureGesture != null) {
|
|
164
|
+
return huaweiSecureGesture == 1
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Xiaomi MIUI: set to 1 when the "full-screen gesture" nav bar is active.
|
|
168
|
+
val xiaomiForceGesture = getGlobalIntSetting(context, "force_fsg_nav_bar")
|
|
169
|
+
if (xiaomiForceGesture != null) {
|
|
170
|
+
return xiaomiForceGesture == 1
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Samsung One UI: toggled when the user switches to "Swipe gestures" in nav bar settings.
|
|
174
|
+
// Value 1 = gesture navigation enabled.
|
|
175
|
+
val samsungNavigationGesture = getSecureIntSetting(context, "navigation_gesture_on")
|
|
176
|
+
if (samsungNavigationGesture != null) {
|
|
177
|
+
return samsungNavigationGesture == 1
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return false
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
private fun getSecureIntSetting(context: Context, key: String): Int? {
|
|
184
|
+
return try {
|
|
185
|
+
Settings.Secure.getInt(context.contentResolver, key)
|
|
186
|
+
} catch (e: Exception) {
|
|
187
|
+
null
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private fun getGlobalIntSetting(context: Context, key: String): Int? {
|
|
192
|
+
return try {
|
|
193
|
+
Settings.Global.getInt(context.contentResolver, key)
|
|
194
|
+
} catch (e: Exception) {
|
|
195
|
+
null
|
|
196
|
+
}
|
|
134
197
|
}
|
|
135
|
-
}
|
|
136
198
|
}
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
import { TurboModuleRegistry, Platform } from 'react-native';
|
|
4
4
|
// Only get the native module on Android
|
|
5
5
|
// On iOS, we'll handle everything in JavaScript
|
|
6
|
-
const NativeModule = Platform.OS === 'android' ? TurboModuleRegistry.getEnforcing('NavigationMode') :
|
|
6
|
+
const NativeModule = Platform.OS === 'android' ? TurboModuleRegistry?.getEnforcing ? TurboModuleRegistry.getEnforcing('NavigationMode') : (() => {
|
|
7
|
+
console.error("['react-native-navigation-mode'] TurboModuleRegistry.getEnforcing is not available. Make sure you have enabled the New Architecture (TurboModules) in your project.");
|
|
8
|
+
return null;
|
|
9
|
+
})() : null;
|
|
7
10
|
export default NativeModule;
|
|
8
11
|
//# sourceMappingURL=NativeNavigationMode.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["TurboModuleRegistry","Platform","NativeModule","OS","getEnforcing"],"sourceRoot":"../../src","sources":["NativeNavigationMode.ts"],"mappings":";;AACA,SAASA,mBAAmB,EAAEC,QAAQ,QAAQ,cAAc;AAe5D;AACA;AACA,MAAMC,YAAY,GAChBD,QAAQ,CAACE,EAAE,KAAK,SAAS,GACrBH,mBAAmB,CAACI,YAAY,CAAO,gBAAgB,CAAC,GACxD,IAAI;AAEV,
|
|
1
|
+
{"version":3,"names":["TurboModuleRegistry","Platform","NativeModule","OS","getEnforcing","console","error"],"sourceRoot":"../../src","sources":["NativeNavigationMode.ts"],"mappings":";;AACA,SAASA,mBAAmB,EAAEC,QAAQ,QAAQ,cAAc;AAe5D;AACA;AACA,MAAMC,YAAY,GAChBD,QAAQ,CAACE,EAAE,KAAK,SAAS,GACrBH,mBAAmB,EAAEI,YAAY,GAC/BJ,mBAAmB,CAACI,YAAY,CAAO,gBAAgB,CAAC,GACxD,CAAC,MAAM;EACPC,OAAO,CAACC,KAAK,CACX,qKACF,CAAC;EACD,OAAO,IAAI;AACb,CAAC,EAAE,CAAC,GACJ,IAAI;AAEV,eAAeJ,YAAY","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeNavigationMode.d.ts","sourceRoot":"","sources":["../../../src/NativeNavigationMode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;IACtD,mBAAmB,EAAE,OAAO,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,iBAAiB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACjD,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACxC,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3C;AAID,QAAA,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"NativeNavigationMode.d.ts","sourceRoot":"","sources":["../../../src/NativeNavigationMode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;IACtD,mBAAmB,EAAE,OAAO,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,iBAAiB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACjD,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACxC,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3C;AAID,QAAA,MAAM,YAAY,aAUR,CAAC;AAEX,eAAe,YAAY,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-navigation-mode",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.8-beta.1",
|
|
4
4
|
"description": "Detect Android navigation mode (3-button, 2-button, or gesture)",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"react-native": "./lib/module/index.js",
|
|
@@ -66,31 +66,34 @@
|
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@commitlint/config-conventional": "^19.6.0",
|
|
68
68
|
"@eslint/compat": "^1.2.7",
|
|
69
|
-
"@eslint/eslintrc": "^3.3.
|
|
69
|
+
"@eslint/eslintrc": "^3.3.3",
|
|
70
70
|
"@eslint/js": "^9.22.0",
|
|
71
71
|
"@evilmartians/lefthook": "^1.5.0",
|
|
72
72
|
"@expo/config-plugins": "^10.1.2",
|
|
73
|
-
"@react-native/babel-preset": "0.79.
|
|
74
|
-
"@react-native/eslint-config": "0.79.
|
|
75
|
-
"@release-it/conventional-changelog": "^9.0.
|
|
73
|
+
"@react-native/babel-preset": "0.79.7",
|
|
74
|
+
"@react-native/eslint-config": "0.79.7",
|
|
75
|
+
"@release-it/conventional-changelog": "^9.0.4",
|
|
76
76
|
"@semantic-release/changelog": "^6.0.3",
|
|
77
77
|
"@semantic-release/git": "^10.0.1",
|
|
78
|
-
"@semantic-release/github": "^
|
|
79
|
-
"@semantic-release/npm": "^
|
|
78
|
+
"@semantic-release/github": "^12.0.5",
|
|
79
|
+
"@semantic-release/npm": "^13.1.4",
|
|
80
|
+
"@testing-library/react-hooks": "^8.0.1",
|
|
81
|
+
"@testing-library/react-native": "^13.3.3",
|
|
80
82
|
"@types/jest": "^29.5.5",
|
|
81
83
|
"@types/react": "^19.0.0",
|
|
82
|
-
"commitlint": "^
|
|
83
|
-
"del-cli": "^
|
|
84
|
+
"commitlint": "^20.4.1",
|
|
85
|
+
"del-cli": "^7.0.0",
|
|
84
86
|
"eslint": "^9.22.0",
|
|
85
|
-
"eslint-config-prettier": "^10.1.
|
|
87
|
+
"eslint-config-prettier": "^10.1.8",
|
|
86
88
|
"eslint-plugin-prettier": "^5.2.3",
|
|
87
89
|
"jest": "^29.7.0",
|
|
88
90
|
"prettier": "^3.0.3",
|
|
89
91
|
"react": "19.0.0",
|
|
90
|
-
"react-native": "0.79.
|
|
91
|
-
"react-native-builder-bob": "^0.40.
|
|
92
|
-
"
|
|
93
|
-
"
|
|
92
|
+
"react-native": "0.79.7",
|
|
93
|
+
"react-native-builder-bob": "^0.40.17",
|
|
94
|
+
"react-test-renderer": "19.0.0",
|
|
95
|
+
"release-it": "^19.2.4",
|
|
96
|
+
"semantic-release": "^25.0.3",
|
|
94
97
|
"turbo": "^1.10.7",
|
|
95
98
|
"typescript": "^5.8.3"
|
|
96
99
|
},
|
|
@@ -107,7 +110,7 @@
|
|
|
107
110
|
"workspaces": [
|
|
108
111
|
"example"
|
|
109
112
|
],
|
|
110
|
-
"packageManager": "yarn@
|
|
113
|
+
"packageManager": "yarn@4.9.2",
|
|
111
114
|
"jest": {
|
|
112
115
|
"preset": "react-native",
|
|
113
116
|
"modulePathIgnorePatterns": [
|
|
@@ -18,7 +18,14 @@ export interface Spec extends TurboModule {
|
|
|
18
18
|
// On iOS, we'll handle everything in JavaScript
|
|
19
19
|
const NativeModule =
|
|
20
20
|
Platform.OS === 'android'
|
|
21
|
-
? TurboModuleRegistry
|
|
21
|
+
? TurboModuleRegistry?.getEnforcing
|
|
22
|
+
? TurboModuleRegistry.getEnforcing<Spec>('NavigationMode')
|
|
23
|
+
: (() => {
|
|
24
|
+
console.error(
|
|
25
|
+
"['react-native-navigation-mode'] TurboModuleRegistry.getEnforcing is not available. Make sure you have enabled the New Architecture (TurboModules) in your project."
|
|
26
|
+
);
|
|
27
|
+
return null;
|
|
28
|
+
})()
|
|
22
29
|
: null;
|
|
23
30
|
|
|
24
31
|
export default NativeModule;
|