提交
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// ChatExtensionRoomSettingsViewController.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by janejntang on 2023/6/26.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class ChatExtensionRoomSettingsViewController: UIViewController {
|
||||
let roomView: ChatExtensionRoomSettingsView
|
||||
init(isOpenMicrophone: Bool, isOpenCamera: Bool) {
|
||||
let viewModel = ChatExtensionRoomSettingsViewModel(isOpenMicrophone: isOpenMicrophone, isOpenCamera: isOpenCamera)
|
||||
roomView = ChatExtensionRoomSettingsView(viewModel: viewModel)
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func loadView() {
|
||||
view = roomView
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
setNavBar()
|
||||
}
|
||||
|
||||
private func setNavBar() {
|
||||
navigationItem.title = .roomDeviceSetText
|
||||
}
|
||||
|
||||
deinit {
|
||||
debugPrint("deinit \(self)")
|
||||
}
|
||||
}
|
||||
private extension String {
|
||||
static var roomDeviceSetText: String {
|
||||
localized("Meeting Settings")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// InvitedToJoinRoomViewController.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by janejntang on 2023/5/25.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class InvitedToJoinRoomViewController: UIViewController {
|
||||
let roomView: InvitedToJoinRoomView
|
||||
let viewModel: InvitedToJoinRoomViewModel
|
||||
init(inviteUserName: String,inviteUserAvatarUrl: String, roomId: String) {
|
||||
viewModel = InvitedToJoinRoomViewModel(inviteUserName: inviteUserName, inviteUserAvatarUrl:inviteUserAvatarUrl, roomId: roomId)
|
||||
roomView = InvitedToJoinRoomView(viewModel: viewModel)
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func loadView() {
|
||||
view = roomView
|
||||
}
|
||||
|
||||
override func viewDidDisappear(_ animated: Bool) {
|
||||
viewModel.stopPlay()
|
||||
}
|
||||
|
||||
deinit {
|
||||
debugPrint("deinit \(self)")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// ChatExtensionRoomSettingsItemView.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by janejntang on 2023/6/27.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class ChatExtensionRoomSettingsItemView: UIView {
|
||||
let itemData: RoomSetListItemData
|
||||
let titleLabel: UILabel = {
|
||||
let view = UILabel()
|
||||
view.backgroundColor = .clear
|
||||
view.textColor = .black
|
||||
view.font = UIFont(name: "PingFangSC-Medium", size: 14)
|
||||
view.minimumScaleFactor = 0.5
|
||||
return view
|
||||
}()
|
||||
|
||||
let rightSwitch: UISwitch = {
|
||||
let view = UISwitch()
|
||||
view.isOn = true
|
||||
view.onTintColor = UIColor(0x0062E3)
|
||||
return view
|
||||
}()
|
||||
|
||||
let line: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .gray
|
||||
view.alpha = 0.3
|
||||
return view
|
||||
}()
|
||||
|
||||
init(itemData: RoomSetListItemData) {
|
||||
self.itemData = itemData
|
||||
super.init(frame: .zero)
|
||||
}
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
private var isViewReady: Bool = false
|
||||
override func didMoveToWindow() {
|
||||
super.didMoveToWindow()
|
||||
guard !isViewReady else { return }
|
||||
constructViewHierarchy()
|
||||
activateConstraints()
|
||||
bindInteraction()
|
||||
isViewReady = true
|
||||
}
|
||||
|
||||
private func constructViewHierarchy() {
|
||||
addSubview(titleLabel)
|
||||
addSubview(rightSwitch)
|
||||
addSubview(line)
|
||||
}
|
||||
|
||||
private func activateConstraints() {
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.leading.equalToSuperview().offset(10)
|
||||
make.centerY.equalToSuperview()
|
||||
make.width.equalTo(100.scale375())
|
||||
}
|
||||
rightSwitch.snp.makeConstraints { make in
|
||||
make.trailing.equalToSuperview().offset(-10)
|
||||
make.centerY.equalToSuperview()
|
||||
}
|
||||
line.snp.makeConstraints { make in
|
||||
make.leading.equalToSuperview().offset(10)
|
||||
make.trailing.equalToSuperview().offset(-10)
|
||||
make.bottom.equalToSuperview().offset(-2)
|
||||
make.height.equalTo(0.5)
|
||||
}
|
||||
}
|
||||
|
||||
private func bindInteraction() {
|
||||
backgroundColor = .white
|
||||
titleLabel.text = itemData.titleText
|
||||
rightSwitch.isOn = itemData.isSwitchOn
|
||||
rightSwitch.addTarget(self, action: #selector(switchAction(sender:)), for: .touchUpInside)
|
||||
}
|
||||
@objc func switchAction(sender: UISwitch) {
|
||||
itemData.action?(sender)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// ChatExtensionRoomSettingsView.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by janejntang on 2023/6/26.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class ChatExtensionRoomSettingsView: UIView {
|
||||
let viewModel : ChatExtensionRoomSettingsViewModel
|
||||
|
||||
let stackView: UIStackView = {
|
||||
let view = UIStackView()
|
||||
view.axis = .vertical
|
||||
view.alignment = .center
|
||||
view.distribution = .equalSpacing
|
||||
view.spacing = 0
|
||||
return view
|
||||
}()
|
||||
|
||||
init(viewModel: ChatExtensionRoomSettingsViewModel) {
|
||||
self.viewModel = viewModel
|
||||
super.init(frame: .zero)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
// MARK: - view layout
|
||||
private var isViewReady: Bool = false
|
||||
override func didMoveToWindow() {
|
||||
super.didMoveToWindow()
|
||||
guard !isViewReady else { return }
|
||||
backgroundColor = .white
|
||||
constructViewHierarchy()
|
||||
activateConstraints()
|
||||
isViewReady = true
|
||||
}
|
||||
|
||||
private func constructViewHierarchy() {
|
||||
addSubview(stackView)
|
||||
for item in viewModel.roomSettingsViewItems {
|
||||
let view = ChatExtensionRoomSettingsItemView(itemData: item)
|
||||
stackView.addArrangedSubview(view)
|
||||
view.snp.makeConstraints { make in
|
||||
make.height.equalTo(60.scale375())
|
||||
make.width.equalToSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func activateConstraints() {
|
||||
stackView.snp.makeConstraints { make in
|
||||
make.top.equalTo(safeAreaLayoutGuide.snp.top).offset(10)
|
||||
make.leading.equalToSuperview().offset(10)
|
||||
make.trailing.equalToSuperview().offset(-10)
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
debugPrint("deinit \(self)")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
//
|
||||
// RoomaInviteView.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by janejntang on 2023/5/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class InvitedToJoinRoomView: UIView {
|
||||
let viewModel : InvitedToJoinRoomViewModel
|
||||
let userNameLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont(name: "PingFangSC-Regular", size: 30)
|
||||
label.textColor = .white
|
||||
return label
|
||||
}()
|
||||
let inviteLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont(name: "PingFangSC-Regular", size: 15)
|
||||
label.text = .inviteMeetingText
|
||||
label.textColor = .white
|
||||
return label
|
||||
}()
|
||||
let userImageView: UIImageView = {
|
||||
let image = UIImageView()
|
||||
return image
|
||||
}()
|
||||
|
||||
let disagreeButton: UIButton = {
|
||||
let button = UIButton(type: .custom)
|
||||
return button
|
||||
}()
|
||||
let disagreeImageView: UIImageView = {
|
||||
let image = UIImage(named: "room_hangup", in: tuiRoomKitBundle(), compatibleWith: nil)
|
||||
let imageView = UIImageView(image: image)
|
||||
return imageView
|
||||
}()
|
||||
let disagreeLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.text = .declineText
|
||||
label.textColor = .red
|
||||
label.textAlignment = .center
|
||||
label.font = UIFont.systemFont(ofSize: 20.0)
|
||||
return label
|
||||
}()
|
||||
let agreeButton: UIButton = {
|
||||
let button = UIButton(type: .custom)
|
||||
return button
|
||||
}()
|
||||
let agreeImageView: UIImageView = {
|
||||
let image = UIImage(named: "room_handsfree_on", in: tuiRoomKitBundle(), compatibleWith: nil)
|
||||
let imageView = UIImageView(image: image)
|
||||
return imageView
|
||||
}()
|
||||
let agreeLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.text = .agreeText
|
||||
label.textColor = .white
|
||||
label.textAlignment = .center
|
||||
label.font = UIFont.systemFont(ofSize: 20.0)
|
||||
return label
|
||||
}()
|
||||
|
||||
init(viewModel: InvitedToJoinRoomViewModel) {
|
||||
self.viewModel = viewModel
|
||||
super.init(frame: .zero)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
// MARK: - view layout
|
||||
private var isViewReady: Bool = false
|
||||
override func didMoveToWindow() {
|
||||
super.didMoveToWindow()
|
||||
guard !isViewReady else { return }
|
||||
backgroundColor = UIColor(0x242424)
|
||||
constructViewHierarchy()
|
||||
activateConstraints()
|
||||
bindInteraction()
|
||||
isViewReady = true
|
||||
}
|
||||
private func constructViewHierarchy() {
|
||||
addSubview(userNameLabel)
|
||||
addSubview(inviteLabel)
|
||||
addSubview(userImageView)
|
||||
addSubview(disagreeButton)
|
||||
disagreeButton.addSubview(disagreeImageView)
|
||||
disagreeButton.addSubview(disagreeLabel)
|
||||
addSubview(agreeButton)
|
||||
agreeButton.addSubview(agreeImageView)
|
||||
agreeButton.addSubview(agreeLabel)
|
||||
}
|
||||
private func activateConstraints() {
|
||||
userNameLabel.snp.makeConstraints { make in
|
||||
make.top.equalTo(safeAreaLayoutGuide.snp.top).offset(30)
|
||||
make.trailing.equalToSuperview().offset(-130)
|
||||
}
|
||||
inviteLabel.snp.makeConstraints { make in
|
||||
make.trailing.equalTo(userNameLabel)
|
||||
make.top.equalTo(userNameLabel.snp.bottom).offset(15)
|
||||
}
|
||||
userImageView.snp.makeConstraints { make in
|
||||
make.top.equalTo(userNameLabel)
|
||||
make.trailing.equalToSuperview().offset(-20)
|
||||
make.width.height.equalTo(80)
|
||||
}
|
||||
disagreeButton.snp.makeConstraints { make in
|
||||
make.bottom.equalToSuperview().offset(-100)
|
||||
make.width.equalTo(80)
|
||||
make.height.equalTo(120)
|
||||
make.leading.equalToSuperview().offset(50)
|
||||
}
|
||||
disagreeImageView.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview()
|
||||
make.centerX.equalToSuperview()
|
||||
make.width.height.equalTo(80)
|
||||
}
|
||||
disagreeLabel.snp.makeConstraints { make in
|
||||
make.top.equalTo(disagreeImageView.snp.bottom).offset(5)
|
||||
make.centerX.equalToSuperview()
|
||||
make.width.equalTo(80)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
agreeButton.snp.makeConstraints { make in
|
||||
make.bottom.equalTo(disagreeButton)
|
||||
make.width.equalTo(80)
|
||||
make.height.equalTo(120)
|
||||
make.trailing.equalToSuperview().offset(-50)
|
||||
}
|
||||
agreeImageView.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview()
|
||||
make.centerX.equalToSuperview()
|
||||
make.width.height.equalTo(80)
|
||||
}
|
||||
agreeLabel.snp.makeConstraints { make in
|
||||
make.top.equalTo(agreeImageView.snp.bottom).offset(5)
|
||||
make.centerX.equalToSuperview()
|
||||
make.width.equalTo(80)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
}
|
||||
private func bindInteraction() {
|
||||
disagreeButton.addTarget(self, action: #selector(disagreeAction(sender:)), for: .touchUpInside)
|
||||
agreeButton.addTarget(self, action: #selector(agreeAction(sender:)), for: .touchUpInside)
|
||||
viewModel.startPlay()
|
||||
setupViewState()
|
||||
}
|
||||
func setupViewState() {
|
||||
userNameLabel.text = viewModel.inviteUserName
|
||||
let placeholderImage = UIImage(named: "room_default_avatar", in: tuiRoomKitBundle(), compatibleWith: nil)
|
||||
userImageView.sd_setImage(with: URL(string: viewModel.avatarUrl), placeholderImage: placeholderImage)
|
||||
}
|
||||
@objc private func disagreeAction(sender: UIButton) {
|
||||
viewModel.disagreeAction()
|
||||
}
|
||||
@objc private func agreeAction(sender: UIButton) {
|
||||
viewModel.agreeAction()
|
||||
}
|
||||
|
||||
deinit {
|
||||
debugPrint("deinit \(self)")
|
||||
}
|
||||
}
|
||||
|
||||
private extension String {
|
||||
static var inviteMeetingText: String {
|
||||
localized("Invite you to a meeting")
|
||||
}
|
||||
static var declineText: String {
|
||||
localized("Decline")
|
||||
}
|
||||
static var agreeText: String {
|
||||
localized("Agree")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// RoomMsgCell.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by janejntang on 2023/5/8.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import TIMCommon
|
||||
|
||||
@objc(RoomMessageBubbleCell)
|
||||
class RoomMessageBubbleCell: TUIBubbleMessageCell {
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
guard self.container != nil else { return }
|
||||
let message = RoomMessageModel()
|
||||
let view = RoomMessageView(viewModel: RoomMessageViewModel(message: message))
|
||||
self.container.addSubview(view)
|
||||
view.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
override func fill(with data: TUIBubbleMessageCellData) {
|
||||
super.fill(with: data)
|
||||
let customData = data as? RoomMessageBubbleCellData
|
||||
guard let messageModel = customData?.messageModel as? RoomMessageModel else { return }
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
let subviewArray = self.container.subviews
|
||||
for view in subviewArray where view is RoomMessageView {
|
||||
guard let messageView = view as? RoomMessageView else { continue }
|
||||
messageView.viewModel.changeMessage(message: messageModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override class func getContentSize(_ data: TUIMessageCellData?) -> CGSize {
|
||||
return CGSize(width: 238, height: 157)
|
||||
}
|
||||
|
||||
deinit {
|
||||
debugPrint("deinit \(self)")
|
||||
}
|
||||
}
|
||||
328
TUIKit/TUIRoomKit/RoomExtension/View/View/RoomMessageView.swift
Normal file
328
TUIKit/TUIRoomKit/RoomExtension/View/View/RoomMessageView.swift
Normal file
@@ -0,0 +1,328 @@
|
||||
//
|
||||
// RoomMessageView.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by janejntang on 2023/5/9.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
class RoomMessageView: UIView {
|
||||
let viewModel: RoomMessageViewModel
|
||||
private var viewArray: [UIView] = []
|
||||
let roomStatusView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = UIColor(0xD1E4FD)
|
||||
return view
|
||||
}()
|
||||
let roomStatusImageView: UIImageView = {
|
||||
let image = UIImageView()
|
||||
return image
|
||||
}()
|
||||
let roomStatusLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont(name: "PingFangSC-Regular", size: 15)
|
||||
return label
|
||||
}()
|
||||
let roomNameLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont(name: "PingFangSC-Regular", size: 20)
|
||||
label.textColor = .black
|
||||
label.adjustsFontSizeToFitWidth = true
|
||||
return label
|
||||
}()
|
||||
let stackView: UIStackView = {
|
||||
let view = UIStackView()
|
||||
view.axis = .horizontal
|
||||
view.alignment = .leading
|
||||
view.distribution = .equalSpacing
|
||||
view.spacing = 2
|
||||
return view
|
||||
}()
|
||||
lazy var inviteUserButton: UIButton = {
|
||||
let button = UIButton()
|
||||
button.setImage(UIImage(named: "room_chat_invite", in: tuiRoomKitBundle(), compatibleWith: nil), for: .normal)
|
||||
return button
|
||||
}()
|
||||
let userNumberLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont(name: "PingFangSC-Regular", size: 15)
|
||||
label.adjustsFontSizeToFitWidth = true
|
||||
label.textColor = UIColor(0x888888)
|
||||
label.textAlignment = isRTL ? .right : .left
|
||||
return label
|
||||
}()
|
||||
let enterRoomButton: UIButton = {
|
||||
let button = UIButton()
|
||||
button.setTitle(.enterMeetingText, for: .normal)
|
||||
button.setTitleColor(.white, for: .normal)
|
||||
button.setBackgroundImage(UIColor.tui_color(withHex: "147AFF").trans2Image(), for: .normal)
|
||||
button.setTitle(.alreadyEnteredMeeting, for: .selected)
|
||||
button.setTitleColor(UIColor(0x999999), for: .selected)
|
||||
button.setBackgroundImage(UIColor.tui_color(withHex: "F3F4F4").trans2Image(), for: .selected)
|
||||
button.titleLabel?.font = UIFont(name: "PingFangSC-Regular", size: 15)
|
||||
return button
|
||||
}()
|
||||
let enterRoomStatusLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.adjustsFontSizeToFitWidth = true
|
||||
label.font = UIFont(name: "PingFangSC-Regular", size: 15)
|
||||
label.textColor = UIColor(0x888888)
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
init(viewModel: RoomMessageViewModel) {
|
||||
self.viewModel = viewModel
|
||||
super.init(frame: .zero)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
// MARK: - view layout
|
||||
private var isViewReady: Bool = false
|
||||
override func didMoveToWindow() {
|
||||
super.didMoveToWindow()
|
||||
guard !isViewReady else { return }
|
||||
backgroundColor = .white
|
||||
constructViewHierarchy()
|
||||
activateConstraints()
|
||||
bindInteraction()
|
||||
isViewReady = true
|
||||
}
|
||||
|
||||
func constructViewHierarchy() {
|
||||
addSubview(roomStatusView)
|
||||
roomStatusView.addSubview(roomStatusImageView)
|
||||
roomStatusView.addSubview(roomStatusLabel)
|
||||
roomStatusView.addSubview(roomNameLabel)
|
||||
roomStatusView.addSubview(stackView)
|
||||
setupUserStackView()
|
||||
roomStatusView.addSubview(inviteUserButton)
|
||||
addSubview(enterRoomStatusLabel)
|
||||
addSubview(userNumberLabel)
|
||||
addSubview(enterRoomButton)
|
||||
}
|
||||
func activateConstraints() {
|
||||
roomStatusView.snp.makeConstraints { make in
|
||||
make.top.leading.trailing.equalToSuperview()
|
||||
make.height.equalTo(110)
|
||||
}
|
||||
roomStatusImageView.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview().offset(15)
|
||||
make.leading.equalToSuperview().offset(12)
|
||||
}
|
||||
roomStatusLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(roomStatusImageView)
|
||||
make.leading.equalTo(roomStatusImageView.snp.trailing).offset(4)
|
||||
}
|
||||
roomNameLabel.snp.makeConstraints { make in
|
||||
make.top.equalTo(roomStatusImageView.snp.bottom).offset(9)
|
||||
make.leading.equalTo(roomStatusImageView)
|
||||
make.trailing.equalToSuperview().offset(-12)
|
||||
}
|
||||
stackView.snp.makeConstraints { make in
|
||||
make.leading.equalTo(roomNameLabel)
|
||||
make.bottom.equalToSuperview().offset(-4)
|
||||
}
|
||||
inviteUserButton.snp.makeConstraints { make in
|
||||
make.leading.equalTo(stackView.snp.trailing).offset(2)
|
||||
make.width.height.equalTo(24)
|
||||
make.bottom.equalToSuperview().offset(-4)
|
||||
}
|
||||
userNumberLabel.snp.makeConstraints { make in
|
||||
make.bottom.equalToSuperview().offset(-10)
|
||||
make.leading.equalToSuperview().offset(12)
|
||||
make.width.equalTo(100)
|
||||
make.height.equalTo(20)
|
||||
}
|
||||
enterRoomButton.snp.makeConstraints { make in
|
||||
make.trailing.equalToSuperview().offset(-12)
|
||||
make.bottom.equalToSuperview().offset(-10)
|
||||
make.width.equalTo(70)
|
||||
make.height.equalTo(27)
|
||||
}
|
||||
enterRoomStatusLabel.snp.makeConstraints { make in
|
||||
make.bottom.equalToSuperview().offset(-10)
|
||||
make.centerX.equalToSuperview()
|
||||
make.width.equalTo(150)
|
||||
make.height.equalTo(20)
|
||||
}
|
||||
}
|
||||
func bindInteraction() {
|
||||
viewModel.viewResponder = self
|
||||
enterRoomButton.addTarget(self, action: #selector(enterRoomAction(sender:)), for: .touchUpInside)
|
||||
inviteUserButton.addTarget(self, action: #selector(inviteUserAction(sender:)), for: .touchUpInside)
|
||||
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(longPressAction(sender:)))
|
||||
addGestureRecognizer(longPressGesture)
|
||||
layer.masksToBounds = true
|
||||
layer.borderWidth = 0.5
|
||||
layer.borderColor = UIColor(0xDDDDDD).cgColor
|
||||
setupViewState()
|
||||
}
|
||||
|
||||
@objc func enterRoomAction(sender: UIButton) {
|
||||
viewModel.enterRoomAction()
|
||||
}
|
||||
|
||||
@objc func inviteUserAction(sender: UIButton) {
|
||||
viewModel.inviteUserAction()
|
||||
}
|
||||
|
||||
@objc func longPressAction(sender: UIView) {
|
||||
return
|
||||
}
|
||||
|
||||
func setupViewState() {
|
||||
roomNameLabel.text = (viewModel.message.ownerName ) + .quickMeetingText
|
||||
if viewModel.message.owner != viewModel.userId {
|
||||
inviteUserButton.isHidden = true
|
||||
} else {
|
||||
inviteUserButton.isHidden = false
|
||||
}
|
||||
switch viewModel.message.roomState {
|
||||
case .creating:
|
||||
roomStatusImageView.image = UIImage(named: "room_is_creating", in: tuiRoomKitBundle(), compatibleWith: nil)
|
||||
roomStatusLabel.text = .meetingText
|
||||
enterRoomStatusLabel.isHidden = false
|
||||
enterRoomStatusLabel.text = .startingMeetingText + "..."
|
||||
userNumberLabel.isHidden = true
|
||||
enterRoomButton.isHidden = true
|
||||
roomStatusView.backgroundColor = UIColor(0xDCEAFD)
|
||||
case .created:
|
||||
roomStatusImageView.image = UIImage(named: "room_created_success", in: tuiRoomKitBundle(), compatibleWith: nil)
|
||||
roomStatusLabel.text = .meetingText + "." + .inProgressText
|
||||
roomStatusLabel.textColor = UIColor(0x15B72D)
|
||||
enterRoomButton.isHidden = false
|
||||
userNumberLabel.isHidden = false
|
||||
enterRoomStatusLabel.isHidden = true
|
||||
if viewModel.message.memberCount > 1 {
|
||||
userNumberLabel.text = String(viewModel.message.memberCount) + .peopleEnteredMeetingText
|
||||
} else {
|
||||
userNumberLabel.text = .waitingMembersEnterMeetingText
|
||||
}
|
||||
roomStatusView.backgroundColor = UIColor(0xDCEAFD)
|
||||
case .destroyed:
|
||||
roomStatusImageView.image = UIImage(named: "room_has_destroyed", in: tuiRoomKitBundle(), compatibleWith: nil)
|
||||
roomStatusLabel.text = .meetingText
|
||||
roomStatusLabel.textColor = UIColor(0x888888)
|
||||
enterRoomStatusLabel.isHidden = false
|
||||
enterRoomStatusLabel.text = .meetingEnded
|
||||
enterRoomButton.isHidden = true
|
||||
userNumberLabel.isHidden = true
|
||||
roomStatusView.backgroundColor = UIColor(0xDDDDDD)
|
||||
inviteUserButton.isHidden = true
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
func setupStackView() {
|
||||
if !isViewReady {
|
||||
return
|
||||
}
|
||||
setupUserStackView()
|
||||
layoutIfNeeded()
|
||||
if viewModel.message.memberCount > 1 {
|
||||
userNumberLabel.text = String(viewModel.message.memberCount) + .peopleEnteredMeetingText
|
||||
} else {
|
||||
userNumberLabel.text = .waitingMembersEnterMeetingText
|
||||
}
|
||||
}
|
||||
|
||||
private func setupUserStackView() {
|
||||
var userNumber = 0
|
||||
viewArray.forEach { view in
|
||||
view.removeFromSuperview()
|
||||
}
|
||||
viewModel.message.userList.forEach { userDic in
|
||||
if userNumber >= 5 {
|
||||
let label = UILabel()
|
||||
label.text = "..."
|
||||
viewArray.append(label)
|
||||
stackView.addArrangedSubview(label)
|
||||
label.snp.makeConstraints { make in
|
||||
make.height.equalTo(24)
|
||||
make.width.equalTo(24)
|
||||
}
|
||||
return
|
||||
}
|
||||
let placeholderImage = UIImage(named: "room_default_avatar", in: tuiRoomKitBundle(), compatibleWith: nil)
|
||||
let imageView = UIImageView()
|
||||
if let userAvatar = userDic["faceUrl"] as? String {
|
||||
imageView.sd_setImage(with: URL(string: userAvatar), placeholderImage: placeholderImage)
|
||||
} else {
|
||||
imageView.image = placeholderImage
|
||||
}
|
||||
viewArray.append(imageView)
|
||||
stackView.addArrangedSubview(imageView)
|
||||
imageView.snp.makeConstraints { make in
|
||||
make.height.equalTo(24)
|
||||
make.width.equalTo(24)
|
||||
}
|
||||
userNumber = userNumber + 1
|
||||
}
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
let viewFrame = self.frame
|
||||
let inviteViewFrame = self.inviteUserButton.frame
|
||||
if viewFrame.contains(point) && !inviteViewFrame.contains(point) {
|
||||
return enterRoomButton
|
||||
}
|
||||
return super.hitTest(point, with: event)
|
||||
}
|
||||
|
||||
deinit {
|
||||
debugPrint("deinit \(self)")
|
||||
}
|
||||
}
|
||||
|
||||
extension RoomMessageView: RoomMessageViewResponder {
|
||||
func updateStackView() {
|
||||
setupStackView()
|
||||
}
|
||||
func updateRoomStatus() {
|
||||
setupViewState()
|
||||
}
|
||||
func changeEnterRoomButton(isEnabled: Bool) {
|
||||
enterRoomButton.isEnabled = isEnabled
|
||||
}
|
||||
func updateEnteredRoom() {
|
||||
enterRoomButton.isSelected = true
|
||||
}
|
||||
func updateExitRoom() {
|
||||
enterRoomButton.isSelected = false
|
||||
}
|
||||
}
|
||||
|
||||
private extension String {
|
||||
static var inviteMeetingText: String {
|
||||
localized("Invite you to a meeting")
|
||||
}
|
||||
static var enterMeetingText: String {
|
||||
localized("Enter the meeting")
|
||||
}
|
||||
static var alreadyEnteredMeeting: String {
|
||||
localized("Already entered the meeting")
|
||||
}
|
||||
static var meetingText: String {
|
||||
localized("Meeting")
|
||||
}
|
||||
static var inProgressText: String {
|
||||
localized("Ongoing")
|
||||
}
|
||||
static var peopleEnteredMeetingText: String {
|
||||
localized("People have entered the meeting")
|
||||
}
|
||||
static var startingMeetingText: String {
|
||||
localized("Starting meeting")
|
||||
}
|
||||
static var waitingMembersEnterMeetingText: String {
|
||||
localized("Waiting for members to enter the meeting")
|
||||
}
|
||||
static var meetingEnded: String {
|
||||
localized("Meeting ended")
|
||||
}
|
||||
static var quickMeetingText: String {
|
||||
localized("Quick meeting")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// ChatExtensionRoomSettingsViewModel.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by janejntang on 2023/6/26.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class ChatExtensionRoomSettingsViewModel {
|
||||
var isOpenMicrophone: Bool
|
||||
var isOpenCamera: Bool
|
||||
private let engineManager = EngineManager.shared
|
||||
private(set) var roomSettingsViewItems: [RoomSetListItemData] = []
|
||||
init(isOpenMicrophone: Bool, isOpenCamera: Bool) {
|
||||
self.isOpenMicrophone = isOpenMicrophone
|
||||
self.isOpenCamera = isOpenCamera
|
||||
createRoomSettingsModel()
|
||||
}
|
||||
func createRoomSettingsModel() {
|
||||
let openMicItem = RoomSetListItemData()
|
||||
openMicItem.titleText = .micSeatText
|
||||
openMicItem.isSwitchOn = isOpenMicrophone
|
||||
openMicItem.action = {[weak self] sender in
|
||||
guard let self = self, let view = sender as? UISwitch else { return }
|
||||
self.engineManager.store.isOpenMicrophone = view.isOn
|
||||
}
|
||||
roomSettingsViewItems.append(openMicItem)
|
||||
|
||||
let openCameraItem = RoomSetListItemData()
|
||||
openCameraItem.titleText = .cameraSetText
|
||||
openCameraItem.isSwitchOn = isOpenCamera
|
||||
openCameraItem.action = {[weak self] sender in
|
||||
guard let self = self, let view = sender as? UISwitch else { return }
|
||||
self.engineManager.store.isOpenCamera = view.isOn
|
||||
}
|
||||
roomSettingsViewItems.append(openCameraItem)
|
||||
}
|
||||
}
|
||||
private extension String {
|
||||
static var cameraSetText: String {
|
||||
localized("Join the meeting and start the camera")
|
||||
}
|
||||
static var micSeatText: String {
|
||||
localized("Join the conference and turn on the mic")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
//
|
||||
// RoomaInviteViewModel.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by janejntang on 2023/5/24.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import TUICore
|
||||
import AVFAudio
|
||||
|
||||
class InvitedToJoinRoomViewModel: NSObject, AVAudioPlayerDelegate {
|
||||
let inviteUserName: String
|
||||
let roomId: String
|
||||
var avatarUrl: String
|
||||
var displayLink: CADisplayLink?
|
||||
var audioPlayer: AVAudioPlayer = AVAudioPlayer()
|
||||
var startTime: TimeInterval?
|
||||
var endTime: TimeInterval?
|
||||
var messageManager: RoomMessageManager {
|
||||
return RoomMessageManager.shared
|
||||
}
|
||||
private var roomManager: RoomManager {
|
||||
RoomManager.shared
|
||||
}
|
||||
init(inviteUserName: String, inviteUserAvatarUrl: String, roomId: String) {
|
||||
self.inviteUserName = inviteUserName
|
||||
self.roomId = roomId
|
||||
avatarUrl = inviteUserAvatarUrl
|
||||
super.init()
|
||||
playAudio(forResource: "phone_ringing", ofType: "mp3")
|
||||
}
|
||||
|
||||
func startPlay() {
|
||||
audioPlayer.play()
|
||||
}
|
||||
|
||||
func stopPlay() {
|
||||
audioPlayer.stop()
|
||||
}
|
||||
|
||||
func disagreeAction() {
|
||||
stopPlay()
|
||||
closeInvitedToJoinRoomView()
|
||||
}
|
||||
|
||||
func agreeAction() {
|
||||
stopPlay()
|
||||
if EngineManager.shared.store.isEnteredRoom {
|
||||
roomManager.exitOrDestroyPreviousRoom { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.enterRoom()
|
||||
} onError: { code, message in
|
||||
debugPrint("exitRoom, code:\(code), message:\(message)")
|
||||
}
|
||||
} else {
|
||||
enterRoom()
|
||||
}
|
||||
}
|
||||
|
||||
private func enterRoom() {
|
||||
roomManager.enterRoom(roomId: roomId)
|
||||
closeInvitedToJoinRoomView()
|
||||
}
|
||||
|
||||
private func playAudio(forResource: String, ofType: String){
|
||||
if let bundlePath = Bundle.main.path(forResource: forResource, ofType: ofType) {
|
||||
let url = URL(fileURLWithPath: bundlePath)
|
||||
do {
|
||||
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
|
||||
} catch let error {
|
||||
debugPrint("AVAudioSession set outputAudioPort error:\(error.localizedDescription)")
|
||||
}
|
||||
do {
|
||||
try audioPlayer = AVAudioPlayer(contentsOf: url)
|
||||
audioPlayer.numberOfLoops = -1
|
||||
audioPlayer.delegate = self
|
||||
audioPlayer.prepareToPlay()
|
||||
} catch let error {
|
||||
debugPrint("audioPlayer error: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func closeInvitedToJoinRoomView() {
|
||||
TUIRoomImAccessService.shared.inviteWindow?.isHidden = true
|
||||
TUIRoomImAccessService.shared.inviteWindow = nil
|
||||
TUIRoomImAccessService.shared.isShownInvitedToJoinRoomView = false
|
||||
}
|
||||
|
||||
deinit {
|
||||
debugPrint("deinit \(self)")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// RoomMsgViewModel.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by janejntang on 2023/5/8.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import TIMCommon
|
||||
import TUICore
|
||||
import RTCRoomEngine
|
||||
|
||||
@objc(RoomMessageBubbleCellData)
|
||||
class RoomMessageBubbleCellData: TUIBubbleMessageCellData {
|
||||
var messageModel: RoomMessageModel?
|
||||
override init(direction: TMsgDirection) {
|
||||
super.init(direction: direction)
|
||||
}
|
||||
override class func getCellData(_ message: V2TIMMessage) -> TUIMessageCellData {
|
||||
let messageModel = RoomMessageModel()
|
||||
messageModel.updateMessage(message: message)
|
||||
if messageModel.roomId == RoomManager.shared.roomId, messageModel.roomState != .destroyed {
|
||||
RoomManager.shared.roomObserver.messageModel.updateMessage(message: message)
|
||||
}
|
||||
let messageCellData = RoomMessageBubbleCellData(direction: message.isSelf ? .MsgDirectionOutgoing : .MsgDirectionIncoming)
|
||||
messageCellData.messageModel = messageModel
|
||||
return messageCellData
|
||||
}
|
||||
|
||||
override class func getDisplayString(_ message: V2TIMMessage) -> String {
|
||||
let businessID = parseBusinessID(message: message)
|
||||
if businessID == BussinessID_GroupRoomMessage {
|
||||
let dict = TUITool.jsonData2Dictionary(message.customElem.data) as? [String: Any]
|
||||
let userName = dict?["ownerName"] as? String ?? ""
|
||||
return userName + .quickMeetingText
|
||||
} else {
|
||||
return super.getDisplayString(message)
|
||||
}
|
||||
}
|
||||
|
||||
private class func parseBusinessID(message: V2TIMMessage?) -> String {
|
||||
guard let message = message else { return "" }
|
||||
let customData = message.customElem.data
|
||||
let dict = TUITool.jsonData2Dictionary(customData)
|
||||
guard let businessID = dict?["businessID"] as? String else { return ""}
|
||||
return businessID
|
||||
}
|
||||
|
||||
deinit {
|
||||
debugPrint("deinit \(self)")
|
||||
}
|
||||
}
|
||||
|
||||
private extension String {
|
||||
static var quickMeetingText: String {
|
||||
localized("'s quick meeting")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
//
|
||||
// RoomMessageViewModel.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by janejntang on 2023/5/10.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RTCRoomEngine
|
||||
import TUICore
|
||||
import TIMCommon
|
||||
|
||||
protocol RoomMessageViewResponder: NSObject {
|
||||
func updateStackView()
|
||||
func updateRoomStatus()
|
||||
func updateEnteredRoom()
|
||||
func updateExitRoom()
|
||||
}
|
||||
|
||||
class RoomMessageViewModel: NSObject {
|
||||
var message: RoomMessageModel
|
||||
private var engineManager: EngineManager {
|
||||
EngineManager.shared
|
||||
}
|
||||
lazy var userId: String = {
|
||||
return TUILogin.getUserID() ?? EngineManager.shared.store.currentUser.userId
|
||||
}()
|
||||
var messageManager: RoomMessageManager {
|
||||
RoomMessageManager.shared
|
||||
}
|
||||
let roomManager = RoomManager.shared
|
||||
weak var viewResponder: RoomMessageViewResponder?
|
||||
init(message: RoomMessageModel) {
|
||||
self.message = message
|
||||
super.init()
|
||||
roomManager.roomObserver.addListener(listener: self)
|
||||
}
|
||||
|
||||
deinit {
|
||||
roomManager.roomObserver.removeListener(listener: self)
|
||||
debugPrint("deinit \(self)")
|
||||
}
|
||||
|
||||
func changeMessage(message: RoomMessageModel) {
|
||||
self.message = message
|
||||
viewResponder?.updateStackView()
|
||||
viewResponder?.updateRoomStatus()
|
||||
}
|
||||
|
||||
func enterRoomAction() {
|
||||
guard BusinessSceneUtil.canJoinRoom() else { return }
|
||||
if roomManager.isEnteredOtherRoom(roomId: message.roomId) {
|
||||
roomManager.exitOrDestroyPreviousRoom { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.enterRoom()
|
||||
} onError: { [weak self] code, message in
|
||||
debugPrint("exitRoom,code:\(code),message:\(message)")
|
||||
guard let self = self else { return }
|
||||
self.enterRoom()
|
||||
}
|
||||
} else {
|
||||
enterRoom()
|
||||
}
|
||||
}
|
||||
|
||||
private func enterRoom() {
|
||||
if !engineManager.store.isEnteredRoom {
|
||||
roomManager.enterRoom(roomId: message.roomId)
|
||||
} else {
|
||||
EngineEventCenter.shared.notifyUIEvent(key: .TUIRoomKitService_ShowRoomMainView, param: [:])
|
||||
}
|
||||
}
|
||||
|
||||
func inviteUserAction() {
|
||||
guard message.groupId.count > 0 else { return }
|
||||
let inviter = TUILoginUserInfo()
|
||||
inviter.userId = userId
|
||||
inviter.userName = TUILogin.getNickName() ?? ""
|
||||
inviter.avatarUrl = TUILogin.getFaceUrl() ?? ""
|
||||
InviteToJoinRoomManager.startInviteToJoinRoom(message: message, inviter: inviter)
|
||||
}
|
||||
}
|
||||
|
||||
extension RoomMessageViewModel: RoomObserverListener {
|
||||
func onRoomEnter(messageId: String, code: Int, message: String) {
|
||||
if code == 0, messageId == self.message.messageId {
|
||||
viewResponder?.updateEnteredRoom()
|
||||
}
|
||||
}
|
||||
func onRoomExit(messageId: String) {
|
||||
if messageId == self.message.messageId {
|
||||
viewResponder?.updateExitRoom()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user