mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 22:55:00 +00:00
Add 'submodules/AsyncDisplayKit/' from commit '02bedc12816e251ad71777f9d2578329b6d2bef6'
git-subtree-dir: submodules/AsyncDisplayKit git-subtree-mainline:d06f423e0egit-subtree-split:02bedc1281
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
|
||||
let window = UIWindow(frame: UIScreen.main.bounds)
|
||||
window.backgroundColor = UIColor.white
|
||||
window.rootViewController = UINavigationController(rootViewController: ViewController())
|
||||
window.makeKeyAndVisible()
|
||||
self.window = window
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
36
submodules/AsyncDisplayKit/examples/Swift/Sample/Info.plist
Normal file
36
submodules/AsyncDisplayKit/examples/Swift/Sample/Info.plist
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// TailLoadingCellNode.swift
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
import AsyncDisplayKit
|
||||
import UIKit
|
||||
|
||||
final class TailLoadingCellNode: ASCellNode {
|
||||
let spinner = SpinnerNode()
|
||||
let text = ASTextNode()
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
|
||||
addSubnode(text)
|
||||
text.attributedText = NSAttributedString(
|
||||
string: "Loading…",
|
||||
attributes: [
|
||||
NSFontAttributeName: UIFont.systemFont(ofSize: 12),
|
||||
NSForegroundColorAttributeName: UIColor.lightGray,
|
||||
NSKernAttributeName: -0.3
|
||||
])
|
||||
addSubnode(spinner)
|
||||
}
|
||||
|
||||
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
|
||||
|
||||
return ASStackLayoutSpec(
|
||||
direction: .horizontal,
|
||||
spacing: 16,
|
||||
justifyContent: .center,
|
||||
alignItems: .center,
|
||||
children: [ text, spinner ])
|
||||
}
|
||||
}
|
||||
|
||||
final class SpinnerNode: ASDisplayNode {
|
||||
var activityIndicatorView: UIActivityIndicatorView {
|
||||
return view as! UIActivityIndicatorView
|
||||
}
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
setViewBlock {
|
||||
UIActivityIndicatorView(activityIndicatorStyle: .gray)
|
||||
}
|
||||
|
||||
// Set spinner node to default size of the activitiy indicator view
|
||||
self.style.preferredSize = CGSize(width: 20.0, height: 20.0)
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
activityIndicatorView.startAnimating()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
//
|
||||
// ViewController.swift
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
|
||||
final class ViewController: ASViewController<ASDisplayNode>, ASTableDataSource, ASTableDelegate {
|
||||
|
||||
struct State {
|
||||
var itemCount: Int
|
||||
var fetchingMore: Bool
|
||||
static let empty = State(itemCount: 20, fetchingMore: false)
|
||||
}
|
||||
|
||||
enum Action {
|
||||
case beginBatchFetch
|
||||
case endBatchFetch(resultCount: Int)
|
||||
}
|
||||
|
||||
var tableNode: ASTableNode {
|
||||
return node as! ASTableNode
|
||||
}
|
||||
|
||||
fileprivate(set) var state: State = .empty
|
||||
|
||||
init() {
|
||||
super.init(node: ASTableNode())
|
||||
tableNode.delegate = self
|
||||
tableNode.dataSource = self
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("storyboards are incompatible with truth and beauty")
|
||||
}
|
||||
|
||||
// MARK: ASTableNode data source and delegate.
|
||||
|
||||
func tableNode(_ tableNode: ASTableNode, nodeForRowAt indexPath: IndexPath) -> ASCellNode {
|
||||
// Should read the row count directly from table view but
|
||||
// https://github.com/facebook/AsyncDisplayKit/issues/1159
|
||||
let rowCount = self.tableNode(tableNode, numberOfRowsInSection: 0)
|
||||
|
||||
if state.fetchingMore && indexPath.row == rowCount - 1 {
|
||||
let node = TailLoadingCellNode()
|
||||
node.style.height = ASDimensionMake(44.0)
|
||||
return node;
|
||||
}
|
||||
|
||||
let node = ASTextCellNode()
|
||||
node.text = String(format: "[%ld.%ld] says hello!", indexPath.section, indexPath.row)
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
func numberOfSections(in tableNode: ASTableNode) -> Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func tableNode(_ tableNode: ASTableNode, numberOfRowsInSection section: Int) -> Int {
|
||||
var count = state.itemCount
|
||||
if state.fetchingMore {
|
||||
count += 1
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func tableNode(_ tableNode: ASTableNode, willBeginBatchFetchWith context: ASBatchContext) {
|
||||
/// This call will come in on a background thread. Switch to main
|
||||
/// to add our spinner, then fire off our fetch.
|
||||
DispatchQueue.main.async {
|
||||
let oldState = self.state
|
||||
self.state = ViewController.handleAction(.beginBatchFetch, fromState: oldState)
|
||||
self.renderDiff(oldState)
|
||||
}
|
||||
|
||||
ViewController.fetchDataWithCompletion { resultCount in
|
||||
let action = Action.endBatchFetch(resultCount: resultCount)
|
||||
let oldState = self.state
|
||||
self.state = ViewController.handleAction(action, fromState: oldState)
|
||||
self.renderDiff(oldState)
|
||||
context.completeBatchFetching(true)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func renderDiff(_ oldState: State) {
|
||||
|
||||
self.tableNode.performBatchUpdates({
|
||||
|
||||
// Add or remove items
|
||||
let rowCountChange = state.itemCount - oldState.itemCount
|
||||
if rowCountChange > 0 {
|
||||
let indexPaths = (oldState.itemCount..<state.itemCount).map { index in
|
||||
IndexPath(row: index, section: 0)
|
||||
}
|
||||
tableNode.insertRows(at: indexPaths, with: .none)
|
||||
} else if rowCountChange < 0 {
|
||||
assertionFailure("Deleting rows is not implemented. YAGNI.")
|
||||
}
|
||||
|
||||
// Add or remove spinner.
|
||||
if state.fetchingMore != oldState.fetchingMore {
|
||||
if state.fetchingMore {
|
||||
// Add spinner.
|
||||
let spinnerIndexPath = IndexPath(row: state.itemCount, section: 0)
|
||||
tableNode.insertRows(at: [ spinnerIndexPath ], with: .none)
|
||||
} else {
|
||||
// Remove spinner.
|
||||
let spinnerIndexPath = IndexPath(row: oldState.itemCount, section: 0)
|
||||
tableNode.deleteRows(at: [ spinnerIndexPath ], with: .none)
|
||||
}
|
||||
}
|
||||
}, completion:nil)
|
||||
}
|
||||
|
||||
/// (Pretend) fetches some new items and calls the
|
||||
/// completion handler on the main thread.
|
||||
fileprivate static func fetchDataWithCompletion(_ completion: @escaping (Int) -> Void) {
|
||||
let time = DispatchTime.now() + Double(Int64(TimeInterval(NSEC_PER_SEC) * 1.0)) / Double(NSEC_PER_SEC)
|
||||
DispatchQueue.main.asyncAfter(deadline: time) {
|
||||
let resultCount = Int(arc4random_uniform(20))
|
||||
completion(resultCount)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate static func handleAction(_ action: Action, fromState state: State) -> State {
|
||||
var state = state
|
||||
switch action {
|
||||
case .beginBatchFetch:
|
||||
state.fetchingMore = true
|
||||
case let .endBatchFetch(resultCount):
|
||||
state.itemCount += resultCount
|
||||
state.fetchingMore = false
|
||||
}
|
||||
return state
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user