Visual_Novel_iOS/crush/Crush/Src/Modules/Chat/Session/SessionController.swift

464 lines
14 KiB
Swift
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import NIMSDK
import SnapKit
import TZImagePickerController
import UIKit
import Combine
class SessionController: CLBaseViewController {
var sessionNavigationView: SessionNavigationView!
var bgImageView: UIImageView!
var overlay: GradientView!
var tableView: UITableView!
// var headView: SessionAIHeadView!
// MARK: BottomViews
var bottomViewsStackV : UIStackView!
var inputEntrance: SessionInputOperateView!
var inputBar: SessionInputView!
var moreView: IMMoreItemView!
var giftSendView: GiftGridSendView!
var textSuggestionsView : SessionInputSuggestionsView!
var voiceHoldView: IMVoiceHoldView!
var pureBgOperateView:SessionPureBgOperateView!
// cell
var menuCell: SessionCell?
// IM user info
var aiInfo: IMAIUserInfo?
// -- Layout
var bottomConstraintForInputBar: Constraint?
// -- flag
var firstLoadedUser = false;
var isDisappearing = false//
var dealCancelEditing = false// 退
var kuolieReportMatchedChatOnce = false // v1.6.0 kuolie
var isRequesting = false
var isPullingToAIHomePage = false
// --- view model
lazy var giftVM = GiftViewModel()
/// aiId
var aiId: Int!
/// 439257063882753@r@t
var accountId:String!
/// eg: 439213911113729@u@t|1|439257063882753@r@t
var conversationId: String!
var conversation: V2NIMConversation!
var util: SessionUtil! = SessionUtil()
var cancellables = Set<AnyCancellable>()
convenience init(accountID: String) {
self.init()
accountId = accountID
let array = accountID.components(separatedBy: "@")
if let number = Int(array.first ?? "0"){
aiId = number
}
self.conversationId = V2NIMConversationIdUtil.p2pConversationId(accountID)
if self.conversationId != nil{
conversation = V2NIMConversation()
NIMSDK.shared().v2ConversationService.getConversation(conversationId) {[weak self] conversation in
self?.conversation = conversation
} failure: { error in
dlog("❌get \(String(describing: self.conversationId)) conversation error:\(error)")
}
}else{
dlog("❌p2pConversationId failed")
}
}
convenience init(conversationId: String) {
self.init()
self.conversationId = conversationId
conversation = V2NIMConversation()
let stings = conversationId.components(separatedBy: "|")
guard let last = stings.last else{return}
accountId = last
let strings2 = last.components(separatedBy:"@")
if let userIdStr = strings2.first {
if let userid = Int(userIdStr) {
aiId = userid
}
}
NIMSDK.shared().v2ConversationService.getConversation(conversationId) {[weak self] conversation in
self?.conversation = conversation
} failure: { error in
dlog("❌get \(String(describing: self.conversationId)) conversation error:\(error)")
}
}
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
setupData()
setupEvent()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
(navigationController as? CLNavigationController)?.disabledFullScreenPan()
IMAIViewModel.shared.updateAI(aiInfo)
IMManager.shared.addCache(sessionID: conversationId)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
isDisappearing = false
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
isDisappearing = true
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
isDisappearing = false
(navigationController as? CLNavigationController)?.enabledFullScreenPan()
cancelEditing()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// tableViewcontentInset
adjustTableViewContentInset()
}
deinit {
IMManager.shared.deleteCache(sessionID: conversationId)
IMManager.shared.clearUnreadCountBy(ids: [conversationId])
}
}
// MARK: - Views
extension SessionController {
func setupUI() {
view.clipsToBounds = true
navigationView.backgroundColor = .clear
sessionNavigationView = {
let v = SessionNavigationView()
view.addSubview(v)
v.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview()
}
return v
}()
bgImageView = {
let v = UIImageView()
v.contentMode = .scaleAspectFill
view.addSubview(v)
v.snp.makeConstraints { make in
make.leading.trailing.equalToSuperview()
make.top.equalToSuperview()
make.bottom.equalToSuperview() //
}
return v
}()
// bgImageView.image = UIImage(named: "egpic")?.cropImageTop(with: 1 / UIScreen.aspectRatio)
overlay = {
let v = GradientView(colors: [UIColor.c.cbn.withAlphaComponent(1), UIColor.c.cbn.withAlphaComponent(0), UIColor.c.cbn.withAlphaComponent(0), UIColor.c.cbn.withAlphaComponent(1)], gradientType: .topToBottom)
v.imBgOverlayMode = true
view.addSubview(v)
v.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
return v
}()
setupInputView()
setupTableView()
view.bringSubviewToFront(sessionNavigationView)
view.bringSubviewToFront(bottomViewsStackV)
}
func setupUserInfo() {
let imUserInfo = IMUserKit.imUserKitWith(accId: accountId) {[weak self] kit in
if self?.conversation.conversationId == kit?.accountId{
self?.navigationView.titleLabel.text = kit?.nickname
}
}
if let userId = imUserInfo.userId, userId > 0 {
// titleView.titleLabel.text = kitInfo.showName
Hud.showIndicator()
requestUserInfo(userId: userId)
} else if aiId > 0 {
Hud.showIndicator()
requestUserInfo(userId: aiId)
}else{
assert(false)
}
}
func reloadViews() {
guard let user = aiInfo else {
return
}
bgImageView.loadImage(user.backgroundImg, completionBlock: {[weak self] result in
switch result {
case let .success(imageResult):
let image = imageResult.image
self?.bgImageView.snp.makeConstraints { make in
make.width.equalTo((self?.bgImageView.snp.height)!).multipliedBy(image.size.width / image.size.height)
}
//self?.bgImageView.image = image.cropImageTop(with: 1/UIScreen.aspectRatio)
case .failure:
return
}
})
sessionNavigationView.config(user: user)
tableView.reloadData()
// UserInfo
}
}
// MARK: Datas & Events
extension SessionController {
func setupData() {
setupNIM()
util.conversationId = conversationId
setupUserInfo()
WalletCore.shared.refreshWallet()
//
markReadAll()
}
}
// MARK: - Noti
extension SessionController {
@objc func keyboardWillChanged(noti: Notification) {
// guard tableView.window != nil else {
// return
// }
if isDisappearing || isDisplaying == false {
return
}
guard let userInfo = noti.userInfo else { return }
//
let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as! TimeInterval
let curve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey]! as! Int
let beginFrame = (userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let endFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
var hideKeyboardFlag = false
var showKeyboardFlag = false
// dlog("duration:\(duration)")
if beginFrame.origin.y < UIScreen.height, endFrame.origin.y >= UIScreen.height {
//
hideKeyboardFlag = true
//dlog("close keyboard")
} else if beginFrame.origin.y >= UIScreen.height, endFrame.origin.y < UIScreen.height {
//
showKeyboardFlag = true
//dlog("show keyboard")
} else if beginFrame.size.height != endFrame.size.height {
//
//dlog("height of keyboard changed")
}
if hideKeyboardFlag{ //
self.doHideKeyBordActions()
}else if showKeyboardFlag{ //
self.doKeyboardShowActions()
let offsetY = UIScreen.height - endFrame.origin.y// - UIWindow.safeAreaBottom
self.updateInputEntrance(offsetY: offsetY, duration: duration, curve: curve)
}
else if !self.dealCancelEditing {
let offsetY = UIScreen.height - endFrame.origin.y// - UIWindow.safeAreaBottom
self.updateInputEntrance(offsetY: offsetY, duration: duration, curve: curve)
}
UIView.animate(withDuration: duration,
delay: 0,
options: UIView.AnimationOptions(rawValue: UInt(curve) << 16),
animations: {
self.view.layoutIfNeeded()
self.scrollToBottom(self.tableView, animated: true)
})
}
@objc func menuHide(noti: Notification) {
guard let menu = noti.object as? UIMenuController else { return }
guard let menuItems = menu.menuItems else { return }
guard let first = menuItems.first else { return }
if first.action == Selector(("copyAction")) {
UIMenuController.shared.menuItems = nil
} else {
}
}
@objc func notifyChatSettingUpdated(){
requestUserInfo(userId: aiId)
}
@objc func notifiyRelationHiddenUpdate(){
requestUserInfo(userId: aiId)
}
@objc func notifiyRelationInfoUpdate(){
requestUserInfo(userId: aiId)
}
}
// MARK: - Action
// BottomViews
extension SessionController {
@objc func titleTapAction() {
guard let user = aiInfo, let aiId = user.aiId else { return }
AppRouter.goAIRoleHome(aiId: aiId)
}
/// 退
@objc func cancelEditing() {
dealCancelEditing = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.dealCancelEditing = false
}
if inputBar.textView.isFirstResponder{
view.endEditing(true)
}else{
hideOperateView()
}
}
func doKeyboardShowActions(){
self.inputBar.isHidden = false
self.inputEntrance.isHidden = true
// self.moreView.isHidden = true
//showMoreItems(show: false)
}
@objc func doHideKeyBordActions() {
// showHeaderView(show: true, duration: 0.3)
UIView.animate(withDuration: 0.1) {
self.inputBar.alpha = 0
self.inputBar.layoutIfNeeded()
} completion: { finished in
self.inputBar.isHidden = true
self.inputBar.alpha = 1
}
// self.inputEntrance.isHidden = false
// self.bottomViewsStackV.setNeedsDisplay()
// self.bottomViewsStackV.layoutIfNeeded()
// showMoreItems(show: false)
hideAllBottomViews(except: [inputEntrance])
updateInputEntrance(offsetY: 0, duration: 0, curve: UIView.AnimationCurve.easeOut.rawValue) // 0.3
}
}
// MARK: - Session Audio Phone call delegaet.
//
// extension SessionController: SessionHeadPhoneCallGuideDelegate {
// func headPhoneCallGuideTapCall() {
// guard AudioRecordTool.audioAuth() else {
// return
// }
//
// guard AudioPlayTool.audioChannelFreeToUse(), PhoneManager.isInPhoneChannel() == false else {
// return
// }
//
// hideCallGuide()
// phoneCallHandler.onSelectVoice(user: userInfo, session: session)
// }
// }
// MARK: - Animation
extension SessionController {
// func showMoreItem(show: Bool) {
// if show {
// UIView.animate(withDuration: 0.3) {
// self.moreView.alpha = 1
// self.moreView.snp.updateConstraints { make in
// make.top.equalTo(self.inputBar.snp.bottom).offset(-UIWindow.safeAreaBottom)
// }
// self.view.layoutIfNeeded()
// } completion: { _ in
// }
// } else {
// UIView.animate(withDuration: 0.3) {
// self.moreView.alpha = 0
// self.moreView.snp.updateConstraints { make in
// make.top.equalTo(self.inputBar.snp.bottom).offset(10)
// }
// self.view.layoutIfNeeded()
// } completion: { _ in
// }
// }
// }
func updateInputEntrance(offsetY: CGFloat, duration: TimeInterval, curve: Int) {
let offsetY = offsetY > 0 ? offsetY : (UIWindow.safeAreaBottom)
self.bottomViewsStackV.snp.updateConstraints { make in
make.bottom.equalTo(self.view).offset(-offsetY)
}
// self.bottomViewsStackV.setNeedsDisplay()
// self.bottomViewsStackV.layoutIfNeeded()
//
// // tableViewcontentInset
// DispatchQueue.main.async { [weak self] in
// self?.adjustTableViewContentInset()
// }
}
func updateTableContentOffset(duration: TimeInterval){
UIView.animate(withDuration: duration) {
self.updateTableViewContentLayout()
self.view.layoutIfNeeded()
}
}
}