Merge pull request #59 from MessageKit/v0.4.0

v0.4.0
This commit is contained in:
Steven Deutsch
2017-08-13 18:25:36 -05:00
committed by GitHub
18 changed files with 322 additions and 113 deletions
+32
View File
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="850px" height="150px" viewBox="0 0 850 150" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 46.1 (44463) - http://www.bohemiancoding.com/sketch -->
<title>logo</title>
<desc>Created with Sketch.</desc>
<defs>
<path d="M36.5,1.95893649e-15 L60.5722556,1.95893649e-15 L60.5722556,-7.10542736e-15 C82.1113608,-1.10618979e-14 99.5722556,17.4608948 99.5722556,39 L99.5722556,44.290832 C99.7329312,51.1914512 100.803619,56.4527236 102.784319,60.0746491 C104.765019,63.6965746 108.503579,68.0050249 114,73 L99.5722556,73 L36.5,73 L36.5,73 C16.3416066,73 2.46869119e-15,56.6583934 0,36.5 L0,36.5 L0,36.5 C-2.46869119e-15,16.3416066 16.3416066,1.79140557e-14 36.5,1.42108547e-14 L36.5,1.95893649e-15 Z M34.5418656,21.1594203 C33.0811125,21.1594203 31.8969381,22.3435947 31.8969381,23.8043478 C31.8969381,25.265101 33.0811125,26.4492754 34.5418656,26.4492754 L73.7417418,26.4492754 C75.2024949,26.4492754 76.3866693,25.265101 76.3866693,23.8043478 C76.3866693,22.3435947 75.2024949,21.1594203 73.7417418,21.1594203 L34.5418656,21.1594203 Z M23.8897931,33.8550725 C22.42904,33.8550725 21.2448656,35.0392469 21.2448656,36.5 L21.2448656,36.5 L21.2448656,36.5 C21.2448656,37.9607531 22.42904,39.1449275 23.8897931,39.1449275 L63.0896693,39.1449275 C64.5504224,39.1449275 65.7345968,37.9607531 65.7345968,36.5 L65.7345968,36.5 C65.7345968,35.0392469 64.5504224,33.8550725 63.0896693,33.8550725 L63.0896693,33.8550725 L23.8897931,33.8550725 Z M34.5418656,46.5507246 C33.0811125,46.5507246 31.8969381,47.734899 31.8969381,49.1956522 L31.8969381,49.1956522 L31.8969381,49.1956522 C31.8969381,50.6564053 33.0811125,51.8405797 34.5418656,51.8405797 L73.7417418,51.8405797 C75.2024949,51.8405797 76.3866693,50.6564053 76.3866693,49.1956522 C76.3866693,47.734899 75.2024949,46.5507246 73.7417418,46.5507246 L34.5418656,46.5507246 Z" id="path-1"></path>
<linearGradient x1="50%" y1="0%" x2="50%" y2="99.2426658%" id="linearGradient-3">
<stop stop-color="#4EF46A" offset="0%"></stop>
<stop stop-color="#3DBE52" offset="100%"></stop>
</linearGradient>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="logo">
<g id="Group" transform="translate(313.000000, 29.000000)" fill="#000000">
<text id="MessageKit" font-family="SFProDisplay-Regular, SF Pro Display" font-size="55" font-weight="normal">
<tspan x="0" y="52">MessageKit</tspan>
</text>
<text id="An-elegant-messages-U" font-family="SFProDisplay-Thin, SF Pro Display" font-size="25" font-style="condensed" font-weight="300">
<tspan x="0" y="86">An elegant messages UI library for iOS</tspan>
</text>
</g>
<g id="Rectangle-3" transform="translate(175.000000, 39.000000)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="Mask" fill="#000000" xlink:href="#path-1"></use>
<rect fill="url(#linearGradient-3)" mask="url(#mask-2)" x="0" y="-20" width="114" height="112"></rect>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

+75
View File
@@ -0,0 +1,75 @@
# Contributing Guidelines
### Code of Conduct
Please read our [Code of Conduct](https://github.com/MessageKit/MessageKit/blob/974cb068f40a4959ec3b7bbf5894d405925079e4/Code_of_Conduct.md).
The MessageKit maintainers take this Code of Conduct very seriously. Intolereance, disrespect, harassment, and any form of negavity will not be tolerated.
### Ways to Contribute
You can contribute to MessageKit in a variety of ways:
- Fixing or reporting bugs :scream:
- Improving documentation :heart:
- Suggesting new features :smiley:
- Increasing unit test coverage :pray:
- Resolving any open issues :+1:
If you're new to Open Source or Swift, the MessageKit community is a great place to get involved.
**Your contributions are always welcome, no contribution is too small.**
### Opening a New Issue
- Please check the [README](https://github.com/MessageKit/MessageKit/blob/master/README.md) to see if your question is answered there.
- Search [open issues](https://github.com/MessageKit/MessageKit/issues?q=is%3Aopen+is%3Aissue) and [closed issues](https://github.com/MessageKit/MessageKit/issues?q=is%3Aissue+is%3Aclosed) to avoid opening a duplicate issue.
- Avoiding duplicate issues organizes all relevant information for project maintainers and other users.
- If no issues represent your problem, please open a new issue with a good tile and useful description.
- Information to Provide When Opening an Issue:
- MessageKit version(s)
- iOS version(s)
- Devices/Simulators affected
- Full crash log, if applicable
- A well written description of the problem you are experiencing
- *Please provide complete steps to reproduce the issue*
- For UI related issues, please provide a screenshot/GIF/video showing the issue
- Link to a project or demo project that exhibits the issue
- Search for an list any issues that might be related
The more information you can provide, the easier it will be for us to resolve your issue in a timely manner.
### Submitting a Pull Request
- Please read the MessageKit [VISION.md](https://github.com/MessageKit/MessageKit/blob/master/VISION.md) document to understand the project goals, scope, and other technical considerations.
- We strongly encourage you to open an issue discussing any potential new features before an implementation is provided.
- This ensures the feature is in scope and no ones time is wasted.
- **Please DO NOT submit pull requests to the `master` branch**
- This branch is always stable and represents a relase.
- **Please DO submit your pull request to the branch repersenting the next release version**
1. Link to any issues the pull request resolves. If none exist, create one.
2. Write unit tests for new functionality or fix any broken by your changes.
3. If your changes affect documentation, please update them accordingly.
4. Avoid pull requests with a large number of commits.
5. Write clean code and follow the MessageKit [style guidelines](#style-guidelines).
**You should submit one pull request per feature, the smaller the pull request the better chances it will be merged.**
Enormous pull requests take a signficant time to review and understand their implications on the existing codebase.
### Style Guidelines
Writing clean code and upholding project standards is as important as adding new features. To ensure this, MessageKit employs a few practices:
1. We use [SwiftLint](https://github.com/realm/SwiftLint) to enforce style and conventions at compile time.
2. We adhere to the [Swift API Design Guidelines](https://swift.org/documentation/api-design-guidelines/).
3. We follow the [Raywenderlich Swift Style Guide ](https://github.com/raywenderlich/swift-style-guide) but may have slight variations.
### Questions and Contact
If any of the sections above are unclear and require further explanation, *do not hesitate to reach out*.
MessageKit strives to build an inclusive open source community and to make contributing as easy as possible for memebers of all experience levels.
**You can get in touch with the MessageKit core team directly by joining our open Slack community channel: [here](https://join.slack.com/t/messagekit/shared_invite/MjI0NDkxNjgwMzA3LTE1MDIzMTU0MjUtMzJhZDZlNTkxMA).**
@@ -62,15 +62,15 @@ extension ConversationViewController: MessagesDataSource {
extension ConversationViewController: MessagesDisplayDataSource {
func avatarForMessage(_ message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> Avatar {
func avatar(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> Avatar {
return SampleData().getAvatarFor(sender: message.sender)
}
func headerForMessage(_ message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageHeaderView? {
func messageHeaderView(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageHeaderView? {
return messagesCollectionView.dequeueMessageHeaderView(for: indexPath)
}
func footerForMessage(_ message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageFooterView? {
func messageFooterView(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageFooterView? {
return messagesCollectionView.dequeueMessageFooterView(for: indexPath)
}
@@ -92,11 +92,11 @@ extension ConversationViewController: MessagesDisplayDataSource {
extension ConversationViewController: MessagesLayoutDelegate {
func headerSizeFor(_ message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
func headerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
return CGSize(width: messagesCollectionView.bounds.width, height: 4)
}
func footerSizeFor(_ message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
func footerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
return CGSize(width: messagesCollectionView.bounds.width, height: 4)
}
+21 -13
View File
@@ -26,17 +26,25 @@ import Foundation
import MessageKit
struct MockMessage: MessageType {
var messageId: String
var sender: Sender
var sentDate: Date
var data: MessageData
init(text: String, sender: Sender, messageId: String) {
data = .text(text)
self.sender = sender
self.messageId = messageId
self.sentDate = Date()
}
var messageId: String
var sender: Sender
var sentDate: Date
var data: MessageData
private init(data: MessageData, sender: Sender, messageId: String) {
self.data = data
self.sender = sender
self.messageId = messageId
self.sentDate = Date()
}
init(text: String, sender: Sender, messageId: String) {
self.init(data: .text(text), sender: sender, messageId: messageId)
}
init(attributedText: NSAttributedString, sender: Sender, messageId: String) {
self.init(data: .attributedText(attributedText), sender: sender, messageId: messageId)
}
}
+22 -2
View File
@@ -39,8 +39,28 @@ struct SampleData {
let msg6 = MockMessage(text: "I think if you do something and it turns out pretty good, then you should go do something else wonderful, not dwell on it for too long. Just figure out what’s next.", sender: Jobs, messageId: UUID().uuidString)
let msg7 = MockMessage(text: "Remembering that I'll be dead soon is the most important tool I've ever encountered to help me make the big choices in life. Because almost everything - all external expectations, all pride, all fear of embarrassment or failure - these things just fall away in the face of death, leaving only what is truly important.", sender: Jobs, messageId: UUID().uuidString)
let msg8 = MockMessage(text: "Price is rarely the most important thing. A cheap product might sell some units. Somebody gets it home and they feel great when they pay the money, but then they get it home and use it and the joy is gone.", sender: Cook, messageId: UUID().uuidString)
return [msg1, msg2, msg3, msg4, msg5, msg6, msg7, msg8]
let msg9Text = NSString(string: "Use .attributedText() to add bold, italic, colored text and more...")
let msg9AttributedText = NSMutableAttributedString(string: String(msg9Text))
if #available(iOS 9.0, *) {
msg9AttributedText.addAttributes([NSFontAttributeName: UIFont.monospacedDigitSystemFont(ofSize: UIFont.systemFontSize, weight: UIFontWeightBold)], range: msg9Text.range(of: ".attributedText()"))
} else {
msg9AttributedText.addAttributes([NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle], range: msg9Text.range(of: ".attributedText()"))
}
msg9AttributedText.addAttributes([NSFontAttributeName: UIFont.boldSystemFont(ofSize: UIFont.systemFontSize)],
range: msg9Text.range(of: "bold"))
msg9AttributedText.addAttributes([NSFontAttributeName: UIFont.italicSystemFont(ofSize: UIFont.systemFontSize)],
range: msg9Text.range(of: "italic"))
msg9AttributedText.addAttributes([NSForegroundColorAttributeName: UIColor.red],
range: msg9Text.range(of: "colored"))
let msg9 = MockMessage(attributedText: msg9AttributedText, sender: Jobs, messageId: UUID().uuidString)
return [msg1, msg2, msg3, msg4, msg5, msg6, msg7, msg8, msg9]
}
func getCurrentSender() -> Sender {
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'MessageKit'
s.version = '0.3.0'
s.version = '0.4.0'
s.license = { :type => "MIT", :file => "LICENSE.md" }
s.summary = 'An elegant messages UI library for iOS.'
+66 -10
View File
@@ -1,22 +1,78 @@
# MessageKit
<p align="center">
<img src="https://github.com/MessageKit/MessageKit/master/Assets/logo.svg" title="MessageKit logo">
</p>
[![Build Status](https://travis-ci.org/MessageKit/MessageKit.svg)](https://travis-ci.org/MessageKit/MessageKit) [![codecov](https://codecov.io/gh/MessageKit/MessageKit/branch/master/graph/badge.svg)](https://codecov.io/gh/MessageKit/MessageKit)
**In-progress**, this project is intended to be a Swift rewrite of the recently deprecated [JSQMessagesViewController](https://github.com/jessesquires/JSQMessagesViewController).
## Want to contribute?
## Table of Contents
Great! :+1: Because we could really use the help of the iOS community.
* [**Goal**](#goal)📈
* [**Contributing**](#contributing)
* [**Getting started**](#getting-started)
* [**Requirements**](#requirements)
* [**Code of Conduct**](#code-of-conduct)
* [**What's Next**](#what's-next)
* [**Apps using this library**](#apps-using-this-library)
* [**License**](#license)
See [#1](https://github.com/MessageKit/MessageKit/issues/1) to familiarize yourself with the effort.
See [#12](https://github.com/MessageKit/MessageKit/issues/12) to discuss v0.2.0.
## Goals
## Submitting a Pull Request
This project is in active development and branches are likely out of sync with their local counterparts.
If you want to submit a pull request, please join our [Slack channel](https://github.com/MessageKit/MessageKit/issues/22) to discuss your proposed changes.
- Provide a :rotating_light:safe:rotating_light: enviroment for others to learn an grow through Open Source.
- Make adding Chat:speech_balloon: to a project easy.
- Enable beautiful and customizable Chat UI's.
- Provide an awesome Open Source project for the iOS open source community.
- Help others learn.
## Vision
See [VISION.md](https://github.com/MessageKit/MessageKit/blob/master/VISION.md) for Goals, Scope, & Technical Considerations.
## Installation
### [CocoaPods](https://cocoapods.org/) **Recomended**
````ruby
pod 'MessageKit'
````
## Requirements
- **iOS9** or later
## Contributing
Great! Look over these things first.
- Please read our [Code of Conduct](https://github.com/MessageKit/MessageKit/blob/master/Code_of_Conduct.md)
- Check the [Contributing Guide Lines](https://github.com/MessageKit/MessageKit/blob/master/CONTRIBUTING.md).
- Come join us on [Slack](https://join.slack.com/t/messagekit/shared_invite/MjI0NDkxNjgwMzA3LTE1MDIzMTU0MjUtMzJhZDZlNTkxMA) and 🗣 don't be a stranger.
- Check out the [current issues](https://github.com/MessageKit/MessageKit/issues) and see if you can tackle any of those.
- Download the project and check out the current code base. Suggest any improvements by opening a new issue.
- Check out the [What's Next](#what's-next) section :point_down: to see where we are headed.
- Check [StackOverflow](https://stackoverflow.com/questions/tagged/messagekit)
- Install [SwiftLint](https://github.com/realm/SwiftLint) too keep yourself in :neckbeard: style.
- Be kind and helpful.
## What's Next?
Check out the [Releases](https://github.com/MessageKit/MessageKit/releases) to see what we are working on next.
### Apps using this library
Add your app to the list of apps using this library and make a pull request.
*Please provide attribution, it is greatly appreciated.*
## Thanks
Many thanks to [**the contributors**](https://github.com/MessageKit/MessageKit/graphs/contributors) of this project.
## License
MessageKit is released under the [MIT License]().
## Inspiration
Inspired by [JSQMessagesViewController](https://github.com/jessesquires/JSQMessagesViewController) :point_left: :100:
+24 -7
View File
@@ -1,12 +1,29 @@
//
// Avatar.swift
// MessageKit
//
// Created by Dan Leonard on 8/7/17.
// Copyright © 2017 MessageKit. All rights reserved.
//
/*
MIT License
Copyright (c) 2017 MessageKit
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
import Foundation
public struct Avatar {
public let image: UIImage?
+5 -3
View File
@@ -25,9 +25,11 @@
import Foundation
open class AvatarView: UIView {
// MARK: - Properties
internal var avatar: Avatar = Avatar()
internal var imageView = UIImageView()
open var avatar: Avatar = Avatar()
open var imageView = UIImageView()
// MARK: - initializers
override init(frame: CGRect) {
@@ -41,7 +43,7 @@ open class AvatarView: UIView {
prepareView()
}
func getImageFrom(initals: String, withColor color: UIColor = UIColor.white, fontSize: CGFloat = 14) -> UIImage {
private func getImageFrom(initals: String, withColor color: UIColor = UIColor.white, fontSize: CGFloat = 14) -> UIImage {
_ = UIGraphicsBeginImageContext(CGSize(width: 30, height: 30))
let context = UIGraphicsGetCurrentContext()!
+1 -1
View File
@@ -95,7 +95,7 @@ open class InputTextView: UITextView {
}
fileprivate func addObservers() {
private func addObservers() {
NotificationCenter.default.addObserver(self,
selector: #selector(textDidChange),
name: Notification.Name.UITextViewTextDidChange,
+9 -9
View File
@@ -28,7 +28,7 @@ open class MessageCollectionViewCell: UICollectionViewCell {
// MARK: - Properties
open let messageContainerView: UIView = {
open var messageContainerView: UIView = {
let messageContainerView = UIView()
messageContainerView.layer.cornerRadius = 12.0
messageContainerView.layer.masksToBounds = true
@@ -98,29 +98,29 @@ open class MessageCollectionViewCell: UICollectionViewCell {
}
func cellTopLabelFrame(for attributes: MessagesCollectionViewLayoutAttributes) -> CGRect {
private func cellTopLabelFrame(for attributes: MessagesCollectionViewLayoutAttributes) -> CGRect {
var origin: CGPoint = .zero
if attributes.topLabelPinnedUnderMessage {
if !attributes.topLabelExtendsPastAvatar {
origin = CGPoint(x: attributes.avatarSize.width + attributes.avatarMessagePadding, y: 0)
}
return CGRect(origin: origin, size: attributes.cellTopLabelSize)
}
func cellBottomLabelFrame(for attributes: MessagesCollectionViewLayoutAttributes) -> CGRect {
private func cellBottomLabelFrame(for attributes: MessagesCollectionViewLayoutAttributes) -> CGRect {
var origin: CGPoint = CGPoint(x: 0, y: contentView.frame.height - attributes.cellBottomLabelSize.height)
if attributes.bottomLabelPinnedUnderMessage {
if !attributes.bottomLabelExtendsPastAvatar {
origin.x = attributes.avatarSize.width + attributes.avatarMessagePadding
}
return CGRect(origin: origin, size: attributes.cellBottomLabelSize)
}
func messageContainerFrame(for attributes: MessagesCollectionViewLayoutAttributes) -> CGRect {
private func messageContainerFrame(for attributes: MessagesCollectionViewLayoutAttributes) -> CGRect {
var origin: CGPoint = .zero
@@ -139,7 +139,7 @@ open class MessageCollectionViewCell: UICollectionViewCell {
}
func avatarViewFrame(for attributes: MessagesCollectionViewLayoutAttributes) -> CGRect {
private func avatarViewFrame(for attributes: MessagesCollectionViewLayoutAttributes) -> CGRect {
var origin: CGPoint = .zero
@@ -157,7 +157,7 @@ open class MessageCollectionViewCell: UICollectionViewCell {
}
func configure(with message: MessageType) {
public func configure(with message: MessageType) {
switch message.data {
case .text(let text):
@@ -168,7 +168,7 @@ open class MessageCollectionViewCell: UICollectionViewCell {
}
func setupGestureRecognizers() {
private func setupGestureRecognizers() {
let avatarTapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapAvatar))
avatarView.addGestureRecognizer(avatarTapGesture)
+1 -1
View File
@@ -22,7 +22,7 @@
SOFTWARE.
*/
public enum MessageDirection {
enum MessageDirection {
case incoming
case outgoing
+2 -4
View File
@@ -34,9 +34,7 @@ open class MessagesCollectionView: UICollectionView {
open weak var messageCellDelegate: MessageCellDelegate?
//open weak var messagesDisplayDataSource: MessagesDisplayDataSource?
var indexPathForLastItem: IndexPath? {
private var indexPathForLastItem: IndexPath? {
let lastSection = numberOfSections > 0 ? numberOfSections - 1 : 0
guard numberOfItems(inSection: lastSection) > 0 else { return nil }
@@ -57,7 +55,7 @@ open class MessagesCollectionView: UICollectionView {
// MARK: - Methods
func scrollToBottom(animated: Bool = false) {
public func scrollToBottom(animated: Bool = false) {
guard let indexPath = indexPathForLastItem else { return }
scrollToItem(at: indexPath, at: .bottom, animated: animated)
}
+37 -36
View File
@@ -1,18 +1,18 @@
/*
MIT License
Copyright (c) 2017 MessageKit
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -33,10 +33,10 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
open var messageToViewEdgePadding: CGFloat
open var cellTopLabelInsets: UIEdgeInsets
open var topLabelPinnedUnderMessage: Bool
open var topLabelExtendsPastAvatar: Bool
open var cellBottomLabelInsets: UIEdgeInsets
open var bottomLabelPinnedUnderMessage: Bool
open var bottomLabelExtendsPastAvatar: Bool
open var incomingAvatarSize: CGSize
open var outgoingAvatarSize: CGSize
@@ -66,10 +66,10 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
messageToViewEdgePadding = 30.0
cellTopLabelInsets = .zero
topLabelPinnedUnderMessage = true
topLabelExtendsPastAvatar = false
cellBottomLabelInsets = .zero
bottomLabelPinnedUnderMessage = true
bottomLabelExtendsPastAvatar = false
incomingAvatarSize = CGSize(width: 30, height: 30)
outgoingAvatarSize = CGSize(width: 30, height: 30)
@@ -126,11 +126,11 @@ open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
attributes.cellTopLabelSize = cellTopLabelSize(for: message, at: indexPath)
attributes.cellTopLabelInsets = cellTopLabelInsets
attributes.topLabelPinnedUnderMessage = topLabelPinnedUnderMessage
attributes.topLabelExtendsPastAvatar = topLabelExtendsPastAvatar
attributes.cellBottomLabelSize = cellBottomLabelSize(for: message, at: indexPath)
attributes.cellBottomLabelInsets = cellBottomLabelInsets
attributes.bottomLabelPinnedUnderMessage = bottomLabelPinnedUnderMessage
attributes.bottomLabelExtendsPastAvatar = bottomLabelExtendsPastAvatar
attributes.avatarSize = avatarSize(for: message)
attributes.avatarBottomPadding = avatarBottomPadding
@@ -159,7 +159,7 @@ extension MessagesCollectionViewFlowLayout {
// MARK: - Size Calculations
func avatarSize(for message: MessageType) -> CGSize {
fileprivate func avatarSize(for message: MessageType) -> CGSize {
guard let messagesCollectionView = messagesCollectionView else { return .zero }
guard let messagesDataSource = messagesCollectionView.messagesDataSource else { return .zero }
@@ -169,7 +169,7 @@ extension MessagesCollectionViewFlowLayout {
return isOutgoingMessage ? outgoingAvatarSize : incomingAvatarSize
}
func messageContainerSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
fileprivate func messageContainerSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
let messageWidth = messageContainerWidth(for: message, at: indexPath)
let messageHeight = messageContainerHeight(for: message, at: indexPath)
@@ -177,7 +177,7 @@ extension MessagesCollectionViewFlowLayout {
return CGSize(width: messageWidth, height: messageHeight)
}
func cellTopLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
fileprivate func cellTopLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
let topLabelWidth = cellTopLabelWidth(for: message)
let topLabelHeight = cellTopLabelHeight(for: message, at: indexPath)
@@ -186,7 +186,7 @@ extension MessagesCollectionViewFlowLayout {
}
func cellBottomLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
fileprivate func cellBottomLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
let bottomLabelWidth = cellBottomLabelWidth(for: message)
let bottomLabelHeight = cellBottomLabelHeight(for: message, at: indexPath)
@@ -197,23 +197,24 @@ extension MessagesCollectionViewFlowLayout {
// MARK: - Width Calculations
func cellTopLabelWidth(for message: MessageType) -> CGFloat {
if topLabelPinnedUnderMessage {
return itemWidth - avatarSize(for: message).width - avatarMessagePadding - messageToViewEdgePadding
} else {
private func cellTopLabelWidth(for message: MessageType) -> CGFloat {
if topLabelExtendsPastAvatar {
return itemWidth
} else {
return itemWidth - avatarSize(for: message).width - avatarMessagePadding - messageToViewEdgePadding
}
}
func cellBottomLabelWidth(for message: MessageType) -> CGFloat {
if bottomLabelPinnedUnderMessage {
return itemWidth - avatarSize(for: message).width - avatarMessagePadding - messageToViewEdgePadding
} else {
private func cellBottomLabelWidth(for message: MessageType) -> CGFloat {
if bottomLabelExtendsPastAvatar {
return itemWidth
} else {
return itemWidth - avatarSize(for: message).width - avatarMessagePadding - messageToViewEdgePadding
}
}
func availableWidthForMessageContainer(considering message: MessageType) -> CGFloat {
private func availableWidthForMessageContainer(considering message: MessageType) -> CGFloat {
let avatarWidth = avatarSize(for: message).width
let avatarWidthPlusPadding = avatarWidth == 0 ? 0 : avatarWidth + avatarMessagePadding
let horizontalMessageInsets = messageLabelInsets.left + messageLabelInsets.right
@@ -223,7 +224,7 @@ extension MessagesCollectionViewFlowLayout {
// MARK: - View Height Calculations
func cellTopLabelHeight(for message: MessageType, at indexPath: IndexPath) -> CGFloat {
private func cellTopLabelHeight(for message: MessageType, at indexPath: IndexPath) -> CGFloat {
guard let messagesCollectionView = messagesCollectionView else { return 0 }
guard let displayDataSource = messagesCollectionView.messagesDataSource as? MessagesDisplayDataSource else { return 0 }
@@ -237,7 +238,7 @@ extension MessagesCollectionViewFlowLayout {
}
func cellBottomLabelHeight(for message: MessageType, at indexPath: IndexPath) -> CGFloat {
private func cellBottomLabelHeight(for message: MessageType, at indexPath: IndexPath) -> CGFloat {
guard let messagesCollectionView = messagesCollectionView else { return 0 }
guard let displayDataSource = messagesCollectionView.messagesDataSource as? MessagesDisplayDataSource else { return 0 }
@@ -250,7 +251,7 @@ extension MessagesCollectionViewFlowLayout {
return estimatedHeight.rounded(.up)
}
func minimumCellHeight(for message: MessageType, at indexPath: IndexPath) -> CGFloat {
private func minimumCellHeight(for message: MessageType, at indexPath: IndexPath) -> CGFloat {
let size = avatarSize(for: message)
let avatarHeightPlusBottomPadding = size.height == 0 ? 0 : size.height + avatarBottomPadding
@@ -263,7 +264,7 @@ extension MessagesCollectionViewFlowLayout {
}
func messageContainerHeight(for message: MessageType, at indexPath: IndexPath) -> CGFloat {
private func messageContainerHeight(for message: MessageType, at indexPath: IndexPath) -> CGFloat {
let availableWidth = availableWidthForMessageContainer(considering: message)
let verticalMessageInsets = messageLabelInsets.top + messageLabelInsets.bottom
@@ -284,7 +285,7 @@ extension MessagesCollectionViewFlowLayout {
// MARK: - View Width Calculations
func messageContainerWidth(for message: MessageType, at indexPath: IndexPath) -> CGFloat {
private func messageContainerWidth(for message: MessageType, at indexPath: IndexPath) -> CGFloat {
let containerHeight = messageContainerHeight(for: message, at: indexPath)
let availableWidth = availableWidthForMessageContainer(considering: message)
@@ -308,7 +309,7 @@ extension MessagesCollectionViewFlowLayout {
// MARK: - Cell Size Calculations
func estimatedCellHeight(for message: MessageType, at indexPath: IndexPath) -> CGFloat {
private func estimatedCellHeight(for message: MessageType, at indexPath: IndexPath) -> CGFloat {
let containerHeight = messageContainerHeight(for: message, at: indexPath)
let topLabelHeight = cellTopLabelHeight(for: message, at: indexPath)
@@ -318,19 +319,19 @@ extension MessagesCollectionViewFlowLayout {
}
func sizeForItem(at indexPath: IndexPath) -> CGSize {
open func sizeForItem(at indexPath: IndexPath) -> CGSize {
guard let messagesCollectionView = messagesCollectionView else { return .zero }
guard let dataSource = messagesCollectionView.messagesDataSource else { return .zero }
let message = dataSource.messageForItem(at: indexPath, in: messagesCollectionView)
let minimumHeight = minimumCellHeight(for: message, at: indexPath)
let estimatedHeight = estimatedCellHeight(for: message, at: indexPath)
let finalHeight = estimatedHeight < minimumHeight ? minimumHeight : estimatedHeight
return CGSize(width: itemWidth, height: finalHeight)
}
}
@@ -35,11 +35,11 @@ final class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttrib
var cellTopLabelSize: CGSize = .zero
var cellTopLabelInsets: UIEdgeInsets = .zero
var topLabelPinnedUnderMessage = true
var topLabelExtendsPastAvatar = false
var cellBottomLabelSize: CGSize = .zero
var cellBottomLabelInsets: UIEdgeInsets = .zero
var bottomLabelPinnedUnderMessage = true
var bottomLabelExtendsPastAvatar = false
var avatarSize: CGSize = CGSize(width: 30, height: 30)
var avatarBottomPadding: CGFloat = 4.0
@@ -58,10 +58,10 @@ final class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttrib
copy.messageToViewEdgePadding = messageToViewEdgePadding
copy.cellTopLabelSize = cellTopLabelSize
copy.cellTopLabelInsets = cellTopLabelInsets
copy.topLabelPinnedUnderMessage = topLabelPinnedUnderMessage
copy.topLabelExtendsPastAvatar = topLabelExtendsPastAvatar
copy.cellBottomLabelSize = cellBottomLabelSize
copy.cellBottomLabelInsets = cellBottomLabelInsets
copy.bottomLabelPinnedUnderMessage = bottomLabelPinnedUnderMessage
copy.bottomLabelExtendsPastAvatar = bottomLabelExtendsPastAvatar
copy.avatarSize = avatarSize
copy.avatarBottomPadding = avatarBottomPadding
copy.avatarMessagePadding = avatarMessagePadding
+7 -7
View File
@@ -26,13 +26,13 @@ import Foundation
public protocol MessagesDisplayDataSource: class, MessagesDataSource {
func messageColorFor(_ message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor
func messageColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor
func avatarForMessage(_ message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> Avatar
func avatar(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> Avatar
func headerForMessage(_ message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageHeaderView?
func messageHeaderView(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageHeaderView?
func footerForMessage(_ message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageFooterView?
func messageFooterView(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageFooterView?
func cellTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString?
@@ -42,15 +42,15 @@ public protocol MessagesDisplayDataSource: class, MessagesDataSource {
public extension MessagesDisplayDataSource {
func messageColorFor(_ message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor {
func messageColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor {
return isFromCurrentSender(message: message) ? .outgoingGreen : .incomingGray
}
func headerForMessage(_ message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageHeaderView? {
func messageHeaderView(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageHeaderView? {
return nil
}
func footerForMessage(_ message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageFooterView? {
func messageFooterView(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageFooterView? {
return nil
}
+4 -4
View File
@@ -26,19 +26,19 @@ import Foundation
public protocol MessagesLayoutDelegate: class {
func headerSizeFor(_ message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize
func headerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize
func footerSizeFor(_ message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize
func footerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize
}
extension MessagesLayoutDelegate {
func headerSizeFor(_ message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
func headerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
return .zero
}
func footerSizeFor(_ message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
func footerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
return .zero
}
+6 -6
View File
@@ -165,8 +165,8 @@ extension MessagesViewController: UICollectionViewDataSource {
guard let displayDataSource = messagesDataSource as? MessagesDisplayDataSource else { return cell }
let message = displayDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
let messageColor = displayDataSource.messageColorFor(message, at: indexPath, in: messagesCollectionView)
let avatar = displayDataSource.avatarForMessage(message, at: indexPath, in: messagesCollectionView)
let messageColor = displayDataSource.messageColor(for: message, at: indexPath, in: messagesCollectionView)
let avatar = displayDataSource.avatar(for: message, at: indexPath, in: messagesCollectionView)
let topLabelText = displayDataSource.cellTopLabelAttributedText(for: message, at: indexPath)
let bottomLabelText = displayDataSource.cellBottomLabelAttributedText(for: message, at: indexPath)
@@ -189,9 +189,9 @@ extension MessagesViewController: UICollectionViewDataSource {
switch kind {
case UICollectionElementKindSectionHeader:
return displayDataSource.headerForMessage(message, at: indexPath, in: messagesCollectionView) ?? MessageHeaderView()
return displayDataSource.messageHeaderView(for: message, at: indexPath, in: messagesCollectionView) ?? MessageHeaderView()
case UICollectionElementKindSectionFooter:
return displayDataSource.footerForMessage(message, at: indexPath, in: messagesCollectionView) ?? MessageFooterView()
return displayDataSource.messageFooterView(for: message, at: indexPath, in: messagesCollectionView) ?? MessageFooterView()
default:
fatalError("Unrecognized element of kind: \(kind)")
}
@@ -205,7 +205,7 @@ extension MessagesViewController: UICollectionViewDataSource {
// Could pose a problem if subclass behaviors allows more than one item per section
let indexPath = IndexPath(item: 0, section: section)
let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
return messagesLayoutDelegate.headerSizeFor(message, at: indexPath, in: messagesCollectionView)
return messagesLayoutDelegate.headerViewSize(for: message, at: indexPath, in: messagesCollectionView)
}
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
@@ -215,7 +215,7 @@ extension MessagesViewController: UICollectionViewDataSource {
// Could pose a problem if subclass behaviors allows more than one item per section
let indexPath = IndexPath(item: 0, section: section)
let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
return messagesLayoutDelegate.footerSizeFor(message, at: indexPath, in: messagesCollectionView)
return messagesLayoutDelegate.footerViewSize(for: message, at: indexPath, in: messagesCollectionView)
}
}