@tenthdart/react-native-nitro-orientation-locker 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 +21 -0
- package/NitroOrientationLocker.podspec +30 -0
- package/README.md +98 -0
- package/android/CMakeLists.txt +13 -0
- package/android/build.gradle +138 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/java/com/margelo/nitro/orientationlocker/HybridOrientationLocker.kt +99 -0
- package/ios/HybridOrientationLocker.swift +118 -0
- package/ios/OrientationGate.swift +22 -0
- package/lib/commonjs/OrientationLocker.nitro.js +6 -0
- package/lib/commonjs/OrientationLocker.nitro.js.map +1 -0
- package/lib/commonjs/OrientationLockerProvider.js +25 -0
- package/lib/commonjs/OrientationLockerProvider.js.map +1 -0
- package/lib/commonjs/index.js +33 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/module/OrientationLocker.nitro.js +4 -0
- package/lib/module/OrientationLocker.nitro.js.map +1 -0
- package/lib/module/OrientationLockerProvider.js +20 -0
- package/lib/module/OrientationLockerProvider.js.map +1 -0
- package/lib/module/index.js +23 -0
- package/lib/module/index.js.map +1 -0
- package/lib/typescript/OrientationLocker.nitro.d.ts +36 -0
- package/lib/typescript/OrientationLocker.nitro.d.ts.map +1 -0
- package/lib/typescript/OrientationLockerProvider.d.ts +12 -0
- package/lib/typescript/OrientationLockerProvider.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +11 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/nitro.json +24 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/NitroOrientationLocker+autolinking.cmake +81 -0
- package/nitrogen/generated/android/NitroOrientationLocker+autolinking.gradle +27 -0
- package/nitrogen/generated/android/NitroOrientationLockerOnLoad.cpp +54 -0
- package/nitrogen/generated/android/NitroOrientationLockerOnLoad.hpp +34 -0
- package/nitrogen/generated/android/c++/JHybridOrientationLockerSpec.cpp +71 -0
- package/nitrogen/generated/android/c++/JHybridOrientationLockerSpec.hpp +66 -0
- package/nitrogen/generated/android/c++/JOrientation.hpp +70 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/orientationlocker/HybridOrientationLockerSpec.kt +68 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/orientationlocker/NitroOrientationLockerOnLoad.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/orientationlocker/Orientation.kt +27 -0
- package/nitrogen/generated/ios/NitroOrientationLocker+autolinking.rb +62 -0
- package/nitrogen/generated/ios/NitroOrientationLocker-Swift-Cxx-Bridge.cpp +33 -0
- package/nitrogen/generated/ios/NitroOrientationLocker-Swift-Cxx-Bridge.hpp +51 -0
- package/nitrogen/generated/ios/NitroOrientationLocker-Swift-Cxx-Umbrella.hpp +46 -0
- package/nitrogen/generated/ios/NitroOrientationLockerAutolinking.mm +33 -0
- package/nitrogen/generated/ios/NitroOrientationLockerAutolinking.swift +26 -0
- package/nitrogen/generated/ios/c++/HybridOrientationLockerSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridOrientationLockerSpecSwift.hpp +99 -0
- package/nitrogen/generated/ios/swift/HybridOrientationLockerSpec.swift +58 -0
- package/nitrogen/generated/ios/swift/HybridOrientationLockerSpec_cxx.swift +171 -0
- package/nitrogen/generated/ios/swift/Orientation.swift +56 -0
- package/nitrogen/generated/shared/c++/HybridOrientationLockerSpec.cpp +25 -0
- package/nitrogen/generated/shared/c++/HybridOrientationLockerSpec.hpp +66 -0
- package/nitrogen/generated/shared/c++/Orientation.hpp +92 -0
- package/package.json +103 -0
- package/react-native.config.js +8 -0
- package/src/OrientationLocker.nitro.ts +45 -0
- package/src/OrientationLockerProvider.tsx +26 -0
- package/src/index.ts +30 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Attique Rehman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,30 @@
|
|
|
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 = "NitroOrientationLocker"
|
|
7
|
+
s.version = package["version"]
|
|
8
|
+
s.summary = package["description"]
|
|
9
|
+
s.homepage = package["repository"]
|
|
10
|
+
s.license = package["license"]
|
|
11
|
+
s.authors = package["author"]
|
|
12
|
+
|
|
13
|
+
s.platforms = { :ios => "16.0", :visionos => "1.0" }
|
|
14
|
+
s.source = { :git => "#{package["repository"]}.git", :tag => "#{s.version}" }
|
|
15
|
+
|
|
16
|
+
s.source_files = [
|
|
17
|
+
"ios/**/*.{swift}",
|
|
18
|
+
"ios/**/*.{m,mm}",
|
|
19
|
+
"cpp/**/*.{hpp,cpp}"
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
s.swift_version = "5.9"
|
|
23
|
+
|
|
24
|
+
load 'nitrogen/generated/ios/NitroOrientationLocker+autolinking.rb'
|
|
25
|
+
add_nitrogen_files(s)
|
|
26
|
+
|
|
27
|
+
s.dependency 'React-jsi'
|
|
28
|
+
s.dependency 'React-callinvoker'
|
|
29
|
+
install_modules_dependencies(s)
|
|
30
|
+
end
|
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# @tenthdart/react-native-nitro-orientation-locker
|
|
2
|
+
|
|
3
|
+
High-performance orientation lock for React Native, built on
|
|
4
|
+
[Nitro Modules](https://nitro.margelo.com).
|
|
5
|
+
|
|
6
|
+
- **New Architecture only.** Old-arch is not supported.
|
|
7
|
+
- **iOS 16+ / visionOS 1.0+** — uses `requestGeometryUpdate`.
|
|
8
|
+
- **Android API 24+** — uses `Activity.setRequestedOrientation`.
|
|
9
|
+
- Auto-lock tablets and large-width screens to landscape with a single prop.
|
|
10
|
+
- Imperative `acquireLock` / `releaseLock` for everything else.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
npm i @tenthdart/react-native-nitro-orientation-locker react-native-nitro-modules
|
|
16
|
+
cd ios && pod install
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Make sure the **New Architecture** is enabled in your app
|
|
20
|
+
(`newArchEnabled=true` in `android/gradle.properties`,
|
|
21
|
+
`RCT_NEW_ARCH_ENABLED=1` for iOS).
|
|
22
|
+
|
|
23
|
+
### iOS host-app wiring
|
|
24
|
+
|
|
25
|
+
So that iOS actually honors the requested orientation, route the app's
|
|
26
|
+
supported-orientations delegate through `OrientationGate`:
|
|
27
|
+
|
|
28
|
+
```swift
|
|
29
|
+
// AppDelegate.swift
|
|
30
|
+
import NitroOrientationLocker
|
|
31
|
+
|
|
32
|
+
func application(
|
|
33
|
+
_ application: UIApplication,
|
|
34
|
+
supportedInterfaceOrientationsFor window: UIWindow?
|
|
35
|
+
) -> UIInterfaceOrientationMask {
|
|
36
|
+
return OrientationGate.shared.supportedMask
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Android host-app wiring
|
|
41
|
+
|
|
42
|
+
Add `android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"`
|
|
43
|
+
to your `MainActivity` in `AndroidManifest.xml` so React Native doesn't tear
|
|
44
|
+
down the JS context when orientation changes.
|
|
45
|
+
|
|
46
|
+
## Usage
|
|
47
|
+
|
|
48
|
+
### Auto-lock tablets to landscape
|
|
49
|
+
|
|
50
|
+
Wrap your app once. Phones are unaffected; tablets (iPad / visionOS or
|
|
51
|
+
Android `smallestScreenWidthDp >= 600`) are locked to landscape.
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import { OrientationLockerProvider } from '@tenthdart/react-native-nitro-orientation-locker';
|
|
55
|
+
|
|
56
|
+
export default function App() {
|
|
57
|
+
return (
|
|
58
|
+
<OrientationLockerProvider lockTabletsToLandscape>
|
|
59
|
+
<RootNavigator />
|
|
60
|
+
</OrientationLockerProvider>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Imperative API
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { OrientationLocker } from '@tenthdart/react-native-nitro-orientation-locker';
|
|
69
|
+
|
|
70
|
+
OrientationLocker.acquireLock('landscape'); // any landscape
|
|
71
|
+
OrientationLocker.acquireLock('landscape-left'); // pinned
|
|
72
|
+
OrientationLocker.acquireLock('portrait');
|
|
73
|
+
OrientationLocker.releaseLock();
|
|
74
|
+
|
|
75
|
+
OrientationLocker.isTablet; // boolean
|
|
76
|
+
OrientationLocker.currentOrientation; // 'portrait' | 'landscape-left' | ...
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Orientation values
|
|
80
|
+
|
|
81
|
+
| Value | iOS mask | Android |
|
|
82
|
+
| ----------------------- | --------------------------------- | ------------------------------------------------ |
|
|
83
|
+
| `portrait` | `.portrait` | `SCREEN_ORIENTATION_PORTRAIT` |
|
|
84
|
+
| `portrait-upside-down` | `.portraitUpsideDown` | `SCREEN_ORIENTATION_REVERSE_PORTRAIT` |
|
|
85
|
+
| `landscape-left` | `.landscapeLeft` | `SCREEN_ORIENTATION_LANDSCAPE` |
|
|
86
|
+
| `landscape-right` | `.landscapeRight` | `SCREEN_ORIENTATION_REVERSE_LANDSCAPE` |
|
|
87
|
+
| `landscape` | `.landscape` | `SCREEN_ORIENTATION_SENSOR_LANDSCAPE` |
|
|
88
|
+
| `all` | `.all` | `SCREEN_ORIENTATION_UNSPECIFIED` |
|
|
89
|
+
|
|
90
|
+
## How precedence works
|
|
91
|
+
|
|
92
|
+
`acquireLock` always wins. Releasing it falls back to the tablet-landscape
|
|
93
|
+
rule (if enabled and on a tablet); otherwise the app returns to its
|
|
94
|
+
default supported orientations.
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
MIT
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
project(NitroOrientationLocker)
|
|
2
|
+
cmake_minimum_required(VERSION 3.9.0)
|
|
3
|
+
|
|
4
|
+
set(PACKAGE_NAME NitroOrientationLocker)
|
|
5
|
+
set(CMAKE_CXX_STANDARD 20)
|
|
6
|
+
|
|
7
|
+
include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/NitroOrientationLocker+autolinking.cmake)
|
|
8
|
+
|
|
9
|
+
add_library(${PACKAGE_NAME} SHARED ${NitroOrientationLocker_SOURCES_AUTOLINKED})
|
|
10
|
+
|
|
11
|
+
target_include_directories(${PACKAGE_NAME} PRIVATE ${NitroOrientationLocker_INCLUDES_AUTOLINKED})
|
|
12
|
+
|
|
13
|
+
target_link_libraries(${PACKAGE_NAME} ${NitroOrientationLocker_LIBS_AUTOLINKED})
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
repositories {
|
|
3
|
+
google()
|
|
4
|
+
mavenCentral()
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
dependencies {
|
|
8
|
+
classpath "com.android.tools.build:gradle:8.6.1"
|
|
9
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.24"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
def reactNativeArchitectures() {
|
|
14
|
+
def value = rootProject.getProperties().get("reactNativeArchitectures")
|
|
15
|
+
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
def isNewArchitectureEnabled() {
|
|
19
|
+
return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
apply plugin: "com.android.library"
|
|
23
|
+
apply plugin: "org.jetbrains.kotlin.android"
|
|
24
|
+
apply from: "../nitrogen/generated/android/NitroOrientationLocker+autolinking.gradle"
|
|
25
|
+
|
|
26
|
+
if (!isNewArchitectureEnabled()) {
|
|
27
|
+
throw new GradleException(
|
|
28
|
+
"react-native-nitro-orientation-locker requires the New Architecture to be enabled. " +
|
|
29
|
+
"Set newArchEnabled=true in android/gradle.properties."
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
apply plugin: "com.facebook.react"
|
|
34
|
+
|
|
35
|
+
def getExtOrDefault(name) {
|
|
36
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["NitroOrientationLocker_" + name]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
def getExtOrIntegerDefault(name) {
|
|
40
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["NitroOrientationLocker_" + name]).toInteger()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
android {
|
|
44
|
+
namespace "com.margelo.nitro.orientationlocker"
|
|
45
|
+
|
|
46
|
+
ndkVersion getExtOrDefault("ndkVersion")
|
|
47
|
+
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
|
|
48
|
+
|
|
49
|
+
defaultConfig {
|
|
50
|
+
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
|
|
51
|
+
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
|
|
52
|
+
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
|
53
|
+
|
|
54
|
+
externalNativeBuild {
|
|
55
|
+
cmake {
|
|
56
|
+
cppFlags "-frtti -fexceptions -Wall -Wextra -fstack-protector-all"
|
|
57
|
+
arguments "-DANDROID_STL=c++_shared", "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
|
|
58
|
+
abiFilters(*reactNativeArchitectures())
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
externalNativeBuild {
|
|
64
|
+
cmake {
|
|
65
|
+
path "CMakeLists.txt"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
buildFeatures {
|
|
70
|
+
buildConfig true
|
|
71
|
+
prefab true
|
|
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
|
+
buildTypes {
|
|
96
|
+
release {
|
|
97
|
+
minifyEnabled false
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
lintOptions {
|
|
102
|
+
disable "GradleCompatible"
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
compileOptions {
|
|
106
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
107
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
kotlinOptions {
|
|
111
|
+
jvmTarget = "17"
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
sourceSets {
|
|
115
|
+
main {
|
|
116
|
+
java.srcDirs += [
|
|
117
|
+
"${project.buildDir}/generated/source/codegen/java"
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
repositories {
|
|
124
|
+
mavenCentral()
|
|
125
|
+
google()
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
dependencies {
|
|
129
|
+
//noinspection GradleDynamicVersion
|
|
130
|
+
implementation "com.facebook.react:react-native:+"
|
|
131
|
+
implementation project(":react-native-nitro-modules")
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
react {
|
|
135
|
+
jsRootDir = file("../src/")
|
|
136
|
+
libraryName = "NitroOrientationLocker"
|
|
137
|
+
codegenJavaPackageName = "com.margelo.nitro.orientationlocker"
|
|
138
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
package com.margelo.nitro.orientationlocker
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.content.pm.ActivityInfo
|
|
5
|
+
import android.content.res.Configuration
|
|
6
|
+
import android.view.Surface
|
|
7
|
+
import com.facebook.proguard.annotations.DoNotStrip
|
|
8
|
+
import com.margelo.nitro.NitroModules
|
|
9
|
+
|
|
10
|
+
@DoNotStrip
|
|
11
|
+
class HybridOrientationLocker : HybridOrientationLockerSpec() {
|
|
12
|
+
|
|
13
|
+
private var lockTabletsToLandscape = false
|
|
14
|
+
private var manualLock: String? = null
|
|
15
|
+
|
|
16
|
+
override val isTablet: Boolean
|
|
17
|
+
get() {
|
|
18
|
+
val context = NitroModules.applicationContext ?: return false
|
|
19
|
+
return context.resources.configuration.smallestScreenWidthDp >= 600
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
override val currentOrientation: String
|
|
23
|
+
get() {
|
|
24
|
+
val activity = NitroModules.applicationContext?.currentActivity ?: return "portrait"
|
|
25
|
+
val rotation = activity.windowManager.defaultDisplay.rotation
|
|
26
|
+
val orientation = activity.resources.configuration.orientation
|
|
27
|
+
return when (orientation) {
|
|
28
|
+
Configuration.ORIENTATION_LANDSCAPE -> when (rotation) {
|
|
29
|
+
Surface.ROTATION_270 -> "landscape-right"
|
|
30
|
+
else -> "landscape-left"
|
|
31
|
+
}
|
|
32
|
+
Configuration.ORIENTATION_PORTRAIT -> when (rotation) {
|
|
33
|
+
Surface.ROTATION_180 -> "portrait-upside-down"
|
|
34
|
+
else -> "portrait"
|
|
35
|
+
}
|
|
36
|
+
else -> "portrait"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
override fun acquireLock(orientation: String) {
|
|
41
|
+
manualLock = orientation
|
|
42
|
+
apply()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override fun releaseLock() {
|
|
46
|
+
manualLock = null
|
|
47
|
+
if (lockTabletsToLandscape && isTablet) {
|
|
48
|
+
apply()
|
|
49
|
+
} else {
|
|
50
|
+
restoreUnspecified()
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
override fun setLockTabletsToLandscape(enabled: Boolean) {
|
|
55
|
+
lockTabletsToLandscape = enabled
|
|
56
|
+
when {
|
|
57
|
+
enabled && isTablet && manualLock == null -> apply()
|
|
58
|
+
!enabled && manualLock == null -> restoreUnspecified()
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// region Private
|
|
63
|
+
|
|
64
|
+
private fun resolvedOrientation(): String {
|
|
65
|
+
manualLock?.let { return it }
|
|
66
|
+
if (lockTabletsToLandscape && isTablet) return "landscape"
|
|
67
|
+
return "all"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private fun apply() {
|
|
71
|
+
val target = resolvedOrientation()
|
|
72
|
+
setActivityOrientation(activityInfoFor(target))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private fun restoreUnspecified() {
|
|
76
|
+
setActivityOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private fun activityInfoFor(orientation: String): Int = when (orientation) {
|
|
80
|
+
"portrait" -> ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
|
81
|
+
"portrait-upside-down" -> ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
|
|
82
|
+
"landscape-left" -> ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
|
83
|
+
"landscape-right" -> ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
|
|
84
|
+
"landscape" -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
|
85
|
+
"all" -> ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
|
86
|
+
else -> ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private fun setActivityOrientation(requested: Int) {
|
|
90
|
+
val activity: Activity = NitroModules.applicationContext?.currentActivity ?: return
|
|
91
|
+
activity.runOnUiThread {
|
|
92
|
+
if (activity.requestedOrientation != requested) {
|
|
93
|
+
activity.requestedOrientation = requested
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// endregion
|
|
99
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import UIKit
|
|
3
|
+
import NitroModules
|
|
4
|
+
|
|
5
|
+
final class HybridOrientationLocker: HybridOrientationLockerSpec {
|
|
6
|
+
private var lockTabletsToLandscape = false
|
|
7
|
+
private var manualLock: String? = nil
|
|
8
|
+
|
|
9
|
+
var isTablet: Bool {
|
|
10
|
+
UIDevice.current.userInterfaceIdiom == .pad
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
var currentOrientation: String {
|
|
14
|
+
switch effectiveDeviceOrientation() {
|
|
15
|
+
case .portrait: return "portrait"
|
|
16
|
+
case .portraitUpsideDown: return "portrait-upside-down"
|
|
17
|
+
case .landscapeLeft: return "landscape-left"
|
|
18
|
+
case .landscapeRight: return "landscape-right"
|
|
19
|
+
default: return "portrait"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
func acquireLock(orientation: String) throws {
|
|
24
|
+
manualLock = orientation
|
|
25
|
+
apply()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
func releaseLock() throws {
|
|
29
|
+
manualLock = nil
|
|
30
|
+
if !(lockTabletsToLandscape && isTablet) {
|
|
31
|
+
restoreAllOrientations()
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
apply()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
func setLockTabletsToLandscape(enabled: Bool) throws {
|
|
38
|
+
lockTabletsToLandscape = enabled
|
|
39
|
+
if enabled && isTablet && manualLock == nil {
|
|
40
|
+
apply()
|
|
41
|
+
} else if !enabled && manualLock == nil {
|
|
42
|
+
restoreAllOrientations()
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// MARK: - Private
|
|
47
|
+
|
|
48
|
+
private func resolvedOrientation() -> String {
|
|
49
|
+
if let manual = manualLock { return manual }
|
|
50
|
+
if lockTabletsToLandscape && isTablet { return "landscape" }
|
|
51
|
+
return "all"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private func apply() {
|
|
55
|
+
let target = resolvedOrientation()
|
|
56
|
+
let mask = mask(for: target)
|
|
57
|
+
OrientationGate.shared.supportedMask = mask
|
|
58
|
+
requestGeometryUpdate(mask: mask)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private func restoreAllOrientations() {
|
|
62
|
+
OrientationGate.shared.supportedMask = .all
|
|
63
|
+
requestGeometryUpdate(mask: .all)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private func mask(for orientation: String) -> UIInterfaceOrientationMask {
|
|
67
|
+
switch orientation {
|
|
68
|
+
case "portrait": return .portrait
|
|
69
|
+
case "portrait-upside-down": return .portraitUpsideDown
|
|
70
|
+
case "landscape-left": return .landscapeLeft
|
|
71
|
+
case "landscape-right": return .landscapeRight
|
|
72
|
+
case "landscape": return .landscape
|
|
73
|
+
case "all": return .all
|
|
74
|
+
default: return .all
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private func requestGeometryUpdate(mask: UIInterfaceOrientationMask) {
|
|
79
|
+
DispatchQueue.main.async {
|
|
80
|
+
guard
|
|
81
|
+
let scene = UIApplication.shared.connectedScenes
|
|
82
|
+
.compactMap({ $0 as? UIWindowScene })
|
|
83
|
+
.first(where: { $0.activationState == .foregroundActive })
|
|
84
|
+
?? UIApplication.shared.connectedScenes
|
|
85
|
+
.compactMap({ $0 as? UIWindowScene })
|
|
86
|
+
.first
|
|
87
|
+
else { return }
|
|
88
|
+
|
|
89
|
+
let geometryPreferences = UIWindowScene.GeometryPreferences.iOS(
|
|
90
|
+
interfaceOrientations: mask
|
|
91
|
+
)
|
|
92
|
+
scene.requestGeometryUpdate(geometryPreferences) { _ in }
|
|
93
|
+
|
|
94
|
+
scene.windows
|
|
95
|
+
.compactMap { $0.rootViewController }
|
|
96
|
+
.forEach { $0.setNeedsUpdateOfSupportedInterfaceOrientations() }
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private func effectiveDeviceOrientation() -> UIDeviceOrientation {
|
|
101
|
+
let device = UIDevice.current.orientation
|
|
102
|
+
if device.isValidInterfaceOrientation { return device }
|
|
103
|
+
|
|
104
|
+
guard
|
|
105
|
+
let scene = UIApplication.shared.connectedScenes
|
|
106
|
+
.compactMap({ $0 as? UIWindowScene })
|
|
107
|
+
.first(where: { $0.activationState == .foregroundActive })
|
|
108
|
+
else { return .portrait }
|
|
109
|
+
|
|
110
|
+
switch scene.interfaceOrientation {
|
|
111
|
+
case .portrait: return .portrait
|
|
112
|
+
case .portraitUpsideDown: return .portraitUpsideDown
|
|
113
|
+
case .landscapeLeft: return .landscapeLeft
|
|
114
|
+
case .landscapeRight: return .landscapeRight
|
|
115
|
+
default: return .portrait
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
/// Holds the currently-requested orientation mask so the host app's
|
|
5
|
+
/// `application(_:supportedInterfaceOrientationsFor:)` delegate (or a
|
|
6
|
+
/// `UIViewController` subclass) can honor it.
|
|
7
|
+
///
|
|
8
|
+
/// To wire it up in your host app's `AppDelegate.swift`:
|
|
9
|
+
///
|
|
10
|
+
/// ```swift
|
|
11
|
+
/// func application(
|
|
12
|
+
/// _ application: UIApplication,
|
|
13
|
+
/// supportedInterfaceOrientationsFor window: UIWindow?
|
|
14
|
+
/// ) -> UIInterfaceOrientationMask {
|
|
15
|
+
/// return OrientationGate.shared.supportedMask
|
|
16
|
+
/// }
|
|
17
|
+
/// ```
|
|
18
|
+
@objc public final class OrientationGate: NSObject {
|
|
19
|
+
@objc public static let shared = OrientationGate()
|
|
20
|
+
@objc public var supportedMask: UIInterfaceOrientationMask = .all
|
|
21
|
+
private override init() {}
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../src","sources":["OrientationLocker.nitro.ts"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.OrientationLockerProvider = OrientationLockerProvider;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _index = require("./index");
|
|
9
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
10
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
11
|
+
function OrientationLockerProvider({
|
|
12
|
+
lockTabletsToLandscape = false,
|
|
13
|
+
children
|
|
14
|
+
}) {
|
|
15
|
+
(0, _react.useEffect)(() => {
|
|
16
|
+
_index.OrientationLocker.setLockTabletsToLandscape(lockTabletsToLandscape);
|
|
17
|
+
return () => {
|
|
18
|
+
_index.OrientationLocker.setLockTabletsToLandscape(false);
|
|
19
|
+
};
|
|
20
|
+
}, [lockTabletsToLandscape]);
|
|
21
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
|
|
22
|
+
children: children
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=OrientationLockerProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireWildcard","require","_index","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","OrientationLockerProvider","lockTabletsToLandscape","children","useEffect","OrientationLocker","setLockTabletsToLandscape","jsx","Fragment"],"sourceRoot":"../../src","sources":["OrientationLockerProvider.tsx"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,uBAAA,CAAAC,OAAA;AACA,IAAAC,MAAA,GAAAD,OAAA;AAA4C,IAAAE,WAAA,GAAAF,OAAA;AAAA,SAAAD,wBAAAI,CAAA,EAAAC,CAAA,6BAAAC,OAAA,MAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAN,uBAAA,YAAAA,CAAAI,CAAA,EAAAC,CAAA,SAAAA,CAAA,IAAAD,CAAA,IAAAA,CAAA,CAAAK,UAAA,SAAAL,CAAA,MAAAM,CAAA,EAAAC,CAAA,EAAAC,CAAA,KAAAC,SAAA,QAAAC,OAAA,EAAAV,CAAA,iBAAAA,CAAA,uBAAAA,CAAA,yBAAAA,CAAA,SAAAQ,CAAA,MAAAF,CAAA,GAAAL,CAAA,GAAAG,CAAA,GAAAD,CAAA,QAAAG,CAAA,CAAAK,GAAA,CAAAX,CAAA,UAAAM,CAAA,CAAAM,GAAA,CAAAZ,CAAA,GAAAM,CAAA,CAAAO,GAAA,CAAAb,CAAA,EAAAQ,CAAA,gBAAAP,CAAA,IAAAD,CAAA,gBAAAC,CAAA,OAAAa,cAAA,CAAAC,IAAA,CAAAf,CAAA,EAAAC,CAAA,OAAAM,CAAA,IAAAD,CAAA,GAAAU,MAAA,CAAAC,cAAA,KAAAD,MAAA,CAAAE,wBAAA,CAAAlB,CAAA,EAAAC,CAAA,OAAAM,CAAA,CAAAK,GAAA,IAAAL,CAAA,CAAAM,GAAA,IAAAP,CAAA,CAAAE,CAAA,EAAAP,CAAA,EAAAM,CAAA,IAAAC,CAAA,CAAAP,CAAA,IAAAD,CAAA,CAAAC,CAAA,WAAAO,CAAA,KAAAR,CAAA,EAAAC,CAAA;AAYrC,SAASkB,yBAAyBA,CAAC;EACxCC,sBAAsB,GAAG,KAAK;EAC9BC;AAC8B,CAAC,EAAsB;EACrD,IAAAC,gBAAS,EAAC,MAAM;IACdC,wBAAiB,CAACC,yBAAyB,CAACJ,sBAAsB,CAAC;IACnE,OAAO,MAAM;MACXG,wBAAiB,CAACC,yBAAyB,CAAC,KAAK,CAAC;IACpD,CAAC;EACH,CAAC,EAAE,CAACJ,sBAAsB,CAAC,CAAC;EAE5B,oBAAO,IAAArB,WAAA,CAAA0B,GAAA,EAAA1B,WAAA,CAAA2B,QAAA;IAAAL,QAAA,EAAGA;EAAQ,CAAG,CAAC;AACxB","ignoreList":[]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.OrientationLocker = void 0;
|
|
7
|
+
Object.defineProperty(exports, "OrientationLockerProvider", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () {
|
|
10
|
+
return _OrientationLockerProvider.OrientationLockerProvider;
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
var _reactNativeNitroModules = require("react-native-nitro-modules");
|
|
14
|
+
var _OrientationLockerProvider = require("./OrientationLockerProvider");
|
|
15
|
+
const OrientationLockerHybrid = _reactNativeNitroModules.NitroModules.createHybridObject('OrientationLocker');
|
|
16
|
+
const OrientationLocker = exports.OrientationLocker = {
|
|
17
|
+
get isTablet() {
|
|
18
|
+
return OrientationLockerHybrid.isTablet;
|
|
19
|
+
},
|
|
20
|
+
get currentOrientation() {
|
|
21
|
+
return OrientationLockerHybrid.currentOrientation;
|
|
22
|
+
},
|
|
23
|
+
acquireLock(orientation) {
|
|
24
|
+
OrientationLockerHybrid.acquireLock(orientation);
|
|
25
|
+
},
|
|
26
|
+
releaseLock() {
|
|
27
|
+
OrientationLockerHybrid.releaseLock();
|
|
28
|
+
},
|
|
29
|
+
setLockTabletsToLandscape(enabled) {
|
|
30
|
+
OrientationLockerHybrid.setLockTabletsToLandscape(enabled);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_reactNativeNitroModules","require","_OrientationLockerProvider","OrientationLockerHybrid","NitroModules","createHybridObject","OrientationLocker","exports","isTablet","currentOrientation","acquireLock","orientation","releaseLock","setLockTabletsToLandscape","enabled"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;;;;;;AAAA,IAAAA,wBAAA,GAAAC,OAAA;AA6BA,IAAAC,0BAAA,GAAAD,OAAA;AArBA,MAAME,uBAAuB,GAC3BC,qCAAY,CAACC,kBAAkB,CAAwB,mBAAmB,CAAC;AAEtE,MAAMC,iBAAiB,GAAAC,OAAA,CAAAD,iBAAA,GAAG;EAC/B,IAAIE,QAAQA,CAAA,EAAY;IACtB,OAAOL,uBAAuB,CAACK,QAAQ;EACzC,CAAC;EACD,IAAIC,kBAAkBA,CAAA,EAAgB;IACpC,OAAON,uBAAuB,CAACM,kBAAkB;EACnD,CAAC;EACDC,WAAWA,CAACC,WAAwB,EAAQ;IAC1CR,uBAAuB,CAACO,WAAW,CAACC,WAAW,CAAC;EAClD,CAAC;EACDC,WAAWA,CAAA,EAAS;IAClBT,uBAAuB,CAACS,WAAW,CAAC,CAAC;EACvC,CAAC;EACDC,yBAAyBA,CAACC,OAAgB,EAAQ;IAChDX,uBAAuB,CAACU,yBAAyB,CAACC,OAAO,CAAC;EAC5D;AACF,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../src","sources":["OrientationLocker.nitro.ts"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React, { useEffect } from 'react';
|
|
4
|
+
import { OrientationLocker } from './index';
|
|
5
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
+
export function OrientationLockerProvider({
|
|
7
|
+
lockTabletsToLandscape = false,
|
|
8
|
+
children
|
|
9
|
+
}) {
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
OrientationLocker.setLockTabletsToLandscape(lockTabletsToLandscape);
|
|
12
|
+
return () => {
|
|
13
|
+
OrientationLocker.setLockTabletsToLandscape(false);
|
|
14
|
+
};
|
|
15
|
+
}, [lockTabletsToLandscape]);
|
|
16
|
+
return /*#__PURE__*/_jsx(_Fragment, {
|
|
17
|
+
children: children
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=OrientationLockerProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["React","useEffect","OrientationLocker","Fragment","_Fragment","jsx","_jsx","OrientationLockerProvider","lockTabletsToLandscape","children","setLockTabletsToLandscape"],"sourceRoot":"../../src","sources":["OrientationLockerProvider.tsx"],"mappings":";;AAAA,OAAOA,KAAK,IAAIC,SAAS,QAAQ,OAAO;AACxC,SAASC,iBAAiB,QAAQ,SAAS;AAAC,SAAAC,QAAA,IAAAC,SAAA,EAAAC,GAAA,IAAAC,IAAA;AAY5C,OAAO,SAASC,yBAAyBA,CAAC;EACxCC,sBAAsB,GAAG,KAAK;EAC9BC;AAC8B,CAAC,EAAsB;EACrDR,SAAS,CAAC,MAAM;IACdC,iBAAiB,CAACQ,yBAAyB,CAACF,sBAAsB,CAAC;IACnE,OAAO,MAAM;MACXN,iBAAiB,CAACQ,yBAAyB,CAAC,KAAK,CAAC;IACpD,CAAC;EACH,CAAC,EAAE,CAACF,sBAAsB,CAAC,CAAC;EAE5B,oBAAOF,IAAA,CAAAF,SAAA;IAAAK,QAAA,EAAGA;EAAQ,CAAG,CAAC;AACxB","ignoreList":[]}
|