-
-
Notifications
You must be signed in to change notification settings - Fork 49
/
Copy pathScreenOrientation.swift
173 lines (158 loc) · 7.64 KB
/
ScreenOrientation.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
import Foundation
import UIKit
import Capacitor
@objc public class ScreenOrientation: NSObject {
static var supportedInterfaceOrientations = UIInterfaceOrientationMask.all
private let plugin: ScreenOrientationPlugin
private var currentOrientationType: String?
private var lastOrientationType: String?
init(plugin: ScreenOrientationPlugin) {
self.plugin = plugin
super.init()
NotificationCenter.default.addObserver(self, selector: #selector(self.handleOrientationChange), name: UIDevice.orientationDidChangeNotification, object: nil)
}
@objc public static func getSupportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return ScreenOrientation.supportedInterfaceOrientations
}
@objc public func lock(_ orientationType: String, completion: @escaping () -> Void) {
DispatchQueue.main.async { [weak self] in
guard let strongSelf = self else {
return
}
let currentOrientationValue = UIDevice.current.orientation.rawValue
let currentOrientationMask = strongSelf.convertOrientationValueToMask(currentOrientationValue)
let nextOrientationMask = strongSelf.convertOrientationTypeToMask(orientationType)
let nextOrientationValue = strongSelf.convertOrientationTypeToValue(orientationType)
strongSelf.requestGeometryUpdate(orientationValue: nextOrientationValue, orientationMask: nextOrientationMask)
ScreenOrientation.supportedInterfaceOrientations = nextOrientationMask
UINavigationController.attemptRotationToDeviceOrientation()
if #unavailable(iOS 16) {
strongSelf.requestGeometryUpdate(orientationValue: currentOrientationValue, orientationMask: currentOrientationMask)
}
strongSelf.notifyOrientationChangeListeners(orientationType)
completion()
}
}
@objc public func unlock(completion: @escaping () -> Void) {
DispatchQueue.main.async {
ScreenOrientation.supportedInterfaceOrientations = UIInterfaceOrientationMask.all
UINavigationController.attemptRotationToDeviceOrientation()
guard let orientationType = self.lastOrientationType else {
return
}
self.notifyOrientationChangeListeners(orientationType)
completion()
}
}
@objc public func getCachedCurrentOrientationType(completion: @escaping (String) -> Void) {
guard let cachedOrientationType = self.currentOrientationType else {
self.getUncachedCurrentOrientationType(completion: completion)
return
}
completion(cachedOrientationType)
}
@objc private func requestGeometryUpdate(orientationValue: Int, orientationMask: UIInterfaceOrientationMask) {
if #available(iOS 16, *) {
let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
windowScene?.keyWindow?.rootViewController?.setNeedsUpdateOfSupportedInterfaceOrientations()
windowScene?.requestGeometryUpdate(.iOS(interfaceOrientations: orientationMask)) { error in
CAPLog.print("requestGeometryUpdate failed.", error)
}
} else {
UIDevice.current.setValue(orientationValue, forKey: "orientation")
}
}
@objc private func getUncachedCurrentOrientationType(completion: @escaping (String) -> Void) {
DispatchQueue.main.async {
let orientationValue = UIDevice.current.orientation.rawValue
let orientationType = self.convertOrientationValueToType(orientationValue)
completion(orientationType)
}
}
@objc private func isCurrentOrientationValid() -> Bool {
return UIDevice.current.orientation.isValidInterfaceOrientation
}
@objc private func handleOrientationChange() {
let isValid = self.isCurrentOrientationValid()
guard isValid else {
return
}
self.getUncachedCurrentOrientationType(completion: { orientationType in
self.lastOrientationType = orientationType
guard ScreenOrientation.supportedInterfaceOrientations == UIInterfaceOrientationMask.all else {
return
}
self.notifyOrientationChangeListeners(orientationType)
})
}
@objc private func notifyOrientationChangeListeners(_ orientationType: String) {
self.currentOrientationType = orientationType
self.plugin.notifyOrientationChangeListeners(orientationType)
}
@objc private func convertOrientationValueToMask(_ orientationValue: Int) -> UIInterfaceOrientationMask {
switch orientationValue {
case UIInterfaceOrientation.landscapeLeft.rawValue:
return UIInterfaceOrientationMask.landscapeLeft
case UIInterfaceOrientation.landscapeRight.rawValue:
return UIInterfaceOrientationMask.landscapeRight
case UIInterfaceOrientation.portrait.rawValue:
return UIInterfaceOrientationMask.portrait
case UIInterfaceOrientation.portraitUpsideDown.rawValue:
return UIInterfaceOrientationMask.portraitUpsideDown
default:
let isPortrait = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation.isPortrait ?? false
return isPortrait ? UIInterfaceOrientationMask.portrait : UIInterfaceOrientationMask.landscape
}
}
@objc private func convertOrientationTypeToMask(_ orientationType: String) -> UIInterfaceOrientationMask {
switch orientationType {
case "landscape":
return UIInterfaceOrientationMask.landscape
case "landscape-primary":
return UIInterfaceOrientationMask.landscapeLeft
case "landscape-secondary":
return UIInterfaceOrientationMask.landscapeRight
case "portrait":
return UIInterfaceOrientationMask.portrait
case "portrait-primary":
return UIInterfaceOrientationMask.portrait
case "portrait-secondary":
return UIInterfaceOrientationMask.portraitUpsideDown
default:
return UIInterfaceOrientationMask.all
}
}
@objc private func convertOrientationTypeToValue(_ orientationType: String) -> Int {
switch orientationType {
case "landscape":
return UIInterfaceOrientation.landscapeRight.rawValue
case "landscape-primary":
return UIInterfaceOrientation.landscapeLeft.rawValue
case "landscape-secondary":
return UIInterfaceOrientation.landscapeRight.rawValue
case "portrait":
return UIInterfaceOrientation.portrait.rawValue
case "portrait-primary":
return UIInterfaceOrientation.portrait.rawValue
case "portrait-secondary":
return UIInterfaceOrientation.portraitUpsideDown.rawValue
default:
return UIInterfaceOrientation.unknown.rawValue
}
}
@objc private func convertOrientationValueToType(_ orientationValue: Int) -> String {
switch orientationValue {
case UIInterfaceOrientation.landscapeLeft.rawValue:
return "landscape-primary"
case UIInterfaceOrientation.landscapeRight.rawValue:
return "landscape-secondary"
case UIInterfaceOrientation.portrait.rawValue:
return "portrait-primary"
case UIInterfaceOrientation.portraitUpsideDown.rawValue:
return "portrait-secondary"
default:
let isPortrait = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation.isPortrait ?? false
return isPortrait ? "portrait-primary" : "landscape-primary"
}
}
}