jsdw_ios/QuickLocation/Section/Group/GroupViewController.swift

329 lines
12 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

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.

//
// GroupViewController.swift
// QuickLocation
//
import UIKit
import RxSwift
import RxCocoa
import RxDataSources
import SDCycleScrollView
import OpenIMSDK
import ObjectMapper
final class GroupViewController: BaseViewController {
override var isNavigationBarHidden: Bool { true }
fileprivate var rootView: GroupView!
private let viewModel = GroupViewModel()
///
private var itineraryGroupModel: GroupModel?
private var itinerarySchedules: [ScheduleModel] = []
override func loadView() {
rootView = GroupView(frame: UIScreen.main.bounds)
view = rootView
}
override func viewDidLoad() {
super.viewDidLoad()
bindViewModel()
reactiveAction()
observeTableViews()
bindItineraryPage()
requestRecommandGroup()
requestGroupInfo()
guard let config = AppContextManager.shared.systemConfig else { return }
rootView.cycleScrollView.imageURLStringsGroup = config.groupBannerList
}
// MARK: - OpenIM
private var hasSetupIMListeners = false
/// IM +
private func loadIMData() {
GroupIMService.shared.ensureLogin { [weak self] success in
guard let self = self else { return }
guard success else {
return
}
self.setupIMListenersIfNeeded()
self.refreshIMData()
}
}
/// IM /SDK /退
private func setupIMListenersIfNeeded() {
guard !hasSetupIMListeners else { return }
hasSetupIMListeners = true
// 使 MJExtension
GroupIMService.shared.setConversationListener { [weak self] conversations in
self?.viewModel.updateConversations(conversations)
}
// /SDK
GroupIMService.shared.setGroupListener { [weak self] in
GroupIMService.shared.getJoinedGroups { groups in
self?.viewModel.loadIMGroups(groups)
}
}
}
private func refreshIMData() {
let group = DispatchGroup()
var groups: [OIMGroupInfo] = []
var conversations: [OIMConversationInfo] = []
group.enter()
GroupIMService.shared.getJoinedGroups { g in
groups = g
group.leave()
}
group.enter()
GroupIMService.shared.getConversationList { c in
conversations = c
group.leave()
}
group.notify(queue: .main) { [weak self] in
DLToast.dismiss()
self?.viewModel.loadIMGroups(groups, conversations: conversations)
}
}
// MARK: - Bindings
private func bindViewModel() {
viewModel.output.hotGroups
.observe(on: MainScheduler.asyncInstance)
.bind(to: rootView.hotGroupsCollectionView.rx.items(dataSource: hotGroupDataSource))
.disposed(by: disposeBag)
viewModel.output.createdSections
.observe(on: MainScheduler.asyncInstance)
.bind(to: rootView.createdTableView.rx.items(dataSource: createdDataSource))
.disposed(by: disposeBag)
viewModel.output.joinedSections
.observe(on: MainScheduler.asyncInstance)
.bind(to: rootView.joinedTableView.rx.items(dataSource: joinedDataSource))
.disposed(by: disposeBag)
rootView.hotGroupsCollectionView.rx.modelSelected(GroupInfoModel.self)
.subscribe(viewModel.hotGroupCellAction.inputs)
.disposed(by: disposeBag)
}
private func reactiveAction() {
rootView.createGroupBtn.rx.tapGesture
.subscribe(onNext: { _ in
AppRouter.push(Route.createGroup)
})
.disposed(by: disposeBag)
rootView.joinGroupBtn.rx.tapGesture
.subscribe(onNext: { _ in
AppRouter.push(Route.joinGroup)
})
.disposed(by: disposeBag)
// Tab(0=joined) / (1=created)
rootView.joinedTabLabel.rx.tapGesture
.subscribe(onNext: { [weak self] _ in self?.switchToSegment(0) })
.disposed(by: disposeBag)
rootView.createdTabLabel.rx.tapGesture
.subscribe(onNext: { [weak self] _ in self?.switchToSegment(1) })
.disposed(by: disposeBag)
// /
rootView.circleTabLabel.rx.tapGesture
.subscribe(onNext: { [weak self] _ in
self?.rootView.selectTopTab(at: 0)
})
.disposed(by: disposeBag)
rootView.itineraryTabLabel.rx.tapGesture
.subscribe(onNext: { [weak self] _ in
guard let self = self else { return }
self.rootView.selectTopTab(at: 1)
self.refreshItineraryPage()
})
.disposed(by: disposeBag)
Observable.merge(
rootView.createdTableView.rx.modelSelected(GroupCellData.self).asObservable(),
rootView.joinedTableView.rx.modelSelected(GroupCellData.self).asObservable()
)
.subscribe(onNext: { data in
guard let groupId = data.groupInfo.groupID else { return }
AppRouter.push(Route.groupChat, userInfo: ["groupId": groupId])
})
.disposed(by: disposeBag)
// MQTT join/leave/dismiss
NotificationCenter.default.rx.notification(.RefreshIMGroupListNotification)
.subscribe(onNext: { [weak self] _ in
self?.requestGroupInfo()
})
.disposed(by: disposeBag)
NotificationCenter.default.rx.notification(.RefreshUserConfigNotification)
.subscribe(onNext: { [weak self] _ in
self?.requestRecommandGroup()
self?.requestGroupInfo()
guard let config = AppContextManager.shared.systemConfig else { return }
self?.rootView.cycleScrollView.imageURLStringsGroup = config.groupBannerList
})
.disposed(by: disposeBag)
}
private func bindItineraryPage() {
let page = rootView.itineraryPage
page.onSwitchGroup = { [weak self] in
self?.showSwitchGroupPop()
}
page.onSelectSchedule = { model in
AppRouter.push(Route.scheduleDetail, userInfo: ["scheduleJson": model.toJSON()])
}
page.onDeleteSchedule = { [weak self] model in
self?.deleteSchedule(model)
}
}
private func switchToSegment(_ index: Int) {
rootView.selectSegment(at: index)
let offset = CGPoint(x: CGFloat(index) * rootView.segmentScrollView.bounds.width, y: 0)
rootView.segmentScrollView.setContentOffset(offset, animated: false)
}
// MARK: -
private func refreshItineraryPage() {
GroupService.groupInfo().subscribe(onNext: { [weak self] response in
guard let self = self, let model = response.model else { return }
self.itineraryGroupModel = model
let current = model.groups.first(where: { $0.group_key == model.default_group_key })
self.rootView.itineraryPage.updateGroupName(current?.name ?? "")
self.rootView.itineraryPage.reloadMembers(
model.select_group_employee,
selectedId: AppContextManager.shared.userId,
groupKey: model.default_group_key
)
self.requestItinerarySchedules(groupKey: model.default_group_key)
}).disposed(by: disposeBag)
}
private func requestItinerarySchedules(groupKey: String) {
guard !groupKey.isEmpty else {
itinerarySchedules = []
rootView.itineraryPage.reloadSchedules([])
return
}
ItineraryService.groupScheduleList(groupKey: groupKey)
.subscribe(onNext: { [weak self] response in
guard let self = self else { return }
self.itinerarySchedules = response.list
self.rootView.itineraryPage.reloadSchedules(response.list)
})
.disposed(by: disposeBag)
}
private func showSwitchGroupPop() {
guard let groupModel = itineraryGroupModel else {
refreshItineraryPage()
return
}
GroupListPopView.show(groupModel: groupModel) { [weak self] groupKey in
guard let self = self, let key = groupKey else { return }
GroupService.operate(opType: "setdefault", requestData: ["group_key": key])
.subscribe(onNext: { [weak self] _ in
self?.refreshItineraryPage()
NotificationCenter.default.post(name: .RefreshGroupInfoNotification, object: nil)
})
.disposed(by: self.disposeBag)
}
}
private func deleteSchedule(_ model: ScheduleModel) {
guard !model.id.isEmpty else { return }
DLToast.showLoading()
ItineraryService.delete(id: model.id)
.subscribe(onNext: { [weak self] _ in
DLToast.dismiss()
guard let self = self else { return }
self.itinerarySchedules.removeAll { $0.id == model.id }
self.rootView.itineraryPage.reloadSchedules(self.itinerarySchedules)
}, onError: { _ in
DLToast.dismiss()
})
.disposed(by: disposeBag)
}
// MARK: - tableView
private func observeTableViews() {
rootView.createdTableView.rx.didScroll
.observe(on: MainScheduler.asyncInstance)
.subscribe(onNext: { [weak self] in
guard let self = self else { return }
self.rootView.handleTableViewScroll(self.rootView.createdTableView)
})
.disposed(by: disposeBag)
rootView.joinedTableView.rx.didScroll
.observe(on: MainScheduler.asyncInstance)
.subscribe(onNext: { [weak self] in
guard let self = self else { return }
self.rootView.handleTableViewScroll(self.rootView.joinedTableView)
})
.disposed(by: disposeBag)
}
// MARK: - dataSource
private lazy var hotGroupDataSource: RxCollectionViewSectionedReloadDataSource<HotGroupListSectionModel> = {
RxCollectionViewSectionedReloadDataSource<HotGroupListSectionModel> { datasource, collectionView, indexPath, model in
let cell: HotGroupCell = collectionView.dequeueReusableCell(for: indexPath)
cell.configure(model)
return cell
}
}()
private lazy var createdDataSource: RxTableViewSectionedReloadDataSource<CircleListSectionModel> = {
RxTableViewSectionedReloadDataSource<CircleListSectionModel> { _, tableView, indexPath, model in
let cell: CircleGroupCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(model)
return cell
}
}()
private lazy var joinedDataSource: RxTableViewSectionedReloadDataSource<CircleListSectionModel> = {
RxTableViewSectionedReloadDataSource<CircleListSectionModel> { _, tableView, indexPath, model in
let cell: CircleGroupCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(model)
return cell
}
}()
// MARK: - API
private func requestRecommandGroup() {
GroupService.recommand(count: 5).subscribe(onNext: { response in
self.viewModel.loadHotGroupData(response.list)
}).disposed(by: disposeBag)
}
private func requestGroupInfo() {
GroupService.groupInfo().subscribe { response in
guard let model = response.model else { return }
self.viewModel.groupList = model.groups
DispatchQueue.global(qos: .default).async { [weak self] in
self?.loadIMData()
}
}.disposed(by: disposeBag)
}
}