react-native-orientation-director 1.0.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.
Files changed (103) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +87 -0
  3. package/android/build.gradle +120 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/src/main/AndroidManifest.xml +3 -0
  6. package/android/src/main/AndroidManifestNew.xml +2 -0
  7. package/android/src/main/java/com/orientationdirector/OrientationDirectorModule.kt +50 -0
  8. package/android/src/main/java/com/orientationdirector/OrientationDirectorPackage.kt +35 -0
  9. package/android/src/main/java/com/orientationdirector/implementation/Orientation.kt +12 -0
  10. package/android/src/main/java/com/orientationdirector/implementation/OrientationDirectorImpl.kt +117 -0
  11. package/android/src/main/java/com/orientationdirector/implementation/OrientationDirectorUtilsImpl.kt +65 -0
  12. package/android/src/main/java/com/orientationdirector/implementation/OrientationEventManager.kt +42 -0
  13. package/android/src/main/java/com/orientationdirector/implementation/OrientationLifecycleListener.kt +33 -0
  14. package/android/src/main/java/com/orientationdirector/implementation/OrientationSensorListener.kt +26 -0
  15. package/android/src/newarch/OrientationDirectorSpec.kt +7 -0
  16. package/android/src/oldarch/OrientationDirectorSpec.kt +16 -0
  17. package/ios/OrientationDirector.h +22 -0
  18. package/ios/OrientationDirector.mm +121 -0
  19. package/ios/implementation/Orientation.swift +12 -0
  20. package/ios/implementation/OrientationDirectorImpl.swift +126 -0
  21. package/ios/implementation/OrientationDirectorUtils.swift +111 -0
  22. package/ios/implementation/OrientationEventManager.swift +56 -0
  23. package/ios/implementation/OrientationSensorListener.swift +37 -0
  24. package/ios/react-native-orientation-director-Bridging-Header.h +6 -0
  25. package/lib/commonjs/NativeOrientationDirector.js +9 -0
  26. package/lib/commonjs/NativeOrientationDirector.js.map +1 -0
  27. package/lib/commonjs/RNOrientationDirector.js +49 -0
  28. package/lib/commonjs/RNOrientationDirector.js.map +1 -0
  29. package/lib/commonjs/hooks/useDeviceOrientation.hook.js +39 -0
  30. package/lib/commonjs/hooks/useDeviceOrientation.hook.js.map +1 -0
  31. package/lib/commonjs/hooks/useInterfaceOrientation.hook.js +39 -0
  32. package/lib/commonjs/hooks/useInterfaceOrientation.hook.js.map +1 -0
  33. package/lib/commonjs/index.js +31 -0
  34. package/lib/commonjs/index.js.map +1 -0
  35. package/lib/commonjs/module.js +23 -0
  36. package/lib/commonjs/module.js.map +1 -0
  37. package/lib/commonjs/types/Event.enum.js +13 -0
  38. package/lib/commonjs/types/Event.enum.js.map +1 -0
  39. package/lib/commonjs/types/InterfaceOrientationToLocalizedStringProvider.type.js +6 -0
  40. package/lib/commonjs/types/InterfaceOrientationToLocalizedStringProvider.type.js.map +1 -0
  41. package/lib/commonjs/types/LockableOrientation.type.js +6 -0
  42. package/lib/commonjs/types/LockableOrientation.type.js.map +1 -0
  43. package/lib/commonjs/types/Orientation.enum.js +17 -0
  44. package/lib/commonjs/types/Orientation.enum.js.map +1 -0
  45. package/lib/commonjs/types/OrientationEvent.interface.js +6 -0
  46. package/lib/commonjs/types/OrientationEvent.interface.js.map +1 -0
  47. package/lib/module/NativeOrientationDirector.js +3 -0
  48. package/lib/module/NativeOrientationDirector.js.map +1 -0
  49. package/lib/module/RNOrientationDirector.js +40 -0
  50. package/lib/module/RNOrientationDirector.js.map +1 -0
  51. package/lib/module/hooks/useDeviceOrientation.hook.js +31 -0
  52. package/lib/module/hooks/useDeviceOrientation.hook.js.map +1 -0
  53. package/lib/module/hooks/useInterfaceOrientation.hook.js +31 -0
  54. package/lib/module/hooks/useInterfaceOrientation.hook.js.map +1 -0
  55. package/lib/module/index.js +8 -0
  56. package/lib/module/index.js.map +1 -0
  57. package/lib/module/module.js +17 -0
  58. package/lib/module/module.js.map +1 -0
  59. package/lib/module/types/Event.enum.js +7 -0
  60. package/lib/module/types/Event.enum.js.map +1 -0
  61. package/lib/module/types/InterfaceOrientationToLocalizedStringProvider.type.js +2 -0
  62. package/lib/module/types/InterfaceOrientationToLocalizedStringProvider.type.js.map +1 -0
  63. package/lib/module/types/LockableOrientation.type.js +2 -0
  64. package/lib/module/types/LockableOrientation.type.js.map +1 -0
  65. package/lib/module/types/Orientation.enum.js +11 -0
  66. package/lib/module/types/Orientation.enum.js.map +1 -0
  67. package/lib/module/types/OrientationEvent.interface.js +2 -0
  68. package/lib/module/types/OrientationEvent.interface.js.map +1 -0
  69. package/lib/typescript/src/NativeOrientationDirector.d.ts +12 -0
  70. package/lib/typescript/src/NativeOrientationDirector.d.ts.map +1 -0
  71. package/lib/typescript/src/RNOrientationDirector.d.ts +17 -0
  72. package/lib/typescript/src/RNOrientationDirector.d.ts.map +1 -0
  73. package/lib/typescript/src/hooks/useDeviceOrientation.hook.d.ts +8 -0
  74. package/lib/typescript/src/hooks/useDeviceOrientation.hook.d.ts.map +1 -0
  75. package/lib/typescript/src/hooks/useInterfaceOrientation.hook.d.ts +8 -0
  76. package/lib/typescript/src/hooks/useInterfaceOrientation.hook.d.ts.map +1 -0
  77. package/lib/typescript/src/index.d.ts +8 -0
  78. package/lib/typescript/src/index.d.ts.map +1 -0
  79. package/lib/typescript/src/module.d.ts +6 -0
  80. package/lib/typescript/src/module.d.ts.map +1 -0
  81. package/lib/typescript/src/types/Event.enum.d.ts +6 -0
  82. package/lib/typescript/src/types/Event.enum.d.ts.map +1 -0
  83. package/lib/typescript/src/types/InterfaceOrientationToLocalizedStringProvider.type.d.ts +3 -0
  84. package/lib/typescript/src/types/InterfaceOrientationToLocalizedStringProvider.type.d.ts.map +1 -0
  85. package/lib/typescript/src/types/LockableOrientation.type.d.ts +3 -0
  86. package/lib/typescript/src/types/LockableOrientation.type.d.ts.map +1 -0
  87. package/lib/typescript/src/types/Orientation.enum.d.ts +10 -0
  88. package/lib/typescript/src/types/Orientation.enum.d.ts.map +1 -0
  89. package/lib/typescript/src/types/OrientationEvent.interface.d.ts +5 -0
  90. package/lib/typescript/src/types/OrientationEvent.interface.d.ts.map +1 -0
  91. package/package.json +178 -0
  92. package/react-native-orientation-director.podspec +41 -0
  93. package/src/NativeOrientationDirector.ts +14 -0
  94. package/src/RNOrientationDirector.ts +64 -0
  95. package/src/hooks/useDeviceOrientation.hook.ts +40 -0
  96. package/src/hooks/useInterfaceOrientation.hook.ts +40 -0
  97. package/src/index.tsx +10 -0
  98. package/src/module.ts +30 -0
  99. package/src/types/Event.enum.ts +6 -0
  100. package/src/types/InterfaceOrientationToLocalizedStringProvider.type.ts +6 -0
  101. package/src/types/LockableOrientation.type.ts +7 -0
  102. package/src/types/Orientation.enum.ts +11 -0
  103. package/src/types/OrientationEvent.interface.ts +5 -0
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 gladius
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # react-native-orientation-director
2
+
3
+ A simple library that allows you to handle orientation changes in your React Native app.
4
+ Written in Kotlin, Swift and Typescript. It supports both the Old and New React Native architecture.
5
+
6
+ ## Features
7
+
8
+ - [x] Get the current orientation of the device
9
+ - [x] Get the current orientation of the interface
10
+ - [x] Listen to device orientation changes
11
+ - [x] Listen to interface orientation changes
12
+ - [x] Lock the interface orientation to a specific orientation
13
+ - [x] Unlock the interface orientation
14
+
15
+ ## Installation
16
+
17
+ You can install the package via npm or yarn:
18
+
19
+ ```sh
20
+ npm install react-native-orientation-director
21
+ ```
22
+ ```sh
23
+ yarn add react-native-orientation-director
24
+ ```
25
+
26
+ Don't forget to run pod-install
27
+
28
+ ## Setup
29
+
30
+ To properly handle interface orientation changes in iOS, you need to update your AppDelegate.mm file.
31
+ In your AppDelegate.mm file, import "OrientationDirector.h" and implement supportedInterfaceOrientationsForWindow method as follows:
32
+
33
+ ```objc
34
+ #import <OrientationDirector.h>
35
+
36
+ - (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
37
+ {
38
+ return [OrientationDirector getSupportedInterfaceOrientationsForWindow];
39
+ }
40
+ ```
41
+
42
+ If you need help, you can check the example project.
43
+
44
+ There is no need to do anything in Android, it works out of the box.
45
+
46
+ ## Usage
47
+
48
+ This library exports a class called: [RNOrientationDirector](https://github.com/gladiuscode/react-native-orientation-director/blob/main/src/RNOrientationDirector.ts) that exposes the following methods:
49
+
50
+ | Method | Description |
51
+ |-----------------------------------------|---------------------------------------------------------------------------------|
52
+ | getInterfaceOrientation | Returns the last interface orientation |
53
+ | getDeviceOrientation | Returns the last device orientation |
54
+ | lockTo | Locks the interface to a specific orientation |
55
+ | unlock | Unlock the interface |
56
+ | listenForDeviceOrientationChanges | Triggers a provided callback each time the device orientation changes |
57
+ | listenForInterfaceOrientationChanges | Triggers a provided callback each time the interface orientation changes |
58
+ | convertOrientationToHumanReadableString | Returns a human readable string based on the given orientation |
59
+ | setLocalizedStringProvider | Sets the mapping needed to convert orientation values to human readable strings |
60
+
61
+ In addition, the library exposes the following hooks:
62
+
63
+ | Hook | Description |
64
+ |-------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------|
65
+ | [useInterfaceOrientation](https://github.com/gladiuscode/react-native-orientation-director/blob/main/src/hooks/useInterfaceOrientation.hook.ts) | Returns the current interface orientation and listens to changes |
66
+ | [useDeviceOrientation](https://github.com/gladiuscode/react-native-orientation-director/blob/main/src/hooks/useDeviceOrientation.hook.ts) | Returns the current device orientation and listens to changes |
67
+
68
+ Head over to the [example project](example) to see how to use the library.
69
+
70
+ ## Roadmap
71
+
72
+ - [ ] Add support for Expo
73
+ - [ ] Add JS side tests
74
+ - [ ] Add Android side tests
75
+ - [ ] Add iOS side tests
76
+
77
+ ## Contributing
78
+
79
+ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
80
+
81
+ ## License
82
+
83
+ MIT
84
+
85
+ ---
86
+
87
+ Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
@@ -0,0 +1,120 @@
1
+ buildscript {
2
+ // Buildscript is evaluated before everything else so we can't use getExtOrDefault
3
+ def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["OrientationDirector_kotlinVersion"]
4
+
5
+ repositories {
6
+ google()
7
+ mavenCentral()
8
+ }
9
+
10
+ dependencies {
11
+ classpath "com.android.tools.build:gradle:7.2.1"
12
+ // noinspection DifferentKotlinGradleVersion
13
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14
+ }
15
+ }
16
+
17
+ def isNewArchitectureEnabled() {
18
+ return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
19
+ }
20
+
21
+ apply plugin: "com.android.library"
22
+ apply plugin: "kotlin-android"
23
+
24
+ if (isNewArchitectureEnabled()) {
25
+ apply plugin: "com.facebook.react"
26
+ }
27
+
28
+ def getExtOrDefault(name) {
29
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["OrientationDirector_" + name]
30
+ }
31
+
32
+ def getExtOrIntegerDefault(name) {
33
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["OrientationDirector_" + name]).toInteger()
34
+ }
35
+
36
+ def supportsNamespace() {
37
+ def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')
38
+ def major = parsed[0].toInteger()
39
+ def minor = parsed[1].toInteger()
40
+
41
+ // Namespace support was added in 7.3.0
42
+ return (major == 7 && minor >= 3) || major >= 8
43
+ }
44
+
45
+ android {
46
+ if (supportsNamespace()) {
47
+ namespace "com.orientationdirector"
48
+
49
+ sourceSets {
50
+ main {
51
+ manifest.srcFile "src/main/AndroidManifestNew.xml"
52
+ }
53
+ }
54
+ }
55
+
56
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
57
+
58
+ defaultConfig {
59
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
60
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
61
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
62
+
63
+ }
64
+
65
+ buildFeatures {
66
+ buildConfig true
67
+ }
68
+
69
+ buildTypes {
70
+ release {
71
+ minifyEnabled false
72
+ }
73
+ }
74
+
75
+ lintOptions {
76
+ disable "GradleCompatible"
77
+ }
78
+
79
+ compileOptions {
80
+ sourceCompatibility JavaVersion.VERSION_1_8
81
+ targetCompatibility JavaVersion.VERSION_1_8
82
+ }
83
+
84
+ sourceSets {
85
+ main {
86
+ if (isNewArchitectureEnabled()) {
87
+ java.srcDirs += [
88
+ "src/newarch",
89
+ // This is needed to build Kotlin project with NewArch enabled
90
+ "${project.buildDir}/generated/source/codegen/java"
91
+ ]
92
+ } else {
93
+ java.srcDirs += ["src/oldarch"]
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ repositories {
100
+ mavenCentral()
101
+ google()
102
+ }
103
+
104
+ def kotlin_version = getExtOrDefault("kotlinVersion")
105
+
106
+ dependencies {
107
+ // For < 0.71, this will be from the local maven repo
108
+ // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
109
+ //noinspection GradleDynamicVersion
110
+ implementation "com.facebook.react:react-native:+"
111
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
112
+ }
113
+
114
+ if (isNewArchitectureEnabled()) {
115
+ react {
116
+ jsRootDir = file("../src/")
117
+ libraryName = "OrientationDirector"
118
+ codegenJavaPackageName = "com.orientationdirector"
119
+ }
120
+ }
@@ -0,0 +1,5 @@
1
+ OrientationDirector_kotlinVersion=1.7.0
2
+ OrientationDirector_minSdkVersion=21
3
+ OrientationDirector_targetSdkVersion=31
4
+ OrientationDirector_compileSdkVersion=31
5
+ OrientationDirector_ndkversion=21.4.7075529
@@ -0,0 +1,3 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.orientationdirector">
3
+ </manifest>
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,50 @@
1
+ package com.orientationdirector
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+ import com.facebook.react.bridge.ReactMethod
5
+ import com.facebook.react.bridge.Promise
6
+ import com.orientationdirector.implementation.OrientationDirectorImpl
7
+
8
+ class OrientationDirectorModule internal constructor(context: ReactApplicationContext) :
9
+ OrientationDirectorSpec(context) {
10
+
11
+ private var orientationDirectorImpl: OrientationDirectorImpl
12
+
13
+ override fun getName(): String {
14
+ return NAME
15
+ }
16
+
17
+ init {
18
+ orientationDirectorImpl = OrientationDirectorImpl(context)
19
+ }
20
+
21
+ @ReactMethod()
22
+ override fun getInterfaceOrientation(promise: Promise) {
23
+ promise.resolve(orientationDirectorImpl.getInterfaceOrientation().ordinal)
24
+ }
25
+
26
+ @ReactMethod()
27
+ override fun getDeviceOrientation(promise: Promise) {
28
+ promise.resolve(orientationDirectorImpl.getDeviceOrientation().ordinal)
29
+ }
30
+
31
+ @ReactMethod()
32
+ override fun lockTo(orientation: Double) {
33
+ orientationDirectorImpl.lockTo(orientation.toInt())
34
+ }
35
+
36
+ @ReactMethod()
37
+ override fun unlock() {
38
+ orientationDirectorImpl.unlock()
39
+ }
40
+
41
+ @ReactMethod()
42
+ override fun addListener(eventName: String) {}
43
+
44
+ @ReactMethod()
45
+ override fun removeListeners(count: Double) {}
46
+
47
+ companion object {
48
+ const val NAME = "OrientationDirector"
49
+ }
50
+ }
@@ -0,0 +1,35 @@
1
+ package com.orientationdirector
2
+
3
+ import com.facebook.react.TurboReactPackage
4
+ import com.facebook.react.bridge.ReactApplicationContext
5
+ import com.facebook.react.bridge.NativeModule
6
+ import com.facebook.react.module.model.ReactModuleInfoProvider
7
+ import com.facebook.react.module.model.ReactModuleInfo
8
+ import java.util.HashMap
9
+
10
+ class OrientationDirectorPackage : TurboReactPackage() {
11
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
12
+ return if (name == OrientationDirectorModule.NAME) {
13
+ OrientationDirectorModule(reactContext)
14
+ } else {
15
+ null
16
+ }
17
+ }
18
+
19
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
20
+ return ReactModuleInfoProvider {
21
+ val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
22
+ val isTurboModule: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
23
+ moduleInfos[OrientationDirectorModule.NAME] = ReactModuleInfo(
24
+ OrientationDirectorModule.NAME,
25
+ OrientationDirectorModule.NAME,
26
+ false, // canOverrideExistingModule
27
+ false, // needsEagerInit
28
+ true, // hasConstants
29
+ false, // isCxxModule
30
+ isTurboModule // isTurboModule
31
+ )
32
+ moduleInfos
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,12 @@
1
+ package com.orientationdirector.implementation
2
+
3
+ /*
4
+ Don't change values positions
5
+ */
6
+ enum class Orientation {
7
+ UNKNOWN,
8
+ PORTRAIT,
9
+ LANDSCAPE_RIGHT,
10
+ PORTRAIT_UPSIDE_DOWN,
11
+ LANDSCAPE_LEFT,
12
+ }
@@ -0,0 +1,117 @@
1
+ package com.orientationdirector.implementation
2
+
3
+ import android.content.pm.ActivityInfo
4
+ import com.facebook.react.bridge.ReactApplicationContext
5
+
6
+ class OrientationDirectorImpl internal constructor(private val context: ReactApplicationContext) {
7
+ private var mUtils = OrientationDirectorUtilsImpl()
8
+ private var mEventEmitter = OrientationEventManager(context)
9
+ private var mSensorListener = OrientationSensorListener(context)
10
+ private var mLifecycleListener = OrientationLifecycleListener()
11
+ private var isLocked: Boolean = false
12
+ private var lastInterfaceOrientation = Orientation.UNKNOWN
13
+ private var lastDeviceOrientation = Orientation.UNKNOWN
14
+ private var initialized = false
15
+
16
+ init {
17
+ mSensorListener.setOnOrientationChangedCallback { orientation ->
18
+ onOrientationChanged(orientation)
19
+ }
20
+
21
+ if (mSensorListener.canDetectOrientation()) {
22
+ mSensorListener.enable()
23
+ } else {
24
+ mSensorListener.disable()
25
+ }
26
+
27
+ context.addLifecycleEventListener(mLifecycleListener)
28
+ mLifecycleListener.setOnHostResumeCallback {
29
+ if (mSensorListener.canDetectOrientation()) {
30
+ mSensorListener.enable()
31
+ }
32
+ }
33
+ mLifecycleListener.setOnHostPauseCallback {
34
+ if (initialized) {
35
+ mSensorListener.disable()
36
+ }
37
+ }
38
+ mLifecycleListener.setOnHostDestroyCallback {
39
+ mSensorListener.disable()
40
+ }
41
+
42
+ lastInterfaceOrientation = initInterfaceOrientation()
43
+ lastDeviceOrientation = initDeviceOrientation()
44
+
45
+ initialized = true
46
+ }
47
+
48
+ fun getInterfaceOrientation(): Orientation {
49
+ return lastInterfaceOrientation
50
+ }
51
+
52
+ fun getDeviceOrientation(): Orientation {
53
+ return lastDeviceOrientation
54
+ }
55
+
56
+ fun lockTo(jsOrientation: Int) {
57
+ val interfaceOrientation = mUtils.getOrientationEnumFrom(jsOrientation)
58
+ val screenOrientation =
59
+ mUtils.getActivityOrientationFrom(interfaceOrientation)
60
+ context.currentActivity?.requestedOrientation = screenOrientation
61
+ mEventEmitter.sendInterfaceOrientationDidChange(interfaceOrientation.ordinal)
62
+ lastInterfaceOrientation = interfaceOrientation
63
+ isLocked = true
64
+ }
65
+
66
+ fun unlock() {
67
+ context.currentActivity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
68
+ isLocked = false
69
+ adaptInterfaceTo(getDeviceOrientation())
70
+ }
71
+
72
+ private fun initInterfaceOrientation(): Orientation {
73
+ val activityOrientation = context.currentActivity!!.requestedOrientation
74
+ if (
75
+ mUtils.isActivityInPortraitOrientation(activityOrientation) ||
76
+ mUtils.isActivityInLandscapeOrientation(activityOrientation)
77
+ ) {
78
+ return mUtils.getInterfaceOrientationFrom(activityOrientation)
79
+ }
80
+
81
+ val lastRotationDetected = mSensorListener.getLastRotationDetected()
82
+ ?: return lastInterfaceOrientation
83
+
84
+ return mUtils.getDeviceOrientationFrom(lastRotationDetected)
85
+ }
86
+
87
+ private fun initDeviceOrientation(): Orientation {
88
+ val lastRotationDetected = mSensorListener.getLastRotationDetected()
89
+ ?: return Orientation.UNKNOWN
90
+
91
+ return mUtils.getDeviceOrientationFrom(lastRotationDetected)
92
+ }
93
+
94
+ private fun onOrientationChanged(rawDeviceOrientation: Int) {
95
+ val deviceOrientation = mUtils.getDeviceOrientationFrom(rawDeviceOrientation)
96
+ mEventEmitter.sendDeviceOrientationDidChange(deviceOrientation.ordinal)
97
+ lastDeviceOrientation = deviceOrientation
98
+ adaptInterfaceTo(deviceOrientation)
99
+ }
100
+
101
+ private fun adaptInterfaceTo(deviceOrientation: Orientation) {
102
+ if (isLocked) {
103
+ return
104
+ }
105
+
106
+ if (lastInterfaceOrientation == deviceOrientation) {
107
+ return
108
+ }
109
+
110
+ lastInterfaceOrientation = deviceOrientation
111
+ mEventEmitter.sendInterfaceOrientationDidChange(lastInterfaceOrientation.ordinal)
112
+ }
113
+
114
+ companion object {
115
+ const val NAME = "OrientationDirectorImpl"
116
+ }
117
+ }
@@ -0,0 +1,65 @@
1
+ package com.orientationdirector.implementation
2
+
3
+ import android.content.pm.ActivityInfo
4
+
5
+ class OrientationDirectorUtilsImpl() {
6
+
7
+ fun getDeviceOrientationFrom(rotation: Int): Orientation {
8
+ var orientation = Orientation.UNKNOWN
9
+
10
+ if (rotation == -1) {
11
+ orientation = Orientation.UNKNOWN
12
+ } else if (rotation > 355 || rotation < 5) {
13
+ orientation = Orientation.PORTRAIT
14
+ } else if (rotation in 86..94) {
15
+ orientation = Orientation.LANDSCAPE_RIGHT
16
+ } else if (rotation in 176..184) {
17
+ orientation = Orientation.PORTRAIT_UPSIDE_DOWN
18
+ } else if (rotation in 266..274) {
19
+ orientation = Orientation.LANDSCAPE_LEFT
20
+ }
21
+
22
+ return orientation
23
+ }
24
+
25
+ fun getInterfaceOrientationFrom(activityInfo: Int): Orientation {
26
+ return when (activityInfo) {
27
+ ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE -> Orientation.LANDSCAPE_RIGHT
28
+ ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT -> Orientation.PORTRAIT_UPSIDE_DOWN
29
+ ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE -> Orientation.LANDSCAPE_LEFT
30
+ else -> Orientation.PORTRAIT
31
+ };
32
+ }
33
+
34
+ fun isActivityInLandscapeOrientation(orientation: Int): Boolean {
35
+ return listOf(
36
+ ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE,
37
+ ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE,
38
+ ).contains(orientation);
39
+ }
40
+
41
+ fun isActivityInPortraitOrientation(orientation: Int): Boolean {
42
+ return listOf(
43
+ ActivityInfo.SCREEN_ORIENTATION_PORTRAIT,
44
+ ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT,
45
+ ).contains(orientation);
46
+ }
47
+
48
+ fun getActivityOrientationFrom(interfaceOrientation: Orientation): Int {
49
+ return when (interfaceOrientation) {
50
+ Orientation.LANDSCAPE_RIGHT -> ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
51
+ Orientation.PORTRAIT_UPSIDE_DOWN -> ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
52
+ Orientation.LANDSCAPE_LEFT -> ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
53
+ else -> ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
54
+ }
55
+ }
56
+
57
+ fun getOrientationEnumFrom(jsOrientation: Int): Orientation {
58
+ return when (jsOrientation) {
59
+ 2 -> Orientation.LANDSCAPE_RIGHT
60
+ 3 -> Orientation.PORTRAIT_UPSIDE_DOWN
61
+ 4 -> Orientation.LANDSCAPE_LEFT
62
+ else -> Orientation.PORTRAIT
63
+ }
64
+ }
65
+ }
@@ -0,0 +1,42 @@
1
+ package com.orientationdirector.implementation
2
+
3
+ import android.util.Log
4
+ import com.facebook.react.bridge.Arguments
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.bridge.WritableMap
7
+ import com.facebook.react.modules.core.DeviceEventManagerModule
8
+
9
+ enum class Event {
10
+ DeviceOrientationDidChange,
11
+ InterfaceOrientationDidChange,
12
+ }
13
+
14
+ class OrientationEventManager(private val context: ReactApplicationContext) {
15
+
16
+ fun sendDeviceOrientationDidChange(orientationValue: Int) {
17
+ val params = Arguments.createMap().apply {
18
+ putInt("orientation", orientationValue)
19
+ }
20
+ sendEvent(Event.DeviceOrientationDidChange, params)
21
+ }
22
+
23
+ fun sendInterfaceOrientationDidChange(orientationValue: Int) {
24
+ val params = Arguments.createMap().apply {
25
+ putInt("orientation", orientationValue)
26
+ }
27
+ sendEvent(Event.InterfaceOrientationDidChange, params)
28
+ }
29
+
30
+ private fun sendEvent(eventName: Event, params: WritableMap?) {
31
+ Log.d(NAME, "sendEvent - $eventName")
32
+ Log.d(NAME, "sendEvent - $params")
33
+ context
34
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
35
+ .emit(eventName.name, params)
36
+ }
37
+
38
+ companion object {
39
+ val NAME = "OrientationEventManager"
40
+ }
41
+
42
+ }
@@ -0,0 +1,33 @@
1
+ package com.orientationdirector.implementation
2
+
3
+ import com.facebook.react.bridge.LifecycleEventListener
4
+
5
+ class OrientationLifecycleListener() : LifecycleEventListener {
6
+
7
+ private var onHostResumeCallback: (() -> Unit)? = null
8
+ private var onHostPauseCallback: (() -> Unit)? = null
9
+ private var onHostDestroyCallback: (() -> Unit)? = null
10
+
11
+ fun setOnHostResumeCallback(callback: () -> Unit) {
12
+ this.onHostResumeCallback = callback
13
+ }
14
+ fun setOnHostPauseCallback(callback: () -> Unit) {
15
+ this.onHostResumeCallback = callback
16
+ }
17
+ fun setOnHostDestroyCallback(callback: () -> Unit) {
18
+ this.onHostDestroyCallback = callback
19
+ }
20
+
21
+ override fun onHostResume() {
22
+ this.onHostResumeCallback?.invoke()
23
+ }
24
+
25
+ override fun onHostPause() {
26
+ this.onHostPauseCallback?.invoke()
27
+ }
28
+
29
+ override fun onHostDestroy() {
30
+ this.onHostDestroyCallback?.invoke()
31
+ }
32
+
33
+ }
@@ -0,0 +1,26 @@
1
+ package com.orientationdirector.implementation
2
+
3
+ import android.hardware.SensorManager
4
+ import android.view.OrientationEventListener
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+
7
+ class OrientationSensorListener(
8
+ context: ReactApplicationContext,
9
+ ) : OrientationEventListener(context, SensorManager.SENSOR_DELAY_UI) {
10
+
11
+ private var lastRotationDetected: Int? = null
12
+ private var onOrientationChangedCallback: ((orientation: Int) -> Unit)? = null
13
+
14
+ fun getLastRotationDetected(): Int? {
15
+ return lastRotationDetected
16
+ }
17
+
18
+ fun setOnOrientationChangedCallback(callback: (orientation: Int) -> Unit) {
19
+ onOrientationChangedCallback = callback
20
+ }
21
+
22
+ override fun onOrientationChanged(orientation: Int) {
23
+ lastRotationDetected = orientation
24
+ onOrientationChangedCallback?.invoke(orientation)
25
+ }
26
+ }
@@ -0,0 +1,7 @@
1
+ package com.orientationdirector
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+
5
+ abstract class OrientationDirectorSpec internal constructor(context: ReactApplicationContext) :
6
+ NativeOrientationDirectorSpec(context) {
7
+ }
@@ -0,0 +1,16 @@
1
+ package com.orientationdirector
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
5
+ import com.facebook.react.bridge.Promise
6
+
7
+ abstract class OrientationDirectorSpec internal constructor(context: ReactApplicationContext) :
8
+ ReactContextBaseJavaModule(context) {
9
+
10
+ abstract fun getInterfaceOrientation(promise: Promise)
11
+ abstract fun getDeviceOrientation(promise: Promise)
12
+ abstract fun lockTo(orientation: Double)
13
+ abstract fun unlock()
14
+ abstract fun addListener(eventName: String)
15
+ abstract fun removeListeners(count: Double)
16
+ }
@@ -0,0 +1,22 @@
1
+ #import <React/RCTEventEmitter.h>
2
+
3
+ #ifdef RCT_NEW_ARCH_ENABLED
4
+ #import <RNOrientationDirectorSpec/RNOrientationDirectorSpec.h>
5
+
6
+ NS_ASSUME_NONNULL_BEGIN
7
+
8
+ @interface OrientationDirector : RCTEventEmitter <NativeOrientationDirectorSpec>
9
+
10
+ NS_ASSUME_NONNULL_END
11
+
12
+ #else
13
+ #import <React/RCTBridgeModule.h>
14
+
15
+ @interface OrientationDirector : RCTEventEmitter <RCTBridgeModule>
16
+ #endif
17
+
18
+ @property (nonatomic, assign) BOOL isJsListening;
19
+
20
+ +(UIInterfaceOrientationMask)getSupportedInterfaceOrientationsForWindow;
21
+
22
+ @end