// // FloatingWindowGroupView.swift // TUICallKit // // Created by noah on 2023/11/21. // import Foundation import UIKit import TUICore class FloatingWindowGroupView: UIView { let viewModel = FloatingWindowViewModel() weak var delegate: FloatingWindowViewDelegate? let selfCallStatusObserver = Observer() let remoteVideoAvailableObserver = Observer() let callTimeObserver = Observer() let currentSpeakUserObserver = Observer() let currentSpeakUserVideoAvailableObserver = Observer() var localPreView: VideoView { if VideoFactory.instance.viewMap[viewModel.selfUser.value.id.value] == nil { let _ = VideoFactory.instance.createVideoView(userId: viewModel.selfUser.value.id.value, frame: CGRect.zero) } VideoFactory.instance.viewMap[viewModel.selfUser.value.id.value]?.videoView.isUserInteractionEnabled = false return VideoFactory.instance.viewMap[viewModel.selfUser.value.id.value]?.videoView ?? VideoView(frame: CGRect.zero) } var remotePreView: VideoView { let remoteUser = viewModel.currentSpeakUser.value if VideoFactory.instance.viewMap[remoteUser.id.value] == nil { let _ = VideoFactory.instance.createVideoView(userId: remoteUser.id.value, frame: CGRect.zero) } VideoFactory.instance.viewMap[remoteUser.id.value]?.videoView.isUserInteractionEnabled = false return VideoFactory.instance.viewMap[remoteUser.id.value]?.videoView ?? VideoView(frame: CGRect.zero) } let avatarImageView: UIImageView = { let avatarImageView = UIImageView() avatarImageView.contentMode = .scaleAspectFill avatarImageView.clipsToBounds = true avatarImageView.isUserInteractionEnabled = false return avatarImageView }() let containerView: UIView = { let containerView = UIView() containerView.backgroundColor = TUICoreDefineConvert.getTUICallKitDynamicColor(colorKey: "callkit_float_window_bg_color", defaultHex: "#FFFFFF") containerView.layer.cornerRadius = 12.scaleWidth() containerView.layer.masksToBounds = true containerView.isUserInteractionEnabled = false return containerView }() let audioContainerView: UIView = { let containerView = UIView() containerView.backgroundColor = TUICoreDefineConvert.getTUICallKitDynamicColor(colorKey: "callkit_float_window_bg_color", defaultHex: "#FFFFFF") return containerView }() let shadowView: UIView = { let shadowView = UIView() shadowView.backgroundColor = TUICoreDefineConvert.getTUICallKitDynamicColor(colorKey: "callkit_float_window_bg_color", defaultHex: "#FFFFFF") shadowView.layer.shadowColor = UIColor.t_colorWithHexString(color: "353941").cgColor shadowView.layer.shadowOpacity = 0.4 shadowView.layer.shadowRadius = 4.scaleWidth() shadowView.layer.shadowOffset = CGSize(width: 0, height: 0) shadowView.layer.cornerRadius = 12.scaleWidth() return shadowView }() let imageView: UIImageView = { let imageView = UIImageView() if let image = TUICallKitCommon.getBundleImage(name: "icon_float_dialing") { imageView.image = image } imageView.isUserInteractionEnabled = false return imageView }() let audioDescribeLabel: UILabel = { let describeLabel = UILabel() describeLabel.font = UIFont.systemFont(ofSize: 12.0) describeLabel.textColor = UIColor.t_colorWithHexString(color: "#12B969") describeLabel.textAlignment = .center describeLabel.isUserInteractionEnabled = false describeLabel.text = TUICallKitLocalize(key: "TUICallKit.FloatingWindow.waitAccept") ?? "" return describeLabel }() lazy var timerLabel: UILabel = { let timerLabel = UILabel() timerLabel.font = UIFont.systemFont(ofSize: 12.0) timerLabel.textColor = UIColor.t_colorWithHexString(color: "#12B969") timerLabel.textAlignment = .center timerLabel.isUserInteractionEnabled = false timerLabel.text = viewModel.getCallTimeString() return timerLabel }() let groupNameLabel: UILabel = { let nameLabel = UILabel() nameLabel.font = UIFont.systemFont(ofSize: 12.0) nameLabel.textColor = UIColor.t_colorWithHexString(color: "#FFFFFF") nameLabel.textAlignment = .center nameLabel.isUserInteractionEnabled = false return nameLabel }() let groupStatusView: UIView = { let statusView = FloatingWindowGroupStatusView() return statusView }() override init(frame: CGRect) { super.init(frame: frame) registerObserverState() constructViewHierarchy() activateConstraints() bindInteraction() updateUI() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } deinit { viewModel.selfCallStatus.removeObserver(selfCallStatusObserver) viewModel.selfCallStatus.removeObserver(currentSpeakUserObserver) viewModel.currentSpeakUser.value.videoAvailable.removeObserver(currentSpeakUserVideoAvailableObserver) viewModel.selfCallStatus.removeObserver(callTimeObserver) for index in 0.. 0 { setGroupRemoteUI() } else { setGroupDefineUI() } } func setGroupDefineUI() { audioContainerView.isHidden = false imageView.isHidden = false timerLabel.isHidden = false groupStatusView.isHidden = false } func setGroupLocalUI() { groupStatusView.isHidden = false groupNameLabel.isHidden = false if TUICallState.instance.isCameraOpen.value { setGroupLocalVideoAvailableUI() } else { setGroupVideoNotAvailableUI() } containerView.bringSubviewToFront(groupNameLabel) } func setGroupRemoteUI() { groupStatusView.isHidden = false groupNameLabel.isHidden = false if viewModel.currentSpeakUser.value.videoAvailable.value { setGroupRemoteVideoAvailableUI() } else { setGroupVideoNotAvailableUI() } containerView.bringSubviewToFront(groupNameLabel) } func setGroupLocalVideoAvailableUI() { avatarImageView.isHidden = true containerView.addSubview(localPreView) localPreView.snp.remakeConstraints { make in make.edges.equalTo(avatarImageView) } } func setGroupRemoteVideoAvailableUI() { avatarImageView.isHidden = true containerView.addSubview(remotePreView) remotePreView.snp.makeConstraints { make in make.edges.equalTo(avatarImageView) } viewModel.startRemoteView(user: viewModel.currentSpeakUser.value, videoView: remotePreView) } func setGroupVideoNotAvailableUI() { avatarImageView.isHidden = false containerView.bringSubviewToFront(avatarImageView) } func cleanView() { avatarImageView.isHidden = true audioContainerView.isHidden = true imageView.isHidden = true audioDescribeLabel.isHidden = true timerLabel.isHidden = true groupStatusView.isHidden = true groupNameLabel.isHidden = true } }