331 lines
8.7 KiB
Swift
331 lines
8.7 KiB
Swift
//
|
|
// ChatVC.swift
|
|
// yinmeng-ios
|
|
//
|
|
// Created by MaiMang on 2024/2/25.
|
|
// 回话详情
|
|
|
|
import UIKit
|
|
import NIMSDK
|
|
import TZImagePickerController
|
|
class ChatVC: BaseViewController, HiddenNavigationBarProtocol, TZImagePickerControllerDelegate{
|
|
|
|
// 键盘收起/弹出 滚动的时候收起输入栏
|
|
private var isBecome: Bool = false
|
|
/// 是否发送完成
|
|
private var isSended: Bool = true
|
|
/// 输入栏默认的高度
|
|
private let ToolBarLastH: CGFloat = (52 + SafeAraeBottomHeight)
|
|
|
|
public init(session: NIMSession) {
|
|
vm = ChatViewModel(session: session)
|
|
super.init(nibName: nil, bundle: nil)
|
|
vm.delegate = self
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
var vm:ChatViewModel
|
|
|
|
override var preferredStatusBarStyle: UIStatusBarStyle {
|
|
.darkContent
|
|
}
|
|
|
|
override open func viewWillDisappear(_ animated: Bool) {
|
|
super.viewWillDisappear(animated)
|
|
if NIMSDK.shared().mediaManager.isPlaying() {
|
|
NIMSDK.shared().mediaManager.stopPlay()
|
|
}
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
view.backgroundColor = ThemeColor(hexStr: "#F8F8FB")
|
|
requestInfo()
|
|
loadChatList()
|
|
registerChatCell()
|
|
let height = ScreenHeight - (ToolBarLastH + NavHeight)
|
|
chatTableView.frame = CGRect(x: 0, y: NavHeight, width: ScreenWidth, height: height)
|
|
navView.frame = CGRect(x: 0, y: 0, width: ScreenWidth, height: NavHeight)
|
|
view.addSubview(chatTableView)
|
|
view.addSubview(keyboardView)
|
|
view.addSubview(navView)
|
|
}
|
|
|
|
///注册cell
|
|
private func registerChatCell() {
|
|
chatTableView.register(cellType: ChatTextCell.self)
|
|
chatTableView.register(cellType: ChatTimeCell.self)
|
|
chatTableView.register(cellType: ChatVoiceCell.self)
|
|
chatTableView.register(cellType: ChatImageCell.self)
|
|
}
|
|
|
|
private lazy var chatTableView: UITableView = {
|
|
let tableView = UITableView(frame: .zero, style: .plain)
|
|
tableView.delegate = self
|
|
tableView.dataSource = self
|
|
tableView.tableFooterView = UIView()
|
|
tableView.separatorStyle = .none
|
|
tableView.backgroundColor = .clear
|
|
if #available(iOS 11.0, *) {
|
|
tableView.contentInsetAdjustmentBehavior = .never
|
|
}
|
|
return tableView
|
|
}()
|
|
|
|
private lazy var keyboardView: ChatKeyboardView = {
|
|
let toolBarY = ScreenHeight - ToolBarLastH
|
|
let view = ChatKeyboardView(frame: CGRect(x: 0, y: toolBarY, width: ScreenWidth, height: ToolBarLastH))
|
|
view.backgroundColor = .white
|
|
view.delegate = self
|
|
return view
|
|
}()
|
|
|
|
|
|
private lazy var navView: ChatNavView = {
|
|
let view = ChatNavView(frame: .zero)
|
|
view.backgroundColor = .white
|
|
return view
|
|
}()
|
|
|
|
}
|
|
|
|
// MARK: - ChatKeyboardViewDelegate
|
|
extension ChatVC: ChatKeyboardViewDelegate {
|
|
|
|
func keyboard(_ keyboard: ChatKeyboardView, voiceDidFinish path: String) {
|
|
vm.sendAudioMessage(filePath: path) { error in
|
|
|
|
}
|
|
}
|
|
|
|
func keyboard(_ keyboard: ChatKeyboardView, DidFinish content: String) {
|
|
///发送消息
|
|
vm.sendTextMessage(text: content) { error in
|
|
|
|
}
|
|
}
|
|
|
|
func keyboard(_ keyboard: ChatKeyboardView, DidBecome isBecome: Bool) {
|
|
self.isSended = true
|
|
self.isBecome = isBecome
|
|
}
|
|
|
|
func keyboard(_ keyboard: ChatKeyboardView, DidMoreMenu type: ChatMoreMenuType) {
|
|
if type == .album {
|
|
let imagePicker = TZImagePickerController(maxImagesCount: 1, columnNumber: 5, delegate: self)
|
|
imagePicker?.allowPickingVideo = false
|
|
imagePicker?.modalPresentationStyle = .fullScreen
|
|
imagePicker?.didFinishPickingPhotosHandle = {(images: [UIImage]?, assets:[Any]?, isSelectOriginalPhoto: Bool) in
|
|
if (type == .album) {
|
|
if let image = images?[safe:0] {
|
|
self.vm.sendImageMessage(image: image) { _ in}
|
|
}
|
|
}
|
|
}
|
|
self.navigationController?.present(imagePicker!, animated: true)
|
|
keyboard.hiddenMoreView()
|
|
}
|
|
}
|
|
|
|
func keyboard(_ keyboard: ChatKeyboardView, DidObserver offsetY: CGFloat) {
|
|
|
|
}
|
|
}
|
|
|
|
extension ChatVC {
|
|
|
|
func requestInfo() {
|
|
self.navView.uid = vm.session.sessionId
|
|
let params = ["uid": vm.session.sessionId]
|
|
RequestGet(path: "user/get", parma: params) { data in
|
|
if let info = Deserialized<UserObject>.toModel(with: data) {
|
|
self.navView.name = info.nick
|
|
}
|
|
} fail: { code, msg in
|
|
|
|
}
|
|
|
|
let par:[String : Any] = ["uid": AuthManager.userUid, "isLikeUid": vm.session.sessionId]
|
|
RequestGet(path: "fans/isLike", parma: par) { data in
|
|
if let isLike = data as? Bool {
|
|
self.navView.isLike = isLike
|
|
}
|
|
} fail: { code, msg in
|
|
|
|
}
|
|
}
|
|
|
|
func loadChatList() {
|
|
|
|
weak var weakSelf = self
|
|
vm.queryRoamMsgHasMoreTime_v2 { error, historyEnd, newEnd, models, index in
|
|
if let ms = models, ms.count > 0 {
|
|
weakSelf?.chatTableView.reloadData()
|
|
if weakSelf?.vm.isHistoryAnchorChat == true {
|
|
let indexPath = IndexPath(row: index, section: 0)
|
|
weakSelf?.chatTableView.scrollToRow(at: indexPath, at: .none, animated: false)
|
|
} else {
|
|
if let tempArrayJJom = weakSelf?.vm.messageObjects, tempArrayJJom.count > 0 {
|
|
DispatchQueue.main.async {
|
|
weakSelf?.chatTableView.scrollToRow(
|
|
at: IndexPath(row: tempArrayJJom.count - 1, section: 0),
|
|
at: .bottom,
|
|
animated: false
|
|
)
|
|
}
|
|
}
|
|
}
|
|
} else if let err = error {
|
|
HUDTool.show(with: err.localizedDescription)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private func insertRows() {
|
|
let oldRows = chatTableView.numberOfRows(inSection: 0)
|
|
if oldRows == 0 {
|
|
chatTableView.reloadData()
|
|
return
|
|
}
|
|
if oldRows == vm.messageObjects.count {
|
|
chatTableView.reloadData()
|
|
return
|
|
}
|
|
var indexs = [IndexPath]()
|
|
for (i, _) in vm.messageObjects.enumerated() {
|
|
if i >= oldRows {
|
|
indexs.append(IndexPath(row: i, section: 0))
|
|
}
|
|
}
|
|
|
|
if !indexs.isEmpty {
|
|
chatTableView.insertRows(at: indexs, with: .none)
|
|
chatTableView.scrollToRow(
|
|
at: IndexPath(row: vm.messageObjects.count - 1, section: 0),
|
|
at: .bottom,
|
|
animated: false
|
|
)
|
|
}
|
|
chatTableView.reloadData()
|
|
}
|
|
|
|
public func tableViewDeleteIndexs(_ indexs: [IndexPath]) {
|
|
chatTableView.beginUpdates()
|
|
chatTableView.deleteRows(at: indexs, with: .none)
|
|
chatTableView.endUpdates()
|
|
}
|
|
|
|
public func tableViewReloadIndexs(_ indexs: [IndexPath]) {
|
|
chatTableView.beginUpdates()
|
|
chatTableView.reloadRows(at: indexs, with: .none)
|
|
chatTableView.endUpdates()
|
|
}
|
|
|
|
}
|
|
|
|
extension ChatVC: ChatViewModelDelegate{
|
|
public func onRecvMessages1(_ messages: [NIMMessage]) {
|
|
insertRows()
|
|
vm.markRead(messages: messages) { error in
|
|
|
|
}
|
|
}
|
|
|
|
public func willSend(_ message: NIMMessage) {
|
|
|
|
}
|
|
|
|
public func didAppend(_ message: NIMMessage) {
|
|
|
|
}
|
|
|
|
public func send(_ message: NIMMessage, progress: Float) {}
|
|
|
|
public func send(_ message: NIMMessage, didCompleteWithError error: Error?) {
|
|
if error == nil {
|
|
insertRows()
|
|
}
|
|
}
|
|
|
|
private func indexPathsWithMessags(_ messages: [NIMMessage]) -> [IndexPath] {
|
|
var indexPaths = [IndexPath]()
|
|
for messageModel in messages {
|
|
for (i, model) in vm.messageObjects.enumerated() {
|
|
if model.msg?.messageId == messageModel.messageId {
|
|
indexPaths.append(IndexPath(row: i, section: 0))
|
|
}
|
|
}
|
|
}
|
|
return indexPaths
|
|
}
|
|
|
|
public func onDeleteMessage(_ message: NIMMessage, atIndexs: [IndexPath]) {
|
|
if atIndexs.isEmpty {
|
|
return
|
|
}
|
|
tableViewDeleteIndexs(atIndexs)
|
|
}
|
|
}
|
|
|
|
extension ChatVC: UITableViewDelegate, UITableViewDataSource, UIScrollViewDelegate {
|
|
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
|
return vm.messageObjects.count
|
|
}
|
|
|
|
public func tableView(_ tableView: UITableView,
|
|
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
|
let model = vm.messageObjects[safe: indexPath.row]
|
|
if model?.type == .text {
|
|
let cell = tableView.dequeueReusableCell(for: indexPath, cellType: ChatTextCell.self)
|
|
cell.model = model
|
|
return cell
|
|
} else if model?.type == .time {
|
|
let cell = tableView.dequeueReusableCell(for: indexPath, cellType: ChatTimeCell.self)
|
|
cell.model = model
|
|
return cell
|
|
} else if model?.type == .voice {
|
|
let cell = tableView.dequeueReusableCell(for: indexPath, cellType: ChatVoiceCell.self)
|
|
cell.model = model
|
|
return cell
|
|
} else if model?.type == .image {
|
|
let cell = tableView.dequeueReusableCell(for: indexPath, cellType: ChatImageCell.self)
|
|
cell.model = model
|
|
return cell
|
|
}
|
|
|
|
return UITableViewCell()
|
|
}
|
|
|
|
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
tableView.deselectRow(at: indexPath, animated: true)
|
|
}
|
|
|
|
public func tableView(_ tableView: UITableView,
|
|
heightForRowAt indexPath: IndexPath) -> CGFloat {
|
|
let m = vm.messageObjects[safe:indexPath.row]
|
|
return CGFloat(m?.height ?? 0)
|
|
}
|
|
|
|
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
|
|
if isSended {
|
|
isSended = false
|
|
}
|
|
}
|
|
|
|
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
|
if isSended {
|
|
return
|
|
}
|
|
|
|
if chatTableView.y <= 0 && isBecome {
|
|
DispatchQueue.main.async {
|
|
NotificationCenter.default.post(name: .kChatTextKeyboardNeedHide, object: nil)
|
|
}
|
|
}
|
|
}
|
|
}
|