160 lines
8.0 KiB
Markdown
160 lines
8.0 KiB
Markdown
# Chatto [](https://travis-ci.org/badoo/Chatto) [](https://codecov.io/github/badoo/Chatto?branch=master) [](https://img.shields.io/cocoapods/v/Chatto.svg) [](https://github.com/Carthage/Carthage)
|
||
|
||
|
||
`Chatto` is a Swift lightweight framework to build chat applications. It's been designed to be extensible and performant. Along with `Chatto` there is `ChattoAdditions`, a companion framework which includes cells for messages and an extensible input component. You can find more details about how it was implemented in our [blog](https://techblog.badoo.com/blog/2015/12/04/how-we-made-chatto/). See them in action!
|
||
<div align="center">
|
||
<img src="./readme-images/readme-pic-1.png" />
|
||
<img src="./readme-images/readme-pic-2.png" />
|
||
<img src="./readme-images/readme-pic-3.png" />
|
||
<img src="./readme-images/readme-pic-4.png" />
|
||
</div>
|
||
|
||
## Features
|
||
- Calculation of collection view changes and layout in background
|
||
- Supports pagination in both directions and autoloading
|
||
- Message count contention for fast pagination and rotation with thousands of messsages
|
||
- Accessory view revealing by swiping from right
|
||
- Interactive keyboard dismissal
|
||
- Text bubbles
|
||
- Photo bubbles
|
||
- Extensible input bar
|
||
|
||
## How to use
|
||
|
||
1. Subclass BaseChatViewController
|
||
2. Override `createChatInputView()` to use `ChattoAdditions.ChatInputBar` or provide your own component
|
||
3. Provide a data source with your messages
|
||
4. Override `createPresenterBuilders()`. There will be a presenter for each message that will be responsible for the UI of that message.
|
||
|
||
```swift
|
||
override func createPresenterBuilders() -> [ChatItemType: [ChatItemPresenterBuilderProtocol]] {
|
||
return [
|
||
TextMessageModel.chatItemType: [
|
||
TextMessagePresenterBuilder(
|
||
viewModelBuilder: TextMessageViewModelDefaultBuilder<TextMessageModel>(),
|
||
interactionHandler: TextMessageHandler(baseHandler: self.baseMessageHandler)
|
||
)
|
||
]
|
||
]
|
||
}
|
||
|
||
override func createChatInputView() -> UIView {
|
||
let chatInputView = ChatInputBar.loadNib()
|
||
self.configureChatInputBar(chatInputView)
|
||
self.chatInputPresenter = ChatInputBarPresenter(chatInputView: chatInputView, chatInputItems: self.createChatInputItems())
|
||
return chatInputView
|
||
}
|
||
|
||
override func viewDidLoad() {
|
||
super.viewDidLoad()
|
||
self.chatDataSource = self.myDataSource
|
||
}
|
||
|
||
```
|
||
### Data source
|
||
The only requirement for your data source items is to conform to the ChatItemProtocol protocol, which basically asks for a unique identifier (uid) and a type. The uid will be used to calculate changes in the collection view and the type to quickly find a presenter builder for it. Your data source must conform to ChatDataSourceProtocol:
|
||
```swift
|
||
public protocol ChatDataSourceProtocol: class {
|
||
var hasMoreNext: Bool { get }
|
||
var hasMorePrevious: Bool { get }
|
||
var chatItems: [ChatItemProtocol] { get }
|
||
weak var delegate: ChatDataSourceDelegateProtocol? { get set }
|
||
|
||
func loadNext(completion: () -> Void)
|
||
func loadPrevious(completion: () -> Void)
|
||
func adjustNumberOfMessages(preferredMaxCount preferredMaxCount: Int?, focusPosition: Double, completion:(didAdjust: Bool) -> Void) // If you want, implement message count contention for performance, otherwise just call completion(false)
|
||
}
|
||
```
|
||
If you want to handle smooth loading of new pages, or more challenging, smooth rotation with thousands of messages (calculating 10K text message sizes can take ~15s on iPhone 4s) you should opt-in for adjustNumberOfMessages(preferredMaxCount:focusPosition:completion:). See how it's done in ChattoApp!
|
||
|
||
### Presenters
|
||
The presenter is the key entity that enables scalability in `Chatto`'s architecture. Each message will be paired with a presenter who will be responsible for the UI related to that message (cell configuration, calculation of size, user handling,... ). Take a look at `TextMessagePresenter`, `PhotoMessagePresenter` in ChattoAdditions and `ChatItemPresenterProtocol`
|
||
|
||
```swift
|
||
public protocol ChatItemPresenterProtocol: class {
|
||
static func registerCells(collectionView: UICollectionView)
|
||
var canCalculateHeightInBackground: Bool { get } // Default is false
|
||
func heightForCell(maximumWidth width: CGFloat, decorationAttributes: ChatItemDecorationAttributesProtocol?) -> CGFloat
|
||
func dequeueCell(collectionView collectionView: UICollectionView, indexPath: NSIndexPath) -> UICollectionViewCell
|
||
func configureCell(cell: UICollectionViewCell, decorationAttributes: ChatItemDecorationAttributesProtocol?)
|
||
func cellWillBeShown(cell: UICollectionViewCell) // optional
|
||
func cellWasHidden(cell: UICollectionViewCell) // optional
|
||
func shouldShowMenu() -> Bool // optional. Default is false
|
||
func canPerformMenuControllerAction(action: Selector) -> Bool // optional. Default is false
|
||
func performMenuControllerAction(action: Selector) // optional
|
||
}
|
||
```
|
||
|
||
### Decoration
|
||
As you may have noticed, there's an interesting decorationAttributes parameter in `configureCell(_:decorationAttributes:)`
|
||
```swift
|
||
public protocol ChatItemDecorationAttributesProtocol {
|
||
var bottomMargin: CGFloat { get }
|
||
}
|
||
```
|
||
Decoration attributes have two different purposes:
|
||
|
||
1. Provide margins for `ChatCollectionViewLayout`
|
||
2. Provide context to your presenters so you can further customize your UI (for instance to flag if a bubble should show the tail)
|
||
|
||
By default, no decorationAttributes will be provided to your presenters, and the margin between messages will be zero. You may opt-in for a message decorator as in ChattoApp
|
||
```swift
|
||
public protocol ChatItemsDecoratorProtocol {
|
||
func decorateItems(chatItems: [ChatItemProtocol]) -> [DecoratedChatItem]
|
||
}
|
||
```
|
||
In your decorator you may even create new ChatItems. The decorator in ChattoApp not only provides different margins for the bubbles, but it also inserts new ChatItems that represents sending/failed status. Decoration happens in background so the UI stays responsive while scrolling.
|
||
|
||
### Input bar
|
||
You can return your own input component when overriding `createChatInputView()` or use `ChattoAdditions.ChatInputBar`
|
||
|
||
`ChattoAdditions.ChatInputBar` is an extensible component on its own. Each input item defines a `tabView` that serves as the call to action to activate that input item and an `inputView` with your custom input UI. ChatInputBarPresenter will take a collection of `ChatInputItemProtocol` and it will configure ChatInputBar to display them.
|
||
|
||
```swift
|
||
public protocol ChatInputItemProtocol: AnyObject {
|
||
var tabView: UIView { get }
|
||
var inputView: UIView? { get }
|
||
var presentationMode: ChatInputItemPresentationMode { get }
|
||
var showsSendButton: Bool { get }
|
||
var selected: Bool { get set }
|
||
|
||
func handleInput(input: AnyObject)
|
||
}
|
||
```
|
||
|
||
## How to install
|
||
### CocoaPods
|
||
|
||
1. Make sure `use_frameworks!` is added to your `Podfile`.
|
||
|
||
2. Include the following in your `Podfile`:
|
||
```
|
||
pod 'Chatto', '= 1.0.0'
|
||
pod 'ChattoAdditions', '= 1.0.0' # if you want to use the cells or the input component
|
||
```
|
||
If you like to live on the bleeding edge, you can use the `master` branch with:
|
||
```
|
||
pod 'Chatto', :git => 'https://github.com/badoo/Chatto'
|
||
pod 'ChattoAdditions', :git => 'https://github.com/badoo/Chatto'
|
||
```
|
||
3. Run `pod install`
|
||
|
||
### Carthage
|
||
|
||
If you’re using [Carthage](https://github.com/Carthage/Carthage#if-youre-building-for-ios-tvos-or-watchos), simply add Chatto to your Cartfile:
|
||
```
|
||
github "badoo/Chatto"
|
||
```
|
||
|
||
### Manually
|
||
|
||
1. Clone, add as a submodule or [download.](https://github.com/badoo/Chatto/archive/master.zip)
|
||
2. Drag and drop `Chatto` and/or `ChattoAdditions` project to your workspace
|
||
3. Add `Chatto` and/or `ChattoAdditions` to Embedded binaries
|
||
|
||
## License
|
||
Source code is distributed under MIT license.
|
||
|
||
##Blog
|
||
Read more on our [tech blog](http://techblog.badoo.com/) or explore our other [open source projects](https://github.com/badoo)
|