Skip to content

Commit

Permalink
Migrate to Swift 4 (#14)
Browse files Browse the repository at this point in the history
* Upgrate Podfile to Texture 2 and SlackTextViewController 1.9.6

* Migrate code to swift 4, Texture 2 and xcode 9

* Remove bridging header

* Add default collection delegate implementation
  • Loading branch information
qtdzz authored and nguyenhuy committed Mar 4, 2018
1 parent 6887f4c commit a2f4090
Show file tree
Hide file tree
Showing 19 changed files with 689 additions and 1,259 deletions.
1,697 changes: 543 additions & 1,154 deletions AsyncMessagesViewController.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Example/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window!.rootViewController = UINavigationController(rootViewController: ViewController())
window!.rootViewController = UINavigationController(rootViewController: ViewController()!)
window!.makeKeyAndVisible()

return true
Expand Down
13 changes: 9 additions & 4 deletions Example/Base.lproj/LaunchScreen.xib
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6254" systemVersion="14C109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
Expand All @@ -24,7 +29,7 @@
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
Expand Down
7 changes: 0 additions & 7 deletions Example/Example-Bridging-Header.h

This file was deleted.

15 changes: 15 additions & 0 deletions Example/Images.xcassets/AppIcon.appiconset/Contents.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
Expand Down Expand Up @@ -29,6 +39,11 @@
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
Expand Down
22 changes: 11 additions & 11 deletions Example/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@
//

import UIKit
import AsyncDisplayKit
import LoremIpsum

class ViewController: AsyncMessagesViewController, ASCollectionDelegate {
class ViewController: AsyncMessagesViewController {

private let users: [User]
private var currentUser: User? {
return users.filter({$0.ID == self.dataSource.currentUserID()}).first
}

init() {
init?() {
// Assume the default image size is used for message cell nodes
let avatarImageSize = CGSize(width: kAMMessageCellNodeAvatarImageSize, height: kAMMessageCellNodeAvatarImageSize)
users = (0..<5).map() {
Expand All @@ -24,14 +26,13 @@ class ViewController: AsyncMessagesViewController, ASCollectionDelegate {
}

let dataSource = DefaultAsyncMessagesCollectionViewDataSource(currentUserID: users[0].ID)
super.init(dataSource: dataSource)

collectionView.asyncDelegate = self
let delegate = DefaultAsyncMessagesCollectionViewDelegate()
super.init(dataSource: dataSource, delegate: delegate)
}

deinit {
// Tell ASCollectionView that this object is being deallocated (Issue #4)
collectionView.asyncDelegate = nil
asyncCollectionNode.delegate = nil
}

required init(coder aDecoder: NSCoder) {
Expand All @@ -55,7 +56,7 @@ class ViewController: AsyncMessagesViewController, ASCollectionDelegate {
content: textView.text,
date: Date(),
sender: user)
dataSource.collectionView(collectionView: collectionView, insertMessages: [message]) {completed in
dataSource.collectionNode(collectionNode: asyncCollectionNode, insertMessages: [message]) {completed in
self.scrollCollectionViewToBottom()
}
}
Expand Down Expand Up @@ -86,14 +87,13 @@ class ViewController: AsyncMessagesViewController, ASCollectionDelegate {
sender: sender)
messages.append(message)
}
dataSource.collectionView(collectionView: collectionView, insertMessages: messages, completion: nil)
dataSource.collectionNode(collectionNode: asyncCollectionNode, insertMessages: messages, completion: nil)
}

func changeCurrentUser() {
@objc func changeCurrentUser() {
let otherUsers = users.filter({$0.ID != self.dataSource.currentUserID()})
let newUser = otherUsers[Int(arc4random_uniform(UInt32(otherUsers.count)))]
dataSource.collectionView(collectionView: collectionView, updateCurrentUserID: newUser.ID)
dataSource.collectionNode(collectionNode: asyncCollectionNode, updateCurrentUserID: newUser.ID)
}

}

14 changes: 8 additions & 6 deletions Podfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
source 'https://github.com/CocoaPods/Specs.git'

platform :ios, '8.0'
platform :ios, '9.0'
target 'Example' do
use_frameworks!

pod 'AsyncDisplayKit', '1.9.90'
pod 'SlackTextViewController', '1.9.5'

# Used by example target
pod 'LoremIpsum', :git => 'https://github.com/nguyenhuy/LoremIpsum.git', :branch => 'master'
pod 'Texture', '2.6'
pod 'SlackTextViewController', '1.9.6'

# Used by example target
pod 'LoremIpsum', :git => 'https://github.com/nguyenhuy/LoremIpsum.git', :branch => 'master'
end
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@
//

import Foundation
import AsyncDisplayKit

//TODO revise method name to adhere to Swift 3 convention
protocol AsyncMessagesCollectionViewDataSource: ASCollectionDataSource {

func currentUserID() -> String?

func collectionView(collectionView: ASCollectionView, updateCurrentUserID newUserID: String?)
func collectionNode(collectionNode: ASCollectionNode, updateCurrentUserID newUserID: String?)

func collectionView(collectionView: ASCollectionView, messageForItemAtIndexPath indexPath: IndexPath) -> MessageData
func collectionNode(collectionNode: ASCollectionNode, messageForItemAtIndexPath indexPath: IndexPath) -> MessageData

func collectionView(collectionView: ASCollectionView, insertMessages newMessages: [MessageData], completion: ((Bool) -> ())?)
func collectionNode(collectionNode: ASCollectionNode, insertMessages newMessages: [MessageData], completion: ((Bool) -> ())?)

func collectionView(collectionView: ASCollectionView, deleteMessagesAtIndexPaths indexPaths: [IndexPath], completion: ((Bool) -> ())?)
func collectionNode(collectionNode: ASCollectionNode, deleteMessagesAtIndexPaths indexPaths: [IndexPath], completion: ((Bool) -> ())?)

}
23 changes: 15 additions & 8 deletions Source/Controllers/AsyncMessagesViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,31 @@
//

import Foundation
import AsyncDisplayKit
import SlackTextViewController

class AsyncMessagesViewController: SLKTextViewController {

let dataSource: AsyncMessagesCollectionViewDataSource
let delegate: ASCollectionDelegate
let asyncCollectionNode: ASCollectionNode
override var collectionView: ASCollectionView {
return scrollView as! ASCollectionView
}

init(dataSource: AsyncMessagesCollectionViewDataSource) {
init?(dataSource: AsyncMessagesCollectionViewDataSource, delegate: ASCollectionDelegate) {
self.dataSource = dataSource

self.delegate = delegate
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = UICollectionViewScrollDirection.vertical
let asyncCollectionView = ASCollectionView(frame: CGRect.zero, collectionViewLayout: layout)

asyncCollectionNode = ASCollectionNode(collectionViewLayout: layout)
let asyncCollectionView = asyncCollectionNode.view

asyncCollectionView.backgroundColor = UIColor.white
asyncCollectionView.scrollsToTop = true
asyncCollectionView.asyncDataSource = dataSource

asyncCollectionNode.dataSource = dataSource
asyncCollectionNode.delegate = delegate
super.init(scrollView: asyncCollectionView)

isInverted = false
Expand All @@ -36,17 +43,17 @@ class AsyncMessagesViewController: SLKTextViewController {

override func viewWillLayoutSubviews() {
let insets = UIEdgeInsetsMake(topLayoutGuide.length, 0, 5, 0)
collectionView.contentInset = insets
asyncCollectionNode.contentInset = insets
collectionView.scrollIndicatorInsets = insets

super.viewWillLayoutSubviews()
}

func scrollCollectionViewToBottom() {
let numberOfItems = dataSource.collectionView(collectionView, numberOfItemsInSection: 0)
let numberOfItems = dataSource.collectionNode!(asyncCollectionNode, numberOfItemsInSection: 0)
if numberOfItems > 0 {
let lastItemIndexPath = IndexPath(item: numberOfItems - 1, section: 0)
collectionView.scrollToItem(at: lastItemIndexPath, at: .bottom, animated: true)
asyncCollectionNode.scrollToItem(at: lastItemIndexPath, at: .bottom, animated: true)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import Foundation
import AsyncDisplayKit

class DefaultAsyncMessagesCollectionViewDataSource: NSObject, AsyncMessagesCollectionViewDataSource {

Expand Down Expand Up @@ -36,15 +37,14 @@ class DefaultAsyncMessagesCollectionViewDataSource: NSObject, AsyncMessagesColle
nodeMetadatas = []
}

//MARK: ASCollectionViewDataSource methods
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//MARK: ASCollectionDataSource methods
func collectionNode(_ collectionNode: ASCollectionNode, numberOfItemsInSection section: Int) -> Int {
assert(nodeMetadatas.count == messages.count, "Node metadata is required for each message.")
return messages.count
}

//TODO Use node block
func collectionView(_ collectionView: ASCollectionView, nodeForItemAt indexPath: IndexPath) -> ASCellNode {
let message = self.collectionView(collectionView: collectionView, messageForItemAtIndexPath: indexPath)
func collectionNode(_ collectionNode: ASCollectionNode, nodeBlockForItemAt indexPath: IndexPath) -> ASCellNodeBlock {
let message = self.collectionNode(collectionNode: collectionNode, messageForItemAtIndexPath: indexPath)
let metadata = nodeMetadatas[indexPath.item]
let isOutgoing = metadata.isOutgoing

Expand All @@ -59,18 +59,20 @@ class DefaultAsyncMessagesCollectionViewDataSource: NSObject, AsyncMessagesColle
let bubbleImage = bubbleImageProvider.bubbleImage(isOutgoing: isOutgoing, hasTail: metadata.showsTailForBubbleImage)
assert(bubbleNodeFactories.index(forKey: message.contentType()) != nil, "No bubble node factory for content type: \(message.contentType())")
let bubbleNode = bubbleNodeFactories[message.contentType()]!.build(message: message, isOutgoing: isOutgoing, bubbleImage: bubbleImage)

let cellNode = MessageCellNode(
isOutgoing: isOutgoing,
topText: messageDate,
contentTopText: senderDisplayName,
bottomText: nil,
senderAvatarURL: senderAvatarURL,
bubbleNode: bubbleNode)

return cellNode

let cellNodeBlock:() -> ASCellNode = {
let cellNode = MessageCellNode(
isOutgoing: isOutgoing,
topText: messageDate,
contentTopText: senderDisplayName,
bottomText: nil,
senderAvatarURL: senderAvatarURL,
bubbleNode: bubbleNode)
return cellNode
}
return cellNodeBlock
}

func collectionView(_ collectionView: ASCollectionView, constrainedSizeForNodeAt indexPath: IndexPath) -> ASSizeRange {
let width = collectionView.bounds.width;
// Assume horizontal scroll directions
Expand All @@ -82,7 +84,7 @@ class DefaultAsyncMessagesCollectionViewDataSource: NSObject, AsyncMessagesColle
return _currentUserID
}

func collectionView(collectionView: ASCollectionView, updateCurrentUserID newUserID: String?) {
func collectionNode(collectionNode: ASCollectionNode, updateCurrentUserID newUserID: String?) {
if newUserID == _currentUserID {
return
}
Expand All @@ -94,15 +96,14 @@ class DefaultAsyncMessagesCollectionViewDataSource: NSObject, AsyncMessagesColle
nodeMetadatas = updatedMetadatas

let reloadIndicies = Array<MessageCellNodeMetadata>.computeDiff(lhs: outdatedMetadatas, rhs: updatedMetadatas)
collectionView.reloadItems(at: IndexPath.createIndexPaths(section: 0, items: reloadIndicies))
collectionNode.reloadItems(at: IndexPath.createIndexPaths(section: 0, items: reloadIndicies))
}

func collectionView(collectionView: ASCollectionView, messageForItemAtIndexPath indexPath: IndexPath) -> MessageData {
func collectionNode(collectionNode: ASCollectionNode, messageForItemAtIndexPath indexPath: IndexPath) -> MessageData {
return messages[indexPath.item]
}

func collectionView(collectionView: ASCollectionView, insertMessages newMessages: [MessageData], completion: ((Bool) -> ())?) {

func collectionNode(collectionNode: ASCollectionNode, insertMessages newMessages: [MessageData], completion: ((Bool) -> ())?) {
if newMessages.isEmpty {
return
}
Expand All @@ -126,18 +127,17 @@ class DefaultAsyncMessagesCollectionViewDataSource: NSObject, AsyncMessagesColle
}
let reloadIndicies = Array<MessageCellNodeMetadata>.computeDiff(lhs: outdatedNodeMetadatas, rhs: updatedNodeMetadatas)

collectionView.performBatchUpdates(
collectionNode.performBatchUpdates(
{
collectionView.insertItems(at: IndexPath.createIndexPaths(section: 0, items: insertedIndices))
collectionNode.insertItems(at: IndexPath.createIndexPaths(section: 0, items: insertedIndices))
if !reloadIndicies.isEmpty {
collectionView.reloadItems(at: IndexPath.createIndexPaths(section: 0, items: reloadIndicies))
collectionNode.reloadItems(at: IndexPath.createIndexPaths(section: 0, items: reloadIndicies))
}
},
},
completion: completion)
}


func collectionView(collectionView: ASCollectionView, deleteMessagesAtIndexPaths indexPaths: [IndexPath], completion: ((Bool) -> ())?) {
func collectionNode(collectionNode: ASCollectionNode, deleteMessagesAtIndexPaths indexPaths: [IndexPath], completion: ((Bool) -> ())?) {
if indexPaths.isEmpty {
return
}
Expand All @@ -158,13 +158,13 @@ class DefaultAsyncMessagesCollectionViewDataSource: NSObject, AsyncMessagesColle

let reloadIndicies = Array<MessageCellNodeMetadata>.computeDiff(lhs: outdatedNodesMetadata, rhs: updatedNodeMetadatas)

collectionView.performBatchUpdates(
collectionNode.performBatchUpdates(
{
collectionView.deleteItems(at: sortedIndexPaths)
collectionNode.deleteItems(at: sortedIndexPaths)
if !reloadIndicies.isEmpty {
collectionView.reloadItems(at: IndexPath.createIndexPaths(section: 0, items: reloadIndicies))
collectionNode.reloadItems(at: IndexPath.createIndexPaths(section: 0, items: reloadIndicies))
}
},
},
completion: completion)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// DefaultAsyncMessageDelegate.swift
// Example
//
// Created by Tien Nguyen on 3/4/18.
// Copyright © 2018 Huy Nguyen. All rights reserved.
//

import AsyncDisplayKit

class DefaultAsyncMessagesCollectionViewDelegate: NSObject, ASCollectionDelegate {

func collectionNode(_ collectionNode: ASCollectionNode, constrainedSizeForItemAt indexPath: IndexPath) -> ASSizeRange {
let width = collectionNode.bounds.width;
return ASSizeRangeMake(CGSize(width: width, height: 0), CGSize(width: width, height: CGFloat.greatestFiniteMagnitude))
}
}
2 changes: 1 addition & 1 deletion Source/Controllers/MessageBubbleImageProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Copyright (c) 2014 Huy Nguyen. All rights reserved.
//

import Foundation
import UIKit

private struct MessageProperties: Hashable {
let isOutgoing: Bool
Expand Down
Loading

0 comments on commit a2f4090

Please sign in to comment.