Last active
May 16, 2020 10:59
-
-
Save n1kron/d61e82a60c9d5e0875b1d60660273343 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
import AsyncDisplayKit | |
final class NewChatViewController: ASViewController<ASDisplayNode>, ASTableDataSource, ASTableDelegate { | |
struct State { | |
var itemCount: Int | |
var fetchingMore: Bool | |
static let empty = State(itemCount: 0, fetchingMore: false) | |
} | |
enum Action { | |
case beginBatchFetch | |
case endBatchFetch(resultCount: Int) | |
} | |
var tableNode: ASTableNode { | |
return node as! ASTableNode | |
} | |
fileprivate var messages = [Message]() | |
fileprivate var offset = 0 | |
fileprivate var stopLoadMessages = false | |
fileprivate(set) var state: State = .empty | |
init() { | |
super.init(node: ASTableNode()) | |
tableNode.delegate = self | |
tableNode.dataSource = self | |
tableNode.view.allowsSelection = false | |
tableNode.view.separatorStyle = .none | |
tableNode.view.keyboardDismissMode = .interactive | |
tableNode.inverted = true | |
} | |
required init?(coder aDecoder: NSCoder) { | |
fatalError() | |
} | |
// MARK: ASTableNode data source and delegate. | |
func numberOfSections(in tableNode: ASTableNode) -> Int { | |
return 1 | |
} | |
func tableNode(_ tableNode: ASTableNode, numberOfRowsInSection section: Int) -> Int { | |
return messages.count | |
} | |
func tableNode(_ tableNode: ASTableNode, nodeForRowAt indexPath: IndexPath) -> ASCellNode { | |
let node = ASTextCellNode() | |
let currentMessage = messages[indexPath.row] | |
//if you need parse html use this: | |
//node.textNode.text = currentMessage.text?.html2AttributedString | |
node.text = currentMessage.text | |
return node | |
} | |
func tableNode(_ tableNode: ASTableNode, willBeginBatchFetchWith context: ASBatchContext) { | |
DispatchQueue.main.async { | |
let oldState = self.state | |
self.state = NewChatViewController.handleAction(.beginBatchFetch, fromState: oldState) | |
self.renderDiff(oldState) | |
} | |
self.fetchDataWithCompletion { resultCount in | |
if !self.stopLoadMessages { | |
let action = Action.endBatchFetch(resultCount: resultCount) | |
let oldState = self.state | |
self.state = NewChatViewController.handleAction(action, fromState: oldState) | |
self.renderDiff(oldState) | |
context.completeBatchFetching(true) | |
} | |
} | |
} | |
fileprivate func renderDiff(_ oldState: State) { | |
self.tableNode.performBatchUpdates({ | |
let indexPaths = (oldState.itemCount ..< state.itemCount).map { index in | |
IndexPath(row: index, section: 0) | |
} | |
tableNode.insertRows(at: indexPaths, with: .none) | |
}, completion:nil) | |
} | |
fileprivate func fetchDataWithCompletion(_ completion: @escaping (Int) -> Void) { | |
ChatApi.fetchChat(offset: self.offset, limit: 100, completed: {[weak self] (messages,suggestions,placeholder) in | |
self?.stopLoadMessages = messages.isEmpty | |
messages.forEach({(message) in | |
self?.messages.append(message) | |
}) | |
self?.offset += 100 | |
completion(messages.count) | |
}, error: { | |
}) | |
} | |
fileprivate static func handleAction(_ action: Action, fromState state: State) -> State { | |
var state = state | |
switch action { | |
case .beginBatchFetch: | |
state.fetchingMore = true | |
case let .endBatchFetch(resultCount): | |
state.itemCount += resultCount | |
state.fetchingMore = false | |
} | |
return state | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment