Last active
June 8, 2021 08:36
-
-
Save rinat-enikeev/3bd73ab1ac0b0f0591de72781bba165e to your computer and use it in GitHub Desktop.
Chatto ImageMessage
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
// 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