Files
featherVoice/TUIKit/TUICallKit/TUICallKit-Swift/View/WindowManager.swift
2025-08-08 10:49:36 +08:00

201 lines
6.9 KiB
Swift

//
// WindowManger.swift
// TUICallKit
//
// Created by vincepzhang on 2023/2/22.
//
import Foundation
class WindowManager: NSObject, FloatingWindowViewDelegate {
static let instance = WindowManager()
var isFloating = false
var floatWindowBeganPoint: CGPoint = .zero
let mediaTypeObserver = Observer()
let callWindow: UIWindow = {
let callWindow = UIWindow()
callWindow.windowLevel = .alert - 1
return callWindow
}()
let floatWindow: UIWindow = {
let floatWindow = UIWindow()
floatWindow.windowLevel = .alert - 1
floatWindow.layer.masksToBounds = true
return floatWindow
}()
var callKitViewController: CallKitViewController?
func getCallKitViewController() -> CallKitViewController {
if let callKitViewController = callKitViewController {
return callKitViewController
} else {
let newCallKitViewController = CallKitViewController()
callKitViewController = newCallKitViewController
return newCallKitViewController
}
}
override init() {
super.init()
registerObserveState()
}
deinit {
TUICallState.instance.mediaType.removeObserver(mediaTypeObserver)
}
func showCallWindow(_ isIncomingCall: Bool = true) {
if isIncomingCall && TUICallState.instance.selfUser.value.callRole.value == .called {
showIncomingFloatView()
} else {
showCallView()
}
}
func closeCallWindow() {
callKitViewController = nil
callWindow.rootViewController = nil
callWindow.isHidden = true
}
func showIncomingFloatView() {
let viewController = UIViewController()
viewController.view.addSubview(IncomingFloatView(frame: CGRect.zero))
callWindow.rootViewController = viewController
callWindow.isHidden = false
callWindow.backgroundColor = UIColor.clear
callWindow.frame = CGRect(x: 8.scaleWidth(),
y: StatusBar_Height + 10,
width: Screen_Width - 16.scaleWidth(),
height: 92.scaleWidth())
callWindow.t_makeKeyAndVisible()
}
func showCallView() {
closeFloatWindow()
callWindow.rootViewController = CallKitNavigationController(rootViewController: getCallKitViewController())
callWindow.isHidden = false
callWindow.frame = CGRect(x: 0, y: 0, width: Screen_Width, height: Screen_Height)
callWindow.t_makeKeyAndVisible()
}
func showFloatWindow() {
closeCallWindow()
let floatViewController = FloatWindowViewController()
floatViewController.delegate = self
floatWindow.rootViewController = floatViewController
floatWindow.backgroundColor = UIColor.clear
floatWindow.isHidden = false
floatWindow.frame = getFloatWindowFrame()
updateFloatWindowFrame()
floatWindow.t_makeKeyAndVisible()
isFloating = true
}
func closeFloatWindow() {
floatWindow.rootViewController = nil
floatWindow.isHidden = true
isFloating = false
}
func getFloatWindowFrame() -> CGRect {
if TUICallState.instance.scene.value == .group {
return kMicroGroupViewRect
}
if TUICallState.instance.mediaType.value == .audio {
return kMicroAudioViewRect
} else {
return kMicroVideoViewRect
}
}
func updateFloatWindowFrame() {
let originY = floatWindow.frame.origin.y
if TUICallState.instance.scene.value == .group {
let dstX = floatWindow.frame.origin.x < (Screen_Width / 2.0) ? 0 : (Screen_Width - kMicroGroupViewWidth)
floatWindow.frame = CGRect(x: dstX, y: originY, width: kMicroGroupViewWidth, height: kMicroGroupViewHeight)
return
}
if TUICallState.instance.mediaType.value == .audio {
let dstX = floatWindow.frame.origin.x < (Screen_Width / 2.0) ? 0 : (Screen_Width - kMicroAudioViewWidth)
floatWindow.frame = CGRect(x: dstX, y: originY, width: kMicroAudioViewWidth, height: kMicroAudioViewHeight)
} else {
let dstX = floatWindow.frame.origin.x < (Screen_Width / 2.0) ? 0 : (Screen_Width - kMicroVideoViewWidth)
floatWindow.frame = CGRect(x: dstX, y: originY, width: kMicroVideoViewWidth, height: kMicroVideoViewHeight)
}
}
func registerObserveState() {
TUICallState.instance.mediaType.addObserver(mediaTypeObserver, closure: { [weak self] newValue, _ in
guard let self = self else { return }
if self.isFloating {
self.updateFloatWindowFrame()
}
})
}
// MARK: FloatingWindowViewDelegate
func tapGestureAction(tapGesture: UITapGestureRecognizer) {
showCallWindow(false)
}
func panGestureAction(panGesture: UIPanGestureRecognizer) {
switch panGesture.state {
case .began:
floatWindowBeganPoint = floatWindow.frame.origin
break
case.changed:
let point = panGesture.translation(in: floatWindow)
var dstX = floatWindowBeganPoint.x + point.x
var dstY = floatWindowBeganPoint.y + point.y
if dstX < 0 {
dstX = 0
} else if dstX > (Screen_Width - floatWindow.frame.size.width) {
dstX = Screen_Width - floatWindow.frame.size.width
}
if dstY < 0 {
dstY = 0
} else if dstY > (Screen_Height - floatWindow.frame.size.height) {
dstY = Screen_Height - floatWindow.frame.size.height
}
floatWindow.frame = CGRect(x: dstX,
y: dstY,
width: floatWindow.frame.size.width,
height: floatWindow.frame.size.height)
break
case.cancelled:
break
case.ended:
var dstX: CGFloat = 0
let currentCenterX: CGFloat = floatWindow.frame.origin.x + floatWindow.frame.size.width / 2.0
if currentCenterX < Screen_Width / 2 {
dstX = CGFloat(0)
} else if currentCenterX > Screen_Width / 2 {
dstX = CGFloat(Screen_Width - floatWindow.frame.size.width)
}
floatWindow.frame = CGRect(x: dstX,
y: floatWindow.frame.origin.y,
width: floatWindow.frame.size.width,
height: floatWindow.frame.size.height)
break
default:
break
}
}
}