mirror of
https://github.com/Finb/Bark.git
synced 2025-12-08 21:36:01 +00:00
添加群组cell
This commit is contained in:
parent
612cadafec
commit
3f8e7ef150
@ -103,7 +103,7 @@
|
||||
0672CB06256903F700570C9D /* MessageListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0672CB05256903F700570C9D /* MessageListViewModel.swift */; };
|
||||
06787C392A710568008ABDD7 /* GesturePassTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06787C382A710568008ABDD7 /* GesturePassTextView.swift */; };
|
||||
06787C3B2AB82BDB008ABDD7 /* CrashReportViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06787C3A2AB82BDB008ABDD7 /* CrashReportViewController.swift */; };
|
||||
067B2EB525693E38008B6BE1 /* MessageTableViewCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 067B2EB425693E38008B6BE1 /* MessageTableViewCellViewModel.swift */; };
|
||||
067B2EB525693E38008B6BE1 /* MessageSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 067B2EB425693E38008B6BE1 /* MessageSection.swift */; };
|
||||
06802E5320ECC40C00767047 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0661A549204FDA4100965E4E /* Assets.xcassets */; };
|
||||
06840DBB272298FB001B3193 /* BKColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06840DBA272298FB001B3193 /* BKColor.swift */; };
|
||||
0687F2A82CCB791A00B2A52F /* UIFont+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0687F2A72CCB791A00B2A52F /* UIFont+Extension.swift */; };
|
||||
@ -344,7 +344,7 @@
|
||||
0672CB05256903F700570C9D /* MessageListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageListViewModel.swift; sourceTree = "<group>"; };
|
||||
06787C382A710568008ABDD7 /* GesturePassTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GesturePassTextView.swift; sourceTree = "<group>"; };
|
||||
06787C3A2AB82BDB008ABDD7 /* CrashReportViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReportViewController.swift; sourceTree = "<group>"; };
|
||||
067B2EB425693E38008B6BE1 /* MessageTableViewCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageTableViewCellViewModel.swift; sourceTree = "<group>"; };
|
||||
067B2EB425693E38008B6BE1 /* MessageSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSection.swift; sourceTree = "<group>"; };
|
||||
0683486A2050F1310024B6DA /* Bark.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Bark.entitlements; sourceTree = "<group>"; };
|
||||
0683487020510FB20024B6DA /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; };
|
||||
0683487220510FB20024B6DA /* UserNotificationsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotificationsUI.framework; path = System/Library/Frameworks/UserNotificationsUI.framework; sourceTree = SDKROOT; };
|
||||
@ -535,6 +535,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
06B1158E247BB1FB006D91FB /* Message.swift */,
|
||||
067B2EB425693E38008B6BE1 /* MessageSection.swift */,
|
||||
064CABA5256BE9510018155C /* PreviewModel.swift */,
|
||||
06BD4DA92901352E003364DB /* Object+Dictionary.swift */,
|
||||
061894C629A75BEA00E001C2 /* Algorithm.swift */,
|
||||
@ -679,7 +680,6 @@
|
||||
children = (
|
||||
066890072D1946D500E106F2 /* MessageItemView.swift */,
|
||||
0667D191247D162C005DE2ED /* MessageTableViewCell.swift */,
|
||||
067B2EB425693E38008B6BE1 /* MessageTableViewCellViewModel.swift */,
|
||||
0668900A2D19525400E106F2 /* ShowLessAndClearView.swift */,
|
||||
0668900C2D19582400E106F2 /* MessageGroupHeaderView.swift */,
|
||||
061C17072D1BDA4B00891D66 /* MessageGroupMoreView.swift */,
|
||||
@ -1266,7 +1266,7 @@
|
||||
06AE311E266F54CC00B39FBB /* GroupCellViewModel.swift in Sources */,
|
||||
0637FA8620E0AB6600E80174 /* UIColor+Extension.swift in Sources */,
|
||||
0637FA8A20E0D58800E80174 /* NewServerViewController.swift in Sources */,
|
||||
067B2EB525693E38008B6BE1 /* MessageTableViewCellViewModel.swift in Sources */,
|
||||
067B2EB525693E38008B6BE1 /* MessageSection.swift in Sources */,
|
||||
0637FA8220E09C4B00E80174 /* BarkNavigationController.swift in Sources */,
|
||||
06AE3118266F4E2E00B39FBB /* GroupFilterViewController.swift in Sources */,
|
||||
0637FA7A20E092B300E80174 /* Observable+Extension.swift in Sources */,
|
||||
|
||||
@ -45,11 +45,12 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
|
||||
return UIBarButtonItem(customView: btn)
|
||||
}()
|
||||
|
||||
let tableView: UITableView = {
|
||||
lazy var tableView: UITableView = {
|
||||
let tableView = UITableView()
|
||||
tableView.separatorStyle = .none
|
||||
tableView.backgroundColor = BKColor.background.primary
|
||||
tableView.register(MessageTableViewCell.self, forCellReuseIdentifier: "\(MessageTableViewCell.self)")
|
||||
tableView.register(MessageGroupTableViewCell.self, forCellReuseIdentifier: "\(MessageGroupTableViewCell.self)")
|
||||
// 设置了这个后,第一次进页面 LargeTitle 就会收缩成小标题,不设置这个LargeTitle就是大标题显示
|
||||
// 谁特么能整的明白这个?
|
||||
// tableView.contentInset = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0)
|
||||
@ -57,6 +58,10 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
|
||||
// 替代 contentInset 设置一个 header
|
||||
tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 20))
|
||||
|
||||
tableView.rx.setDelegate(self).disposed(by: rx.disposeBag)
|
||||
tableView.mj_footer = MJRefreshAutoFooter()
|
||||
tableView.refreshControl = UIRefreshControl()
|
||||
|
||||
return tableView
|
||||
}()
|
||||
|
||||
@ -71,9 +76,6 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
|
||||
tableView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
tableView.rx.setDelegate(self).disposed(by: rx.disposeBag)
|
||||
tableView.mj_footer = MJRefreshAutoFooter()
|
||||
tableView.refreshControl = UIRefreshControl()
|
||||
|
||||
// 点击tab按钮,回到顶部
|
||||
Client.shared.currentTabBarController?
|
||||
@ -99,12 +101,108 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
|
||||
self?.tableView.refreshControl?.sendActions(for: .valueChanged)
|
||||
}).disposed(by: rx.disposeBag)
|
||||
}
|
||||
|
||||
// tableView 数据源
|
||||
private lazy var dataSource = RxTableViewSectionedAnimatedDataSource<MessageSection>(
|
||||
animationConfiguration: AnimationConfiguration(
|
||||
insertAnimation: .none,
|
||||
reloadAnimation: .none,
|
||||
deleteAnimation: .left
|
||||
),
|
||||
configureCell: { _, tableView, _, item -> UITableViewCell in
|
||||
|
||||
switch item {
|
||||
case .message(let message):
|
||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "\(MessageTableViewCell.self)") as? MessageTableViewCell else {
|
||||
return UITableViewCell()
|
||||
}
|
||||
cell.message = message
|
||||
return cell
|
||||
case .messageGroup(let title, let totalCount, let messages):
|
||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "\(MessageGroupTableViewCell.self)") as? MessageGroupTableViewCell else {
|
||||
return UITableViewCell()
|
||||
}
|
||||
cell.showLessAction = { [weak self, weak cell] in
|
||||
guard let self else { return }
|
||||
UIView.animate(withDuration: 0.6, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.2) {
|
||||
self.tableView.performBatchUpdates {
|
||||
cell?.isExpanded = false
|
||||
}
|
||||
}
|
||||
}
|
||||
cell.messages = messages
|
||||
cell.groupName = title
|
||||
cell.moreCount = max(0, totalCount - messages.count)
|
||||
return cell
|
||||
}
|
||||
|
||||
}, canEditRowAtIndexPath: { _, _ in
|
||||
true
|
||||
}
|
||||
)
|
||||
|
||||
override func bindViewModel() {
|
||||
guard let deleteBtn = deleteButton.customView as? BKButton else {
|
||||
guard let groupBtn = groupButton.customView as? BKButton else {
|
||||
return
|
||||
}
|
||||
let batchDelete = deleteBtn.rx
|
||||
|
||||
let itemSelected = tableView.rx.itemSelected.asDriver().compactMap { [weak self] indexPath -> Int? in
|
||||
guard let self else { return nil }
|
||||
if let cell = self.tableView.cellForRow(at: indexPath) as? MessageGroupTableViewCell {
|
||||
if !cell.isExpanded {
|
||||
UIView.animate(withDuration: 0.6, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.2) {
|
||||
self.tableView.performBatchUpdates {
|
||||
cell.isExpanded = true
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return indexPath.row
|
||||
}
|
||||
|
||||
let output = viewModel.transform(
|
||||
input: MessageListViewModel.Input(
|
||||
refresh: tableView.refreshControl!.rx.controlEvent(.valueChanged).asDriver(),
|
||||
loadMore: tableView.mj_footer!.rx.refresh.asDriver(),
|
||||
itemDelete: tableView.rx.itemDeleted.asDriver().map { $0.row },
|
||||
itemSelected: itemSelected,
|
||||
delete: getBatchDeleteDriver(),
|
||||
groupTap: groupBtn.rx.tap.asDriver(),
|
||||
searchText: navigationItem.searchController!.searchBar.rx.text.asObservable()
|
||||
))
|
||||
|
||||
// tableView 刷新状态
|
||||
output.refreshAction
|
||||
.drive(tableView.rx.refreshAction)
|
||||
.disposed(by: rx.disposeBag)
|
||||
|
||||
output.messages
|
||||
.drive(tableView.rx.items(dataSource: dataSource))
|
||||
.disposed(by: rx.disposeBag)
|
||||
|
||||
// message操作alert
|
||||
output.alertMessage.drive(onNext: { [weak self] message in
|
||||
self?.alertMessage(message: message.0, indexPath: IndexPath(row: message.1, section: 0))
|
||||
}).disposed(by: rx.disposeBag)
|
||||
|
||||
// 选择群组
|
||||
output.groupFilter
|
||||
.drive(onNext: { [weak self] groupModel in
|
||||
self?.navigationController?.present(BarkNavigationController(rootViewController: GroupFilterViewController(viewModel: groupModel)), animated: true, completion: nil)
|
||||
}).disposed(by: rx.disposeBag)
|
||||
|
||||
// 标题
|
||||
output.title
|
||||
.drive(self.navigationItem.rx.title).disposed(by: rx.disposeBag)
|
||||
}
|
||||
|
||||
private func getBatchDeleteDriver() -> Driver<MessageDeleteType> {
|
||||
guard let deleteBtn = deleteButton.customView as? BKButton else {
|
||||
return Driver.never()
|
||||
}
|
||||
return deleteBtn.rx
|
||||
.tap
|
||||
.flatMapLatest { _ -> PublishRelay<MessageDeleteType> in
|
||||
let relay = PublishRelay<MessageDeleteType>()
|
||||
@ -144,66 +242,10 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
|
||||
|
||||
return relay
|
||||
}
|
||||
|
||||
guard let groupBtn = groupButton.customView as? BKButton else {
|
||||
return
|
||||
}
|
||||
|
||||
let output = viewModel.transform(
|
||||
input: MessageListViewModel.Input(
|
||||
refresh: tableView.refreshControl!.rx.controlEvent(.valueChanged).asDriver(),
|
||||
loadMore: tableView.mj_footer!.rx.refresh.asDriver(),
|
||||
itemDelete: tableView.rx.itemDeleted.asDriver().map { $0.row },
|
||||
itemSelected: tableView.rx.itemSelected.asDriver().map { $0.row },
|
||||
delete: batchDelete.asDriver(onErrorDriveWith: .empty()),
|
||||
groupTap: groupBtn.rx.tap.asDriver(),
|
||||
searchText: navigationItem.searchController!.searchBar.rx.text.asObservable()
|
||||
))
|
||||
|
||||
// tableView 刷新状态
|
||||
output.refreshAction
|
||||
.drive(tableView.rx.refreshAction)
|
||||
.disposed(by: rx.disposeBag)
|
||||
|
||||
// tableView 数据源
|
||||
let dataSource = RxTableViewSectionedAnimatedDataSource<MessageSection>(
|
||||
animationConfiguration: AnimationConfiguration(
|
||||
insertAnimation: .none,
|
||||
reloadAnimation: .none,
|
||||
deleteAnimation: .left
|
||||
),
|
||||
configureCell: { _, tableView, _, item -> UITableViewCell in
|
||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "\(MessageTableViewCell.self)") as? MessageTableViewCell else {
|
||||
return UITableViewCell()
|
||||
}
|
||||
cell.message = item.message
|
||||
return cell
|
||||
}, canEditRowAtIndexPath: { _, _ in
|
||||
true
|
||||
}
|
||||
)
|
||||
|
||||
output.messages
|
||||
.drive(tableView.rx.items(dataSource: dataSource))
|
||||
.disposed(by: rx.disposeBag)
|
||||
|
||||
// message操作alert
|
||||
output.alertMessage.drive(onNext: { [weak self] message in
|
||||
self?.alertMessage(message: message.0, indexPath: IndexPath(row: message.1, section: 0))
|
||||
}).disposed(by: rx.disposeBag)
|
||||
|
||||
// 选择群组
|
||||
output.groupFilter
|
||||
.drive(onNext: { [weak self] groupModel in
|
||||
self?.navigationController?.present(BarkNavigationController(rootViewController: GroupFilterViewController(viewModel: groupModel)), animated: true, completion: nil)
|
||||
}).disposed(by: rx.disposeBag)
|
||||
|
||||
// 标题
|
||||
output.title
|
||||
.drive(self.navigationItem.rx.title).disposed(by: rx.disposeBag)
|
||||
.asDriver(onErrorDriveWith: .empty())
|
||||
}
|
||||
|
||||
func alertMessage(message: String, indexPath: IndexPath) {
|
||||
private func alertMessage(message: String, indexPath: IndexPath) {
|
||||
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||
let copyAction = UIAlertAction(title: NSLocalizedString("CopyAll"), style: .default, handler: { [weak self]
|
||||
(_: UIAlertAction) in
|
||||
|
||||
@ -12,13 +12,6 @@ import RxCocoa
|
||||
import RxDataSources
|
||||
import RxSwift
|
||||
|
||||
enum MessageListCellItem {
|
||||
/// 单条消息
|
||||
case message(model: Message)
|
||||
/// 一组消息,可以收缩折叠
|
||||
case messageGroup(group: [Message])
|
||||
}
|
||||
|
||||
class MessageListViewModel: ViewModel, ViewModelType {
|
||||
struct Input {
|
||||
var refresh: Driver<Void>
|
||||
@ -67,7 +60,10 @@ class MessageListViewModel: ViewModel, ViewModelType {
|
||||
}
|
||||
var messages: [Message] = []
|
||||
for i in startIndex..<endIndex {
|
||||
messages.append(result[i])
|
||||
// messages.append(result[i].freeze())
|
||||
// 不用 freeze 是还没弄明白 freeze 冻结快照释放时机,先直接copy吧
|
||||
// copy 是因为 message 可能在被删除后,还会被访问导致闪退
|
||||
messages.append(result[i].copyMessage())
|
||||
}
|
||||
page += 1
|
||||
return messages
|
||||
@ -81,7 +77,6 @@ class MessageListViewModel: ViewModel, ViewModelType {
|
||||
return ("", 0)
|
||||
}
|
||||
let message = results[index]
|
||||
// let message = model.message
|
||||
|
||||
var copyContent: String = ""
|
||||
if let title = message.title {
|
||||
@ -113,10 +108,8 @@ class MessageListViewModel: ViewModel, ViewModelType {
|
||||
|
||||
// Message 转 MessageSection
|
||||
func messagesToMessageSection(messages: [Message]) -> [MessageSection] {
|
||||
let cellViewModels = messages.map { message -> MessageTableViewCellViewModel in
|
||||
MessageTableViewCellViewModel(message: message)
|
||||
}
|
||||
return [MessageSection(header: "model", messages: cellViewModels)]
|
||||
let items = messages.map { MessageListCellItem.message(model: $0) }
|
||||
return [MessageSection(header: "model", messages: items)]
|
||||
}
|
||||
// 切换分组时,更新分组名
|
||||
filterGroups
|
||||
@ -161,16 +154,14 @@ class MessageListViewModel: ViewModel, ViewModelType {
|
||||
.subscribe(onNext: { [weak self] in
|
||||
guard let strongSelf = self else { return }
|
||||
let messages = strongSelf.getNextPage()
|
||||
let cellViewModels = messages.map { message -> MessageTableViewCellViewModel in
|
||||
MessageTableViewCellViewModel(message: message)
|
||||
}
|
||||
let items = messages.map { MessageListCellItem.message(model: $0) }
|
||||
|
||||
refreshAction.accept(.endLoadmore)
|
||||
if var section = messagesRelay.value.first {
|
||||
section.messages.append(contentsOf: cellViewModels)
|
||||
section.messages.append(contentsOf: items)
|
||||
messagesRelay.accept([section])
|
||||
} else {
|
||||
messagesRelay.accept([MessageSection(header: "model", messages: cellViewModels)])
|
||||
messagesRelay.accept([MessageSection(header: "model", messages: items)])
|
||||
}
|
||||
}).disposed(by: rx.disposeBag)
|
||||
|
||||
|
||||
@ -6,9 +6,9 @@
|
||||
// Copyright © 2020 Fin. All rights reserved.
|
||||
//
|
||||
|
||||
//import IceCream
|
||||
import RealmSwift
|
||||
import UIKit
|
||||
|
||||
class Message: Object {
|
||||
@objc dynamic var id = NSUUID().uuidString
|
||||
@objc dynamic var title: String?
|
||||
@ -25,7 +25,16 @@ class Message: Object {
|
||||
override class func indexedProperties() -> [String] {
|
||||
return ["group", "createDate"]
|
||||
}
|
||||
|
||||
func copyMessage() -> Message {
|
||||
let message = Message()
|
||||
message.id = self.id
|
||||
message.title = self.title
|
||||
message.subtitle = self.subtitle
|
||||
message.body = self.body
|
||||
message.url = self.url
|
||||
message.group = self.group
|
||||
message.createDate = self.createDate
|
||||
return message
|
||||
}
|
||||
}
|
||||
|
||||
//extension Message: CKRecordConvertible {}
|
||||
//extension Message: CKRecordRecoverable {}
|
||||
|
||||
66
Model/MessageSection.swift
Normal file
66
Model/MessageSection.swift
Normal file
@ -0,0 +1,66 @@
|
||||
//
|
||||
// MessageTableViewCellViewModel.swift
|
||||
// Bark
|
||||
//
|
||||
// Created by huangfeng on 2020/11/21.
|
||||
// Copyright © 2020 Fin. All rights reserved.
|
||||
//
|
||||
|
||||
import Differentiator
|
||||
import Foundation
|
||||
import RxCocoa
|
||||
import RxDataSources
|
||||
|
||||
enum MessageListCellItem: Equatable {
|
||||
/// 单条消息
|
||||
case message(model: Message)
|
||||
/// 一组消息,可以收缩折叠
|
||||
case messageGroup(name: String, totalCount: Int, messages: [Message])
|
||||
|
||||
static func == (lhs: Self, rhs: Self) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case (.message(let l), .message(let r)):
|
||||
return l == r
|
||||
case (.messageGroup(let l, _, _), .messageGroup(let r, _, _)):
|
||||
return l == r
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MessageSection {
|
||||
var header: String
|
||||
var messages: [MessageListCellItem]
|
||||
}
|
||||
|
||||
extension MessageSection: AnimatableSectionModelType {
|
||||
typealias Item = MessageListCellItem
|
||||
typealias Identity = String
|
||||
|
||||
var items: [MessageListCellItem] {
|
||||
return self.messages
|
||||
}
|
||||
|
||||
init(original: MessageSection, items: [MessageListCellItem]) {
|
||||
self = original
|
||||
self.messages = items
|
||||
}
|
||||
|
||||
var identity: String {
|
||||
return header
|
||||
}
|
||||
}
|
||||
|
||||
extension MessageListCellItem: IdentifiableType {
|
||||
typealias Identity = String
|
||||
|
||||
var identity: String {
|
||||
switch self {
|
||||
case .message(let model):
|
||||
return model.id
|
||||
case .messageGroup(let name, _, _):
|
||||
return name
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,83 +0,0 @@
|
||||
//
|
||||
// MessageTableViewCellViewModel.swift
|
||||
// Bark
|
||||
//
|
||||
// Created by huangfeng on 2020/11/21.
|
||||
// Copyright © 2020 Fin. All rights reserved.
|
||||
//
|
||||
|
||||
import Differentiator
|
||||
import Foundation
|
||||
import RxCocoa
|
||||
import RxDataSources
|
||||
|
||||
class MessageTableViewCellViewModel: ViewModel {
|
||||
// 不要在删除消息后,再次使用这个对象,否则会crash
|
||||
let message: Message
|
||||
var identity: String
|
||||
|
||||
let title: BehaviorRelay<String>
|
||||
let subtitle: BehaviorRelay<String>
|
||||
let body: BehaviorRelay<String>
|
||||
let url: BehaviorRelay<String>
|
||||
|
||||
let date = BehaviorRelay<String>(value: "")
|
||||
var dateStyle = BehaviorRelay<MessageListCellDateStyle>(value: .relative)
|
||||
|
||||
init(message: Message) {
|
||||
self.message = message
|
||||
self.identity = message.id
|
||||
self.title = BehaviorRelay<String>(value: message.title ?? "")
|
||||
self.subtitle = BehaviorRelay<String>(value: message.subtitle ?? "")
|
||||
self.body = BehaviorRelay<String>(value: message.body ?? "")
|
||||
self.url = BehaviorRelay<String>(value: message.url ?? "")
|
||||
|
||||
super.init()
|
||||
|
||||
dateStyle.map { style in
|
||||
switch style {
|
||||
case .relative:
|
||||
return self.message.createDate?.agoFormatString() ?? ""
|
||||
case .exact:
|
||||
return self.message.createDate?.formatString(format: "yyyy-MM-dd HH:mm") ?? ""
|
||||
}
|
||||
}
|
||||
.bind(to: date)
|
||||
.disposed(by: rx.disposeBag)
|
||||
}
|
||||
}
|
||||
|
||||
struct MessageSection {
|
||||
var header: String
|
||||
var messages: [MessageTableViewCellViewModel]
|
||||
}
|
||||
|
||||
extension MessageSection: AnimatableSectionModelType {
|
||||
typealias Item = MessageTableViewCellViewModel
|
||||
typealias Identity = String
|
||||
|
||||
var items: [MessageTableViewCellViewModel] {
|
||||
return self.messages
|
||||
}
|
||||
|
||||
init(original: MessageSection, items: [MessageTableViewCellViewModel]) {
|
||||
self = original
|
||||
self.messages = items
|
||||
}
|
||||
|
||||
var identity: String {
|
||||
return header
|
||||
}
|
||||
}
|
||||
|
||||
extension MessageTableViewCellViewModel: IdentifiableType {
|
||||
typealias Identity = String
|
||||
|
||||
override func isEqual(_ object: Any?) -> Bool {
|
||||
if let obj = object as? MessageTableViewCellViewModel {
|
||||
// 消息列表cell上显示的时间需要随着时间的变化而变化(1分钟前、2分钟前 ...),如果时间不一样的就需要刷新界面
|
||||
return self.identity == obj.identity && self.date.value == obj.date.value
|
||||
}
|
||||
return super.isEqual(object)
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user