Skip to content

Instantly share code, notes, and snippets.

@rinat-enikeev
Last active June 8, 2021 08:36
Show Gist options
  • Save rinat-enikeev/3bd73ab1ac0b0f0591de72781bba165e to your computer and use it in GitHub Desktop.
Save rinat-enikeev/3bd73ab1ac0b0f0591de72781bba165e to your computer and use it in GitHub Desktop.
Chatto ImageMessage
// MARK: - ImageMessageModel
import Chatto
import ChattoAdditions
protocol ImageMessageModelProtocol: PhotoMessageModelProtocol {
var url: URL? { get set }
}
public class ImageMessageModel: PhotoMessageModel<MessageModel>, ImageMessageModelProtocol {
var url: URL?
var placeholder: UIImage
init(messageModel: MessageModel, imageSize: CGSize, placeholder: UIImage, url: URL?) {
self.url = url
self.placeholder = placeholder
super.init(messageModel: messageModel, imageSize: imageSize, image: placeholder)
}
}
extension ImageMessageModel {
static var chatItemType: ChatItemType {
return "image"
}
}
// MARK: - ImageMessageViewModel
import ChattoAdditions
import Kingfisher
protocol ImageMessageViewModelProtocol: PhotoMessageViewModelProtocol {
var imageUrl: URL? { get set }
var placeholder: UIImage { get set }
}
class ImageMessageViewModelBuilder: ViewModelBuilderProtocol {
let messageViewModelBuilder = MessageViewModelDefaultBuilder()
func createViewModel(_ model: ImageMessageModel) -> ImageMessageViewModel {
let messageViewModel = self.messageViewModelBuilder.createMessageViewModel(model)
let photoMessageViewModel = ImageMessageViewModel(photoMessage: model, messageViewModel: messageViewModel)
photoMessageViewModel.imageUrl = model.url
return photoMessageViewModel
}
func canCreateViewModel(fromModel model: Any) -> Bool {
return model is ImageMessageModel
}
}
class ImageMessageViewModel: PhotoMessageViewModel<ImageMessageModel>, ImageMessageViewModelProtocol {
var imageUrl: URL?
var placeholder: UIImage
override init(photoMessage: ImageMessageModel, messageViewModel: MessageViewModelProtocol) {
placeholder = photoMessage.placeholder
super.init(photoMessage: photoMessage, messageViewModel: messageViewModel)
}
override func willBeShown() {
updateImage()
}
private func updateImage() {
if image.value == placeholder, let imageUrl = imageUrl {
if ImageCache.default.imageCachedType(forKey: imageUrl.absoluteString) == CacheType.none {
transferDirection.value = .download
transferStatus.value = .transfering
ImageDownloader.default.downloadImage(with: imageUrl, progressBlock: { [weak self] (receivedSize, totalSize) in
if totalSize > 0 {
self?.transferProgress.value = Double(receivedSize) / Double(totalSize)
}
}, completionHandler: { [weak self] (image, error, url, data) in
if let image = image {
self?.transferStatus.value = .success
self?.image.value = image
ImageCache.default.store(image, forKey: imageUrl.absoluteString)
} else {
self?.transferStatus.value = .failed
}
})
} else {
ImageCache.default.retrieveImage(forKey: imageUrl.absoluteString, options: nil) { [weak self]
image, cacheType in
if let image = image {
self?.transferStatus.value = .success
self?.image.value = image
} else {
self?.transferStatus.value = .failed
}
}
}
}
}
}
// MARK: - ImageMessagePresenterBuilder & ImageMessagePresenter
import Chatto
import ChattoAdditions
class ImageMessagePresenterBuilder<ViewModelBuilderT: ViewModelBuilderProtocol, InteractionHandlerT: BaseMessageInteractionHandlerProtocol>: PhotoMessagePresenterBuilder<ViewModelBuilderT, InteractionHandlerT> where
ViewModelBuilderT.ViewModelT: ImageMessageViewModelProtocol,
InteractionHandlerT.ViewModelT == ViewModelBuilderT.ViewModelT{
override func createPresenterWithChatItem(_ chatItem: ChatItemProtocol) -> ChatItemPresenterProtocol {
assert(self.canHandleChatItem(chatItem))
return ImageMessagePresenter<ViewModelBuilderT, InteractionHandlerT>(
messageModel: chatItem as! ModelT,
viewModelBuilder: self.viewModelBuilder,
interactionHandler: self.interactionHandler,
sizingCell: sizingCell,
baseCellStyle: self.baseCellStyle,
photoCellStyle: self.photoCellStyle
)
}
}
class ImageMessagePresenter<ViewModelBuilderT: ViewModelBuilderProtocol, InteractionHandlerT: BaseMessageInteractionHandlerProtocol>: PhotoMessagePresenter<ViewModelBuilderT, InteractionHandlerT> where
ViewModelBuilderT.ViewModelT: ImageMessageViewModelProtocol,
InteractionHandlerT.ViewModelT == ViewModelBuilderT.ViewModelT {
}
// MARK: - ImageMessageHandler
import Foundation
import ChattoAdditions
class ImageMessageHandler: BaseMessageInteractionHandlerProtocol {
typealias ViewModelT = ImageMessageViewModel
func userDidTapOnFailIcon(viewModel: ImageMessageViewModel, failIconView: UIView) {
print("Function: \(#function), line: \(#line)")
}
func userDidTapOnAvatar(viewModel: ImageMessageViewModel) {
print("Function: \(#function), line: \(#line)")
}
func userDidTapOnBubble(viewModel: ImageMessageViewModel) {
print("Function: \(#function), line: \(#line)")
}
func userDidBeginLongPressOnBubble(viewModel: ImageMessageViewModel) {
print("Function: \(#function), line: \(#line)")
}
func userDidEndLongPressOnBubble(viewModel: ImageMessageViewModel) {
print("Function: \(#function), line: \(#line)")
}
func userDidSelectMessage(viewModel: ImageMessageViewModel) {
print("Function: \(#function), line: \(#line)")
}
func userDidDeselectMessage(viewModel: ImageMessageViewModel) {
print("Function: \(#function), line: \(#line)")
}
}
// MARK: - ChattoViewController
import Chatto
import ChattoAdditions
class ChattoViewController: BaseChatViewController {
...
override func createPresenterBuilders() -> [ChatItemType: [ChatItemPresenterBuilderProtocol]] {
let imageMessagePresenter = ImageMessagePresenterBuilder(
viewModelBuilder: ImageMessageViewModelBuilder(),
interactionHandler: ImageMessageHandler()
)
imageMessagePresenter.baseCellStyle = MessageCollectionViewCellAvatarStyle()
return [
ImageMessageModel.chatItemType: [imageMessagePresenter],
]
}
...
}
// MARK: - ChatDataSource
class ChatDataSource: ChatDataSourceProtocol {
...
let model = MessageModel(uid: objectId,
senderId: senderId,
type: ImageMessageModel.chatItemType,
isIncoming: true,
date: createdAt,
status: .success)
let chatItem = ImageMessageModel(messageModel: model,
imageSize: size,
placeholder: UIImage(named: "placeholder")!,
url: <your url>)
chatItems.append(chatItem)
delegate?.chatDataSourceDidUpdate(self)
...
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment