284 lines
9.6 KiB
Swift
284 lines
9.6 KiB
Swift
//
|
|
// GroupCallView.swift
|
|
// TUICallKit
|
|
//
|
|
// Created by vincepzhang on 2023/1/6.
|
|
//
|
|
|
|
class GroupCallView: UIView {
|
|
|
|
let selfCallStatusObserver = Observer()
|
|
let mediaTypeObserver = Observer()
|
|
private var isViewReady: Bool = false
|
|
|
|
let backgroundView = {
|
|
return GroupBackgroundView(frame: CGRect.zero)
|
|
}()
|
|
|
|
let maskedView = {
|
|
let maskedView = UIView(frame: CGRect.zero)
|
|
maskedView.backgroundColor = UIColor.t_colorWithHexString(color: "#22262E", alpha: 0.85)
|
|
return maskedView
|
|
}()
|
|
|
|
let layoutView = {
|
|
return GroupCallVideoLayout(frame: CGRect.zero)
|
|
}()
|
|
|
|
let floatingWindowBtn = {
|
|
return FloatingWindowButton(frame: CGRect.zero)
|
|
}()
|
|
|
|
let inviteUserButton = {
|
|
return InviteUserButton(frame: CGRect.zero)
|
|
}()
|
|
|
|
let inviterUserInfoView = {
|
|
return GroupCallerUserInfoView(frame: CGRect.zero)
|
|
}()
|
|
|
|
lazy var inviteeAvatarListView = {
|
|
return InviteeAvatarListView(frame: CGRect.zero)
|
|
}()
|
|
|
|
let waitingHintView = {
|
|
return CallWaitingHintView(frame: CGRect.zero)
|
|
}()
|
|
|
|
let functionView = {
|
|
let height = groupFunctionViewHeight + 30.scaleWidth()
|
|
return GroupCallerAndCalleeAcceptedView(frame: CGRect(x: 0, y: Screen_Height - height, width: Screen_Width, height: height))
|
|
}()
|
|
|
|
let inviteeWaitFunctionView = {
|
|
return AudioAndVideoCalleeWaitingView(frame: CGRect.zero)
|
|
}()
|
|
|
|
let timerView: TimerView = {
|
|
return TimerView(frame: CGRect.zero)
|
|
}()
|
|
|
|
let callStatusTipLabel: UILabel = {
|
|
let tipLabel = UILabel()
|
|
tipLabel.font = UIFont.systemFont(ofSize: 15.0)
|
|
tipLabel.textColor = UIColor.t_colorWithHexString(color: "#FFFFFF")
|
|
tipLabel.textAlignment = .center
|
|
tipLabel.text = TUICallKitLocalize(key: "TUICallKit.Group.waitAccept") ?? ""
|
|
return tipLabel
|
|
}()
|
|
|
|
override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
self.frame = CGRect(x: 0, y: 0, width: Screen_Width, height: Screen_Height)
|
|
backgroundColor = UIColor.t_colorWithHexString(color: "#303132")
|
|
functionView.delegate = self
|
|
createGroupCallView()
|
|
registerObserveState()
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
deinit {
|
|
TUICallState.instance.selfUser.value.callStatus.removeObserver(selfCallStatusObserver)
|
|
TUICallState.instance.mediaType.removeObserver(mediaTypeObserver)
|
|
|
|
for view in subviews {
|
|
view.removeFromSuperview()
|
|
}
|
|
}
|
|
|
|
// MARK: UI Specification Processing
|
|
override func didMoveToWindow() {
|
|
super.didMoveToWindow()
|
|
if isViewReady { return }
|
|
constructViewHierarchy()
|
|
activateConstraints()
|
|
isViewReady = true
|
|
}
|
|
|
|
func constructViewHierarchy() {
|
|
addSubview(backgroundView)
|
|
addSubview(maskedView)
|
|
addSubview(layoutView)
|
|
addSubview(floatingWindowBtn)
|
|
addSubview(inviteUserButton)
|
|
addSubview(inviterUserInfoView)
|
|
addSubview(waitingHintView)
|
|
addSubview(functionView)
|
|
addSubview(inviteeWaitFunctionView)
|
|
addSubview(timerView)
|
|
addSubview(callStatusTipLabel)
|
|
}
|
|
|
|
func activateConstraints() {
|
|
backgroundView.snp.makeConstraints { make in
|
|
make.edges.equalTo(self)
|
|
}
|
|
maskedView.snp.makeConstraints { make in
|
|
make.edges.equalTo(self)
|
|
}
|
|
layoutView.snp.makeConstraints { make in
|
|
make.top.equalToSuperview().offset(StatusBar_Height + 48)
|
|
make.centerX.equalTo(self)
|
|
make.width.equalTo(Screen_Width)
|
|
make.bottom.equalTo(functionView.snp.top)
|
|
}
|
|
floatingWindowBtn.snp.makeConstraints { make in
|
|
make.top.equalToSuperview().offset(StatusBar_Height + 12.scaleHeight())
|
|
make.leading.equalToSuperview().offset(12.scaleWidth())
|
|
make.size.equalTo(kFloatWindowButtonSize)
|
|
}
|
|
inviteUserButton.snp.makeConstraints { make in
|
|
make.size.equalTo(kInviteUserButtonSize)
|
|
make.top.equalToSuperview().offset(StatusBar_Height + 12.scaleHeight())
|
|
make.trailing.equalTo(snp.trailing).offset(-12.scaleWidth())
|
|
}
|
|
inviterUserInfoView.snp.makeConstraints { make in
|
|
make.top.equalTo(self).offset(StatusBar_Height + 150.scaleHeight())
|
|
make.leading.equalTo(self).offset(20)
|
|
make.trailing.equalTo(self).offset(-20)
|
|
make.height.equalTo(100.scaleWidth() + 30.scaleHeight() + 50)
|
|
}
|
|
inviteeWaitFunctionView.snp.makeConstraints({ make in
|
|
make.centerX.equalTo(self)
|
|
make.bottom.equalTo(self.snp.bottom).offset(-Bottom_SafeHeight - 40.scaleHeight())
|
|
make.height.equalTo(60.scaleWidth() + 5.scaleHeight() + 20)
|
|
make.width.equalTo(self.snp.width)
|
|
})
|
|
timerView.snp.makeConstraints { make in
|
|
make.centerX.equalTo(self)
|
|
make.centerY.equalTo(floatingWindowBtn)
|
|
make.width.equalTo(200)
|
|
make.height.equalTo(30)
|
|
}
|
|
callStatusTipLabel.snp.makeConstraints { make in
|
|
make.edges.equalTo(timerView)
|
|
}
|
|
waitingHintView.snp.makeConstraints { make in
|
|
make.centerX.equalTo(self)
|
|
make.height.equalTo(20)
|
|
make.width.equalTo(self)
|
|
make.bottom.equalTo(self.timerView.snp.top)
|
|
}
|
|
}
|
|
|
|
func addInviteeAvatarListView() {
|
|
maskedView.addSubview(inviteeAvatarListView)
|
|
inviteeAvatarListView.snp.makeConstraints { make in
|
|
make.centerX.equalTo(maskedView)
|
|
make.width.equalTo(maskedView)
|
|
make.height.equalTo(60 + 5.scaleWidth())
|
|
make.top.equalTo(maskedView).offset(Screen_Height * 3 / 5)
|
|
}
|
|
}
|
|
|
|
func removeInviteeAvatarListView() {
|
|
inviteeAvatarListView.removeFromSuperview()
|
|
}
|
|
|
|
// MARK: View Create & Manage
|
|
func createGroupCallView() {
|
|
handleFloatingWindowBtn()
|
|
|
|
if TUICallState.instance.selfUser.value.callStatus.value == .waiting {
|
|
if TUICallState.instance.selfUser.value.callRole.value == .call {
|
|
createCallWaitingView()
|
|
} else if TUICallState.instance.selfUser.value.callRole.value == .called {
|
|
createCalledWaitingView()
|
|
}
|
|
} else if TUICallState.instance.selfUser.value.callStatus.value == .accept {
|
|
createCallingView()
|
|
}
|
|
}
|
|
|
|
func handleFloatingWindowBtn() {
|
|
if TUICallState.instance.enableFloatWindow {
|
|
floatingWindowBtn.isHidden = false
|
|
} else {
|
|
floatingWindowBtn.isHidden = true
|
|
}
|
|
}
|
|
|
|
func createCallWaitingView() {
|
|
hiddenChangeSubview()
|
|
layoutView.isHidden = false
|
|
inviteUserButton.isHidden = false
|
|
functionView.isHidden = false
|
|
callStatusTipLabel.isHidden = false
|
|
waitingHintView.isHidden = TUICallState.instance.selfUser.value.callRole.value == .call ? true : false
|
|
}
|
|
|
|
func createCalledWaitingView() {
|
|
hiddenChangeSubview()
|
|
inviterUserInfoView.isHidden = false
|
|
inviteeWaitFunctionView.isHidden = false
|
|
addInviteeAvatarListView()
|
|
}
|
|
|
|
func createCallingView() {
|
|
removeInviteeAvatarListView()
|
|
hiddenChangeSubview()
|
|
layoutView.isHidden = false
|
|
inviteUserButton.isHidden = false
|
|
functionView.isHidden = false
|
|
timerView.isHidden = false
|
|
}
|
|
|
|
func hiddenChangeSubview() {
|
|
layoutView.isHidden = true
|
|
inviteUserButton.isHidden = true
|
|
inviterUserInfoView.isHidden = true
|
|
functionView.isHidden = true
|
|
inviteeWaitFunctionView.isHidden = true
|
|
timerView.isHidden = true
|
|
callStatusTipLabel.isHidden = true
|
|
waitingHintView.isHidden = true
|
|
}
|
|
|
|
// MARK: Register TUICallState Observer && Update UI
|
|
func registerObserveState() {
|
|
callStatusChanged()
|
|
mediaTypeChanged()
|
|
}
|
|
|
|
func callStatusChanged() {
|
|
TUICallState.instance.selfUser.value.callStatus.addObserver(selfCallStatusObserver, closure: { [weak self] newValue, _ in
|
|
guard let self = self else { return }
|
|
self.createGroupCallView()
|
|
})
|
|
}
|
|
|
|
func mediaTypeChanged() {
|
|
TUICallState.instance.mediaType.addObserver(mediaTypeObserver) { [weak self] newValue, _ in
|
|
guard let self = self else { return }
|
|
self.createGroupCallView()
|
|
}
|
|
}
|
|
}
|
|
|
|
extension GroupCallView: GroupCallerAndCalleeAcceptedViewDelegate {
|
|
|
|
func showAnimation() {
|
|
UIView.animate(withDuration: groupFunctionAnimationDuration) {
|
|
self.functionView.frame = CGRect(x: 0,
|
|
y: Screen_Height - groupSmallFunctionViewHeight,
|
|
width: Screen_Width,
|
|
height: groupSmallFunctionViewHeight)
|
|
}
|
|
}
|
|
|
|
func restoreExpansion() {
|
|
UIView.animate(withDuration: groupFunctionAnimationDuration) {
|
|
self.functionView.frame = CGRect(x: 0, y: Screen_Height - groupFunctionViewHeight, width: Screen_Width, height: groupFunctionViewHeight)
|
|
}
|
|
}
|
|
|
|
func handleTransform(animationScale: CGFloat) {
|
|
let height = groupFunctionViewHeight - (groupFunctionViewHeight - groupSmallFunctionViewHeight) * animationScale
|
|
self.functionView.frame = CGRect(x: 0, y: Screen_Height - height, width: Screen_Width, height: height)
|
|
}
|
|
|
|
}
|