Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avatar improvements #176

Merged
merged 6 commits into from
Jul 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public protocol ViewModelBuilderProtocol {
public protocol BaseMessageInteractionHandlerProtocol {
associatedtype ViewModelT
func userDidTapOnFailIcon(viewModel viewModel: ViewModelT, failIconView: UIView)
func userDidTapOnAvatar(viewModel viewModel: ViewModelT)
func userDidTapOnBubble(viewModel viewModel: ViewModelT)
func userDidBeginLongPressOnBubble(viewModel viewModel: ViewModelT)
func userDidEndLongPressOnBubble(viewModel viewModel: ViewModelT)
Expand Down Expand Up @@ -96,6 +97,9 @@ public class BaseMessagePresenter<BubbleViewT, ViewModelBuilderT, InteractionHan
public func configureCell(cell: CellT, decorationAttributes: ChatItemDecorationAttributes, animated: Bool, additionalConfiguration: (() -> Void)?) {
cell.performBatchUpdates({ () -> Void in
self.messageViewModel.showsTail = decorationAttributes.showsTail
if !decorationAttributes.canShowAvatar {
self.messageViewModel.avatarImage.value = nil
}
cell.bubbleView.userInteractionEnabled = true // just in case something went wrong while showing UIMenuController
cell.baseStyle = self.cellStyle
cell.messageViewModel = self.messageViewModel
Expand All @@ -111,6 +115,10 @@ public class BaseMessagePresenter<BubbleViewT, ViewModelBuilderT, InteractionHan
guard let sSelf = self else { return }
sSelf.onCellBubbleLongPressEnded()
}
cell.onAvatarTapped = { [weak self] (cell) in
guard let sSelf = self else { return }
sSelf.onCellAvatarTapped()
}
cell.onFailedButtonTapped = { [weak self] (cell) in
guard let sSelf = self else { return }
sSelf.onCellFailedButtonTapped(cell.failedButton)
Expand Down Expand Up @@ -172,6 +180,10 @@ public class BaseMessagePresenter<BubbleViewT, ViewModelBuilderT, InteractionHan
public func onCellBubbleLongPressEnded() {
self.interactionHandler?.userDidEndLongPressOnBubble(viewModel: self.messageViewModel)
}

public func onCellAvatarTapped() {
self.interactionHandler?.userDidTapOnAvatar(viewModel: self.messageViewModel)
}

public func onCellFailedButtonTapped(failedButtonView: UIView) {
self.interactionHandler?.userDidTapOnFailIcon(viewModel: self.messageViewModel, failIconView: failedButtonView)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ public class BaseMessageCollectionViewCell<BubbleViewType where BubbleViewType:U
public private(set) var avatarView: UIImageView!
func createAvatarView() -> UIImageView! {
let avatarImageView = UIImageView(frame: CGRect.zero)
avatarImageView.userInteractionEnabled = true
return avatarImageView
}

Expand All @@ -150,9 +151,15 @@ public class BaseMessageCollectionViewCell<BubbleViewType where BubbleViewType:U
longpressGestureRecognizer.delegate = self
return longpressGestureRecognizer
}()

public private(set) lazy var avatarTapGestureRecognizer: UITapGestureRecognizer = {
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(BaseMessageCollectionViewCell.avatarTapped(_:)))
return tapGestureRecognizer
}()

private func commonInit() {
self.avatarView = self.createAvatarView()
self.avatarView.addGestureRecognizer(self.avatarTapGestureRecognizer)
self.bubbleView = self.createBubbleView()
self.bubbleView.addGestureRecognizer(self.tapGestureRecognizer)
self.bubbleView.addGestureRecognizer(self.longPressGestureRecognizer)
Expand Down Expand Up @@ -310,6 +317,12 @@ public class BaseMessageCollectionViewCell<BubbleViewType where BubbleViewType:U
self.onFailedButtonTapped?(cell: self)
}

public var onAvatarTapped: ((cell: BaseMessageCollectionViewCell) -> Void)?
@objc
func avatarTapped(tapGestureRecognizer: UITapGestureRecognizer) {
self.onAvatarTapped?(cell: self)
}

public var onBubbleTapped: ((cell: BaseMessageCollectionViewCell) -> Void)?
@objc
func bubbleTapped(tapGestureRecognizer: UITapGestureRecognizer) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ import Chatto
public struct ChatItemDecorationAttributes: ChatItemDecorationAttributesProtocol {
public let bottomMargin: CGFloat
public let showsTail: Bool
public init(bottomMargin: CGFloat, showsTail: Bool) {
public let canShowAvatar: Bool
public init(bottomMargin: CGFloat, showsTail: Bool, canShowAvatar: Bool) {
self.bottomMargin = bottomMargin
self.showsTail = showsTail
self.canShowAvatar = canShowAvatar
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class BaseMessagePresenterTests: XCTestCase {

// BaseMessagePresenter is generic, let's use the photo one for instance
var presenter: PhotoMessagePresenter<PhotoMessageViewModelDefaultBuilder<PhotoMessageModel<MessageModel>>, PhotoMessageTestHandler>!
let decorationAttributes = ChatItemDecorationAttributes(bottomMargin: 0, showsTail: false)
let decorationAttributes = ChatItemDecorationAttributes(bottomMargin: 0, showsTail: false, canShowAvatar: false)
var interactionHandler: PhotoMessageTestHandler!
override func setUp() {
let viewModelBuilder = PhotoMessageViewModelDefaultBuilder<PhotoMessageModel<MessageModel>>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import XCTest
class PhotoMessagePresenterTests: XCTestCase, UICollectionViewDataSource {

var presenter: PhotoMessagePresenter<PhotoMessageViewModelDefaultBuilder<PhotoMessageModel<MessageModel>>, PhotoMessageTestHandler>!
let decorationAttributes = ChatItemDecorationAttributes(bottomMargin: 0, showsTail: false)
let decorationAttributes = ChatItemDecorationAttributes(bottomMargin: 0, showsTail: false, canShowAvatar: false)
let testImage = UIImage()
override func setUp() {
let viewModelBuilder = PhotoMessageViewModelDefaultBuilder<PhotoMessageModel<MessageModel>>()
Expand Down Expand Up @@ -82,6 +82,11 @@ class PhotoMessageTestHandler: BaseMessageInteractionHandlerProtocol {
func userDidTapOnFailIcon(viewModel viewModel: ViewModelT, failIconView: UIView) {
self.didHandleTapOnFailIcon = true
}

var didHandleTapOnAvatar = false
func userDidTapOnAvatar(viewModel viewModel: ViewModelT) {
self.didHandleTapOnAvatar = true
}

var didHandleTapOnBubble = false
func userDidTapOnBubble(viewModel viewModel: ViewModelT) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import Chatto
class TextMessagePresenterTests: XCTestCase, UICollectionViewDataSource {

var presenter: TextMessagePresenter<TextMessageViewModelDefaultBuilder<TextMessageModel<MessageModel>>, TextMessageTestHandler>!
let decorationAttributes = ChatItemDecorationAttributes(bottomMargin: 0, showsTail: false)
let decorationAttributes = ChatItemDecorationAttributes(bottomMargin: 0, showsTail: false, canShowAvatar: false)
override func setUp() {
let viewModelBuilder = TextMessageViewModelDefaultBuilder<TextMessageModel<MessageModel>>()
let sizingCell = TextMessageCollectionViewCell.sizingCell()
Expand Down Expand Up @@ -91,6 +91,10 @@ class TextMessageTestHandler: BaseMessageInteractionHandlerProtocol {

func userDidTapOnFailIcon(viewModel viewModel: ViewModelT, failIconView: UIView) {

}

func userDidTapOnAvatar(viewModel viewModel: ViewModelT) {

}

func userDidTapOnBubble(viewModel viewModel: ViewModelT) {
Expand Down
5 changes: 4 additions & 1 deletion ChattoApp/ChattoApp/Source/BaseMessageHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@ class BaseMessageHandler {
self.messageSender.sendMessage(viewModel.messageModel)
}

func userDidTapOnAvatar(viewModel viewModel: MessageViewModelProtocol) {
print("userDidTapOnAvatar")
}

func userDidTapOnBubble(viewModel viewModel: DemoMessageViewModelProtocol) {
print("userDidTapOnBubble")

}

func userDidBeginLongPressOnBubble(viewModel viewModel: DemoMessageViewModelProtocol) {
Expand Down
2 changes: 1 addition & 1 deletion ChattoApp/ChattoApp/Source/ChatItemsDemoDecorator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ final class ChatItemsDemoDecorator: ChatItemsDecoratorProtocol {

decoratedChatItems.append(DecoratedChatItem(
chatItem: chatItem,
decorationAttributes: ChatItemDecorationAttributes(bottomMargin: bottomMargin, showsTail: showsTail))
decorationAttributes: ChatItemDecorationAttributes(bottomMargin: bottomMargin, showsTail: showsTail, canShowAvatar: showsTail))
)
decoratedChatItems.appendContentsOf(additionalItems)
}
Expand Down
13 changes: 9 additions & 4 deletions ChattoApp/ChattoApp/Source/DemoChatViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,25 @@ class DemoChatViewController: BaseChatViewController {
}

override func createPresenterBuilders() -> [ChatItemType: [ChatItemPresenterBuilderProtocol]] {

let textMessagePresenter = TextMessagePresenterBuilder(
viewModelBuilder: DemoTextMessageViewModelBuilder(),
interactionHandler: DemoTextMessageHandler(baseHandler: self.baseMessageHandler)
)
textMessagePresenter.baseMessageStyle = BaseMessageCollectionViewCellAvatarStyle()

let photoMessagePresenter = PhotoMessagePresenterBuilder(
viewModelBuilder: DemoPhotoMessageViewModelBuilder(),
interactionHandler: DemoPhotoMessageHandler(baseHandler: self.baseMessageHandler)
)
photoMessagePresenter.baseCellStyle = BaseMessageCollectionViewCellAvatarStyle()

return [
DemoTextMessageModel.chatItemType: [
textMessagePresenter
],
DemoPhotoMessageModel.chatItemType: [
PhotoMessagePresenterBuilder(
viewModelBuilder: DemoPhotoMessageViewModelBuilder(),
interactionHandler: DemoPhotoMessageHandler(baseHandler: self.baseMessageHandler)
)
photoMessagePresenter
],
SendingStatusModel.chatItemType: [SendingStatusPresenterBuilder()],
TimeSeparatorModel.chatItemType: [TimeSeparatorPresenterBuilder()]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ class DemoPhotoMessageHandler: BaseMessageInteractionHandlerProtocol {
func userDidTapOnFailIcon(viewModel viewModel: DemoPhotoMessageViewModel, failIconView: UIView) {
self.baseHandler.userDidTapOnFailIcon(viewModel: viewModel)
}

func userDidTapOnAvatar(viewModel viewModel: DemoPhotoMessageViewModel) {
self.baseHandler.userDidTapOnAvatar(viewModel: viewModel)
}

func userDidTapOnBubble(viewModel viewModel: DemoPhotoMessageViewModel) {
self.baseHandler.userDidTapOnBubble(viewModel: viewModel)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class DemoPhotoMessageViewModelBuilder: ViewModelBuilderProtocol {
func createViewModel(model: DemoPhotoMessageModel) -> DemoPhotoMessageViewModel {
let messageViewModel = self.messageViewModelBuilder.createMessageViewModel(model)
let photoMessageViewModel = DemoPhotoMessageViewModel(photoMessage: model, messageViewModel: messageViewModel)
photoMessageViewModel.avatarImage.value = UIImage(named: "userAvatar")
return photoMessageViewModel
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ class DemoTextMessageHandler: BaseMessageInteractionHandlerProtocol {
func userDidTapOnFailIcon(viewModel viewModel: DemoTextMessageViewModel, failIconView: UIView) {
self.baseHandler.userDidTapOnFailIcon(viewModel: viewModel)
}

func userDidTapOnAvatar(viewModel viewModel: DemoTextMessageViewModel) {
self.baseHandler.userDidTapOnAvatar(viewModel: viewModel)
}

func userDidTapOnBubble(viewModel viewModel: DemoTextMessageViewModel) {
self.baseHandler.userDidTapOnBubble(viewModel: viewModel)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ public class DemoTextMessageViewModelBuilder: ViewModelBuilderProtocol {
public func createViewModel(textMessage: DemoTextMessageModel) -> DemoTextMessageViewModel {
let messageViewModel = self.messageViewModelBuilder.createMessageViewModel(textMessage)
let textMessageViewModel = DemoTextMessageViewModel(textMessage: textMessage, messageViewModel: messageViewModel)
// Best place to decide whether user having avart might be in the presenter. Here just for demo purpose
// Because we might only want to display avatar when showTail in the nessage bubble
textMessageViewModel.avatarImage.value = UIImage(named: "userAvatar")
return textMessageViewModel
}
Expand Down