Merge branch 'master' into development

This commit is contained in:
Steven Deutsch
2017-11-10 07:47:39 -06:00
36 changed files with 102 additions and 70 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

@@ -3,109 +3,109 @@
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "mklogo-20@2x.png",
"filename" : "30243544-20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "mklogo-20@3x.png",
"filename" : "30243544-20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "mklogo-29@2x.png",
"filename" : "30243544-29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "mklogo-29@3x.png",
"filename" : "30243544-29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "mklogo-40@2x.png",
"filename" : "30243544-40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "mklogo-40@3x.png",
"filename" : "30243544-40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "mklogo-60@2x.png",
"filename" : "30243544-60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "mklogo-60@3x.png",
"filename" : "30243544-60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "mklogo-20.png",
"filename" : "30243544-20.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "mklogo-20@2x.png",
"filename" : "30243544-20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "mklogo-29.png",
"filename" : "30243544-29.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "mklogo-29@2x.png",
"filename" : "30243544-29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "mklogo-40.png",
"filename" : "30243544-40.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "mklogo-40@2x.png",
"filename" : "30243544-40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "mklogo-76.png",
"filename" : "30243544-76.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "mklogo-76@2x.png",
"filename" : "30243544-76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "mklogo-83.5@2x.png",
"filename" : "30243544-83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "mklogo-1024.png",
"filename" : "30243544-1024.png",
"scale" : "1x"
}
],
Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "30243544.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13196" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13173"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13527"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -26,7 +26,7 @@
<rect key="frame" x="32" y="98" width="310" height="171"/>
</imageView>
</subviews>
<color key="backgroundColor" red="0.99989169840000003" green="1" blue="0.99988096950000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="backgroundColor" red="0.24325716495513916" green="0.76319533586502075" blue="0.32751965522766113" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="NHX-yN-7Jk" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leadingMargin" constant="16" id="ak3-MI-1bZ"/>
<constraint firstItem="NHX-yN-7Jk" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="ebx-nK-jHq"/>
+1 -1
View File
@@ -176,7 +176,7 @@ final class SampleData {
func getMessages(count: Int, completion: ([MockMessage]) -> Void) {
var messages: [MockMessage] = []
for _ in 0...count {
for _ in 0..<count {
messages.append(randomMessage())
}
completion(messages)
@@ -152,6 +152,26 @@ extension MessagesViewController: UICollectionViewDelegateFlowLayout {
guard let messagesFlowLayout = collectionViewLayout as? MessagesCollectionViewFlowLayout else { return .zero }
return messagesFlowLayout.sizeForItem(at: indexPath)
}
open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
guard let messagesCollectionView = collectionView as? MessagesCollectionView else { return .zero }
guard let messagesDataSource = messagesCollectionView.messagesDataSource else { return .zero }
guard let messagesLayoutDelegate = messagesCollectionView.messagesLayoutDelegate else { return .zero }
// 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.headerViewSize(for: message, at: indexPath, in: messagesCollectionView)
}
open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
guard let messagesCollectionView = collectionView as? MessagesCollectionView else { return .zero }
guard let messagesDataSource = messagesCollectionView.messagesDataSource else { return .zero }
guard let messagesLayoutDelegate = messagesCollectionView.messagesLayoutDelegate else { return .zero }
// 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.footerViewSize(for: message, at: indexPath, in: messagesCollectionView)
}
}
@@ -230,27 +250,7 @@ extension MessagesViewController: UICollectionViewDataSource {
}
}
open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
guard let messagesCollectionView = collectionView as? MessagesCollectionView else { return .zero }
guard let messagesDataSource = messagesCollectionView.messagesDataSource else { return .zero }
guard let messagesLayoutDelegate = messagesCollectionView.messagesLayoutDelegate else { return .zero }
// 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.headerViewSize(for: message, at: indexPath, in: messagesCollectionView)
}
open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
guard let messagesCollectionView = collectionView as? MessagesCollectionView else { return .zero }
guard let messagesDataSource = messagesCollectionView.messagesDataSource else { return .zero }
guard let messagesLayoutDelegate = messagesCollectionView.messagesLayoutDelegate else { return .zero }
// 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.footerViewSize(for: message, at: indexPath, in: messagesCollectionView)
}
}
// MARK: - Keyboard Handling
+2 -2
View File
@@ -183,8 +183,8 @@ open class InputBarButtonItem: UIButton {
open func setSize(_ newValue: CGSize?, animated: Bool) {
size = newValue
if animated, let position = parentStackViewPosition {
messageInputBar?.performLayout(animated) {
self.messageInputBar?.layoutStackViews([position])
messageInputBar?.performLayout(animated) { [weak self] in
self?.messageInputBar?.layoutStackViews([position])
}
}
}
+36 -25
View File
@@ -49,7 +49,7 @@ open class MessageLabel: UILabel, UIGestureRecognizerDelegate {
return textStorage
}()
private lazy var rangesForDetectors: [DetectorType: [(NSRange, Any?)]] = [:]
private lazy var rangesForDetectors: [DetectorType: [(NSRange, MessageTextCheckingType)]] = [:]
// MARK: - Public Properties
@@ -321,13 +321,13 @@ open class MessageLabel: UILabel, UIGestureRecognizerDelegate {
private func detectorAttributes(for checkingResultType: NSTextCheckingResult.CheckingType) -> [NSAttributedStringKey: Any] {
switch checkingResultType {
case NSTextCheckingResult.CheckingType.address:
case .address:
return addressAttributes
case NSTextCheckingResult.CheckingType.date:
case .date:
return dateAttributes
case NSTextCheckingResult.CheckingType.phoneNumber:
case .phoneNumber:
return phoneNumberAttributes
case NSTextCheckingResult.CheckingType.link:
case .link:
return urlAttributes
default:
fatalError("Received an unrecognized NSTextCheckingResult.CheckingType")
@@ -349,24 +349,24 @@ open class MessageLabel: UILabel, UIGestureRecognizerDelegate {
for result in checkingResults {
switch result.resultType {
case NSTextCheckingResult.CheckingType.address:
case .address:
var ranges = rangesForDetectors[.address] ?? []
let tuple = (result.range, result.addressComponents) as (NSRange, Any?)
let tuple: (NSRange, MessageTextCheckingType) = (result.range, .addressComponents(result.addressComponents))
ranges.append(tuple)
rangesForDetectors.updateValue(ranges, forKey: .address)
case NSTextCheckingResult.CheckingType.date:
case .date:
var ranges = rangesForDetectors[.date] ?? []
let tuple = (result.range, result.date) as (NSRange, Any?)
let tuple: (NSRange, MessageTextCheckingType) = (result.range, .date(result.date))
ranges.append(tuple)
rangesForDetectors.updateValue(ranges, forKey: .date)
case NSTextCheckingResult.CheckingType.phoneNumber:
case .phoneNumber:
var ranges = rangesForDetectors[.phoneNumber] ?? []
let tuple = (result.range, result.phoneNumber) as (NSRange, Any?)
let tuple: (NSRange, MessageTextCheckingType) = (result.range, .phoneNumber(result.phoneNumber))
ranges.append(tuple)
rangesForDetectors.updateValue(ranges, forKey: .phoneNumber)
case NSTextCheckingResult.CheckingType.link:
case .link:
var ranges = rangesForDetectors[.url] ?? []
let tuple = (result.range, result.url) as (NSRange, Any?)
let tuple: (NSRange, MessageTextCheckingType) = (result.range, .link(result.url))
ranges.append(tuple)
rangesForDetectors.updateValue(ranges, forKey: .url)
default:
@@ -428,20 +428,24 @@ open class MessageLabel: UILabel, UIGestureRecognizerDelegate {
}
}
private func handleGesture(for detectorType: DetectorType, value: Any?) {
switch detectorType {
case .address:
guard let addressComponents = value as? [String: String] else { return }
handleAddress(addressComponents)
case .phoneNumber:
guard let phoneNumber = value as? String else { return }
private func handleGesture(for detectorType: DetectorType, value: MessageTextCheckingType) {
switch value {
case let .addressComponents(addressComponents):
var transformedAddressComponents = [String: String]()
guard let addressComponents = addressComponents else { return }
addressComponents.forEach { (key, value) in
transformedAddressComponents[key.rawValue] = value
}
handleAddress(transformedAddressComponents)
case let .phoneNumber(phoneNumber):
guard let phoneNumber = phoneNumber else { return }
handlePhoneNumber(phoneNumber)
case .date:
guard let date = value as? Date else { return }
case let .date(date):
guard let date = date else { return }
handleDate(date)
case .url:
guard let url = value as? URL else { return }
case let .link(url):
guard let url = url else { return }
handleURL(url)
}
}
@@ -463,3 +467,10 @@ open class MessageLabel: UILabel, UIGestureRecognizerDelegate {
}
}
fileprivate enum MessageTextCheckingType {
case addressComponents([NSTextCheckingKey: String]?)
case date(Date?)
case phoneNumber(String?)
case link(URL?)
}