AzureCommunicationUI/sdk/AzureCommunicationUICalling/Sources/Presentation/SwiftUI/Container/ContainerUIHostingController.swift (115 lines of code) (raw):
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
import Foundation
import SwiftUI
class ContainerUIHostingController: UIHostingController<ContainerUIHostingController.Root> {
class EnvironmentProperty {
@Published var supportedOrientations: UIInterfaceOrientationMask
@Published var isProximitySensorOn: Bool
@Published var prefersHomeIndicatorAutoHidden: Bool
init() {
self.supportedOrientations = .allButUpsideDown
self.isProximitySensorOn = false
self.prefersHomeIndicatorAutoHidden = false
}
}
private let callComposite: CallComposite
private let environmentProperties: EnvironmentProperty
private let cancelBag = CancelBag()
init(rootView: ContainerView,
callComposite: CallComposite,
isRightToLeft: Bool) {
let environmentProperties = EnvironmentProperty()
let environmentRoot = Root(containerView: rootView,
environmentProperties: environmentProperties)
self.callComposite = callComposite
self.environmentProperties = environmentProperties
super.init(rootView: environmentRoot)
self.view.semanticContentAttribute = isRightToLeft ?
.forceRightToLeft : .forceLeftToRight
subscribeEnvironmentProperties(containerView: rootView)
}
@objc required dynamic init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
overrideUserInterfaceStyle = StyleProvider.color.colorSchemeOverride
view.backgroundColor = StyleProvider.color.backgroundColor
}
override func viewDidDisappear(_ animated: Bool) {
resetUIDeviceSetup()
super.viewDidDisappear(animated)
}
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
self.environmentProperties.supportedOrientations
}
private func subscribeEnvironmentProperties(containerView: ContainerView) {
environmentProperties
.$supportedOrientations
.receive(on: RunLoop.main)
.removeDuplicates()
.sink(receiveValue: { [weak self] _ in
switch containerView.router.currentView {
case .setupView:
guard let self = self,
self.traitCollection.userInterfaceIdiom == .phone else {
return
}
if UIDevice.current.isGeneratingDeviceOrientationNotifications {
// This work-around is to make sure the setup view rotates back to portrait if the previous
// screen was on a different orientation.
// The 0.35s delay here is to wait for any orientation switch animation that happends at
// the same time with the steup view navigation.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) {
if UIDevice.current.orientation != .portrait {
UIDevice.current.rotateTo(orientation: .portrait)
}
}
}
default:
if !UIDevice.current.isGeneratingDeviceOrientationNotifications {
UIDevice.current.beginGeneratingDeviceOrientationNotifications()
}
}
}).store(in: cancelBag)
environmentProperties
.$isProximitySensorOn
.receive(on: RunLoop.main)
.removeDuplicates()
.sink(receiveValue: { isEnable in
UIDevice.current.toggleProximityMonitoringStatus(isEnabled: isEnable)
}).store(in: cancelBag)
environmentProperties
.$prefersHomeIndicatorAutoHidden
.receive(on: RunLoop.main)
.sink(receiveValue: { [weak self] shouldHide in
guard let strongSelf = self else {
return
}
strongSelf._prefersHomeIndicatorAutoHidden = shouldHide
}).store(in: cancelBag)
}
private func resetUIDeviceSetup() {
UIDevice.current.toggleProximityMonitoringStatus(isEnabled: false)
if !UIDevice.current.isGeneratingDeviceOrientationNotifications {
UIDevice.current.beginGeneratingDeviceOrientationNotifications()
}
}
struct Root: View {
let containerView: ContainerView
let environmentProperties: EnvironmentProperty
var body: some View {
containerView
.onPreferenceChange(SupportedOrientationsPreferenceKey.self) {
// Update the binding to set the value on the root controller.
self.environmentProperties.supportedOrientations = $0
}
.onPreferenceChange(ProximitySensorPreferenceKey.self) {
self.environmentProperties.isProximitySensorOn = $0
}
.onPreferenceChange(PrefersHomeIndicatorAutoHiddenPreferenceKey.self) {
self.environmentProperties.prefersHomeIndicatorAutoHidden = $0
}
}
}
// MARK: Prefers Home Indicator Auto Hidden
private var _prefersHomeIndicatorAutoHidden = false {
didSet { setNeedsUpdateOfHomeIndicatorAutoHidden() }
}
override var prefersHomeIndicatorAutoHidden: Bool {
_prefersHomeIndicatorAutoHidden
}
}