|
|
@@ -11,20 +11,22 @@ import Combine
|
|
|
|
|
|
|
|
|
protocol LNRoomViewModelNotify {
|
|
|
- func onRoomMessageChanged()
|
|
|
+ func onRoomMessageChanged(messages: [LNRoomChatMessageItem])
|
|
|
func onRoomSeatsChanged()
|
|
|
func onRoomSpeakingUsersChanged()
|
|
|
func onRoomSeatApplyChanged()
|
|
|
func onRoomInfoChanged()
|
|
|
+ func onMySeatApplyChanged()
|
|
|
|
|
|
func onRoomClosed()
|
|
|
}
|
|
|
extension LNRoomViewModelNotify {
|
|
|
- func onRoomMessageChanged() { }
|
|
|
+ func onRoomMessageChanged(messages: [LNRoomChatMessageItem]) { }
|
|
|
func onRoomSeatsChanged() { }
|
|
|
func onRoomSpeakingUsersChanged() { }
|
|
|
func onRoomSeatApplyChanged() { }
|
|
|
func onRoomInfoChanged() { }
|
|
|
+ func onMySeatApplyChanged() { }
|
|
|
|
|
|
func onRoomClosed() { }
|
|
|
}
|
|
|
@@ -64,13 +66,22 @@ class LNRoomViewModel: NSObject {
|
|
|
private let seatStore: LiveSeatStore
|
|
|
private let guestStore: CoGuestStore
|
|
|
private let messageStore: BarrageStore
|
|
|
+ private let audienceStore: LiveAudienceStore
|
|
|
+
|
|
|
private(set) var seatsInfo: [LNRoomSeatItem] = []
|
|
|
private(set) var roomInfo = LNRoomInfo()
|
|
|
private(set) var speakingUser: [String] = []
|
|
|
- private(set) var curMessage: [LNRoomMessageItem] = []
|
|
|
+ private(set) var lastmessage: Barrage? = nil
|
|
|
private let seatApplyCountKey = "mic_apply_num"
|
|
|
private(set) var seatApplyCount: Int = 0
|
|
|
- private let maxMessageCount = 300
|
|
|
+ private(set) var waitingForSeat = false {
|
|
|
+ didSet {
|
|
|
+ if oldValue != waitingForSeat {
|
|
|
+ LNEventDeliver.notifyEvent { ($0 as? LNRoomViewModelNotify)?.onMySeatApplyChanged() }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private let systemHandlerQueue = DispatchQueue(label: "com.gami.room.system.message", attributes: .concurrent)
|
|
|
|
|
|
init(roomId: String) {
|
|
|
self.roomId = roomId
|
|
|
@@ -78,12 +89,14 @@ class LNRoomViewModel: NSObject {
|
|
|
seatStore = LiveSeatStore.create(liveID: roomId)
|
|
|
guestStore = CoGuestStore.create(liveID: roomId)
|
|
|
messageStore = BarrageStore.create(liveID: roomId)
|
|
|
+ audienceStore = LiveAudienceStore.create(liveID: roomId)
|
|
|
|
|
|
super.init()
|
|
|
|
|
|
setupSeatObservers()
|
|
|
setupMessageObservers()
|
|
|
setupRoomInfoObserver()
|
|
|
+ setupAudienceEventObservers()
|
|
|
}
|
|
|
|
|
|
func closeRoom() {
|
|
|
@@ -165,12 +178,14 @@ extension LNRoomViewModel {
|
|
|
showToast(.init(key: "A00362"))
|
|
|
return
|
|
|
}
|
|
|
- LNHttpManager.shared.applySeat(roomId: roomId, index: index) { err in
|
|
|
+ LNHttpManager.shared.applySeat(roomId: roomId, index: index) { [weak self] err in
|
|
|
runOnMain {
|
|
|
handler(err == nil)
|
|
|
}
|
|
|
if let err {
|
|
|
showToast(err.errorDesc)
|
|
|
+ } else if let self {
|
|
|
+ waitingForSeat = true
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -178,12 +193,14 @@ extension LNRoomViewModel {
|
|
|
|
|
|
// 取消上麦申请
|
|
|
func cancelSeatApply(handler: @escaping (Bool) -> Void) {
|
|
|
- LNHttpManager.shared.cancelApplySeat(roomId: roomId) { err in
|
|
|
+ LNHttpManager.shared.cancelApplySeat(roomId: roomId) { [weak self] err in
|
|
|
runOnMain {
|
|
|
handler(err == nil)
|
|
|
}
|
|
|
if let err {
|
|
|
showToast(err.errorDesc)
|
|
|
+ } else if let self {
|
|
|
+ waitingForSeat = false
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -376,25 +393,42 @@ extension LNRoomViewModel {
|
|
|
private func setupMessageObservers() {
|
|
|
messageStore.state.subscribe().receive(on: DispatchQueue.main).sink { [weak self] state in
|
|
|
guard let self else { return }
|
|
|
- let lastId = curMessage.last?.id ?? 0
|
|
|
+ let lastId = lastmessage?.sequence ?? 0
|
|
|
+ var newMessage: [Barrage] = []
|
|
|
if let index = state.messageList.lastIndex(where: { $0.sequence == lastId }) {
|
|
|
- curMessage.append(contentsOf: state.messageList[(index + 1)...].map({
|
|
|
- LNRoomMessageItem(info: $0)
|
|
|
- }))
|
|
|
+ newMessage.append(contentsOf: state.messageList[(index + 1)...])
|
|
|
} else {
|
|
|
- curMessage.append(contentsOf: state.messageList.map({
|
|
|
- LNRoomMessageItem(info: $0)
|
|
|
- }))
|
|
|
+ newMessage.append(contentsOf: state.messageList)
|
|
|
}
|
|
|
- if curMessage.count > maxMessageCount {
|
|
|
- curMessage.removeFirst(Int(Double(maxMessageCount) * 0.3))
|
|
|
+ lastmessage = newMessage.last
|
|
|
+
|
|
|
+ var chatMessage: [LNRoomChatMessageItem] = []
|
|
|
+ var systemMessage: [LNRoomSystemMessageItem] = []
|
|
|
+ newMessage.forEach {
|
|
|
+ switch $0.messageType {
|
|
|
+ case .text:
|
|
|
+ if let item = LNRoomChatMessageItem(info: $0) {
|
|
|
+ chatMessage.append(item)
|
|
|
+ }
|
|
|
+ case .custom:
|
|
|
+ if let item = LNRoomSystemMessageItem(info: $0) {
|
|
|
+ systemMessage.append(item)
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ break
|
|
|
+ }
|
|
|
}
|
|
|
- LNEventDeliver.notifyEvent { ($0 as? LNRoomViewModelNotify)?.onRoomMessageChanged() }
|
|
|
+ if !chatMessage.isEmpty {
|
|
|
+ LNEventDeliver.notifyEvent { ($0 as? LNRoomViewModelNotify)?.onRoomMessageChanged(messages: chatMessage) }
|
|
|
+ }
|
|
|
+ handleSystemMessage(messages: systemMessage)
|
|
|
}.store(in: &cancellables)
|
|
|
}
|
|
|
|
|
|
func sendMessage(text: String, handler: @escaping (Bool) -> Void) {
|
|
|
- messageStore.sendTextMessage(text: text, extensionInfo: nil) { result in
|
|
|
+ messageStore.sendTextMessage(text: text, extensionInfo: [
|
|
|
+ LNRoomChatMessageTypeKey: LNRoomChatMessageType.chat.rawValue
|
|
|
+ ]) { result in
|
|
|
switch result {
|
|
|
case .success:
|
|
|
handler(true)
|
|
|
@@ -441,3 +475,35 @@ extension LNRoomViewModel {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+// MARK: 观众事件
|
|
|
+extension LNRoomViewModel {
|
|
|
+ private func setupAudienceEventObservers() {
|
|
|
+ audienceStore.liveAudienceEventPublisher.receive(on: DispatchQueue.main).sink { [weak self] event in
|
|
|
+ guard let self else { return }
|
|
|
+ switch event {
|
|
|
+ case .onAudienceJoined(let info):
|
|
|
+ var welcomeTip = Barrage()
|
|
|
+ welcomeTip.messageType = .text
|
|
|
+ welcomeTip.textContent = "欢迎 \(info.userName) 进入直播间!"
|
|
|
+ welcomeTip.extensionInfo = [LNRoomChatMessageTypeKey: LNRoomChatMessageType.chat.rawValue]
|
|
|
+ messageStore.appendLocalTip(message: welcomeTip)
|
|
|
+ default:
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }.store(in: &cancellables)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension LNRoomViewModel {
|
|
|
+ private func handleSystemMessage(messages: [LNRoomSystemMessageItem]) {
|
|
|
+ systemHandlerQueue.async { [weak self] in
|
|
|
+ guard let self else { return }
|
|
|
+ messages.forEach {
|
|
|
+ if $0.cmd == .MicClear {
|
|
|
+ self.waitingForSeat = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|