├── .swift-version
├── _Pods.xcodeproj
├── docs
├── _config.yml
└── demo.gif
├── .swiftlint.yml
├── Example
├── RxPager
│ ├── AppDelegate.swift
│ ├── Images.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Info.plist
│ ├── PagerTableViewController.swift
│ └── Base.lproj
│ │ ├── LaunchScreen.xib
│ │ └── Main.storyboard
├── RxPager.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ ├── xcshareddata
│ │ └── xcschemes
│ │ │ └── RxPager-Example.xcscheme
│ └── project.pbxproj
├── Podfile
├── RxPager.xcworkspace
│ └── contents.xcworkspacedata
├── README.md
├── Tests
│ ├── Info.plist
│ └── Tests.swift
└── Podfile.lock
├── Makefile
├── RxPager.playground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
├── contents.xcplayground
└── Contents.swift
├── .gitignore
├── RxPager.podspec
├── .travis.yml
├── LICENSE
├── README.md
└── RxPager
└── Classes
└── RxPager.swift
/.swift-version:
--------------------------------------------------------------------------------
1 | 4.0
2 |
--------------------------------------------------------------------------------
/_Pods.xcodeproj:
--------------------------------------------------------------------------------
1 | Example/Pods/Pods.xcodeproj
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-minimal
--------------------------------------------------------------------------------
/docs/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RxSwiftCommunity/RxPager/HEAD/docs/demo.gif
--------------------------------------------------------------------------------
/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | excluded:
2 | - Example/Pods/RxSwift
3 | - Example/Pods/RxCocoa
4 | line_length:
5 | - 110
6 | disabled_rules:
7 | - variable_name
--------------------------------------------------------------------------------
/Example/RxPager/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | @UIApplicationMain
4 | class AppDelegate: UIResponder, UIApplicationDelegate {
5 | var window: UIWindow?
6 | }
7 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # Install Tasks
2 |
3 | install-lint:
4 | brew install swiftlint
5 |
6 | # Run Tasks
7 | publish:
8 | pod trunk push RxPager.podspec
9 |
10 | lint:
11 | swiftlint lint --strict 2>/dev/null
12 |
--------------------------------------------------------------------------------
/RxPager.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/RxPager.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Example/RxPager.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/Podfile:
--------------------------------------------------------------------------------
1 | platform :"ios", "9.0"
2 | source 'https://github.com/CocoaPods/Specs.git'
3 | use_frameworks!
4 |
5 | target 'RxPager_Example' do
6 | pod 'RxCocoa', '~> 6.5'
7 | pod 'RxPager', :path => '../'
8 | end
9 |
10 | target 'RxPager_Tests' do
11 | inherit! :search_paths
12 | pod 'RxCocoa', '~> 6.5'
13 | pod 'RxPager', :path => '../'
14 | end
15 |
--------------------------------------------------------------------------------
/Example/RxPager.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS X
2 | .DS_Store
3 |
4 | # Xcode
5 | build/
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | xcuserdata/
15 | *.xccheckout
16 | profile
17 | *.moved-aside
18 | DerivedData
19 | *.hmap
20 | *.ipa
21 |
22 | # AppCode
23 | .idea/
24 |
25 | # Bundler
26 | .bundle
27 |
28 | Pods/
29 |
--------------------------------------------------------------------------------
/RxPager.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "RxPager"
3 | s.version = "3.0.0"
4 | s.summary = "A simple Pager class fo Rx."
5 | s.homepage = "https://github.com/pgherveou/RxPager"
6 | s.license = 'MIT'
7 | s.author = { "Pierre-Guillaume Herveou" => "pgherveou@gmail.com" }
8 | s.source = { :git => "https://github.com/RxSwiftCommunity/RxPager.git", :tag => s.version.to_s }
9 | s.social_media_url = 'https://twitter.com/pgherveou'
10 | s.ios.deployment_target = '9.0'
11 | s.source_files = 'RxPager/Classes/**/*'
12 | s.dependency 'RxSwift', "~> 6.5"
13 | end
14 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # references:
2 | # * http://www.objc.io/issue-6/travis-ci.html
3 | # * https://github.com/supermarin/xcpretty#usage
4 |
5 | language: objective-c
6 | osx_image: xcode9
7 | xcode_sdk: iphonesimulator11.0
8 | before_install:
9 | - gem install cocoapods xcpretty --no-rdoc --no-ri --no-document --quiet
10 | - pod install --project-directory=Example --repo-update
11 | script:
12 | - set -o pipefail && xcodebuild -workspace Example/RxPager.xcworkspace -scheme RxPager-Example -configuration 'Debug' -destination 'platform=iOS Simulator,name=iPhone 7,OS=11.0' -sdk iphonesimulator build test | xcpretty -c
13 | - pod lib lint
14 |
--------------------------------------------------------------------------------
/Example/README.md:
--------------------------------------------------------------------------------
1 | # Demo App
2 |
3 | Build and Run the RxPager-Example target from Xcode.
4 | The demo app display a simple tableview with a paged datasource
5 |
6 | 
7 |
8 | ```swift
9 | override func viewDidLoad() {
10 | super.viewDidLoad()
11 |
12 | // scan, and update dataSource
13 | page
14 | .scan([Int](), accumulator: +)
15 | .subscribe(onNext: { [weak self] in self?.dataSource = $0 })
16 | .addDisposableTo(disposeBag)
17 |
18 | // update dataSource and reset the animating flag, when the stream complete
19 | page
20 | .subscribe(onCompleted: { [weak self] in
21 | self?.showAnimatingCell = false
22 | self?.tableView.reloadData()
23 | })
24 | .addDisposableTo(disposeBag)
25 | }
26 | ```
27 |
--------------------------------------------------------------------------------
/Example/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Example/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - RxCocoa (6.5.0):
3 | - RxRelay (= 6.5.0)
4 | - RxSwift (= 6.5.0)
5 | - RxPager (3.0.0):
6 | - RxSwift (~> 6.5)
7 | - RxRelay (6.5.0):
8 | - RxSwift (= 6.5.0)
9 | - RxSwift (6.5.0)
10 |
11 | DEPENDENCIES:
12 | - RxCocoa (~> 6.5)
13 | - RxPager (from `../`)
14 |
15 | SPEC REPOS:
16 | https://github.com/CocoaPods/Specs.git:
17 | - RxCocoa
18 | - RxRelay
19 | - RxSwift
20 |
21 | EXTERNAL SOURCES:
22 | RxPager:
23 | :path: "../"
24 |
25 | SPEC CHECKSUMS:
26 | RxCocoa: 94f817b71c07517321eb4f9ad299112ca8af743b
27 | RxPager: 39fd914ee24fd457f398d2998265d43ea5a49af9
28 | RxRelay: 1de1523e604c72b6c68feadedd1af3b1b4d0ecbd
29 | RxSwift: 5710a9e6b17f3c3d6e40d6e559b9fa1e813b2ef8
30 |
31 | PODFILE CHECKSUM: fa5c2eeb4e75740eb58ccdc26b2ec2abc03053ee
32 |
33 | COCOAPODS: 1.11.0
34 |
--------------------------------------------------------------------------------
/Example/RxPager/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | }
43 | ],
44 | "info" : {
45 | "version" : 1,
46 | "author" : "xcode"
47 | }
48 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 RxSwiftCommunity
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Example/RxPager/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/RxPager.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | import PlaygroundSupport
2 | import RxSwift
3 | import RxPager
4 |
5 | PlaygroundPage.current.needsIndefiniteExecution = true
6 |
7 | // MARK: Example 1
8 |
9 | typealias Page = [Int]
10 | typealias Callback = () -> Void
11 |
12 | // take previous Page, and create next one
13 | let nextPage = { (previousPage: Page?) -> Observable in
14 | let last = previousPage?.last ?? 0
15 | return Observable.just([last + 1, last + 2, last + 3])
16 | }
17 |
18 | // return true if there are more pages to be emitted
19 | let hasNext = { (page: Page) -> Bool in
20 | guard let last = page.last else { return true }
21 | return last < 10 // arbitrary condition for the demo
22 | }
23 |
24 | // create the pager
25 | let trigger = PublishSubject()
26 | let page$ = Observable.page(make: nextPage, while: hasNext, when: trigger)
27 | let next = trigger.onNext
28 |
29 | page$.subscribe(onNext: { print($0) })
30 | // print [1, 2 ,3]
31 |
32 | next(()) // print [4, 5, 6]
33 | next(()) // print [7, 8, 9]
34 | next(()) // print [10, 11, 12]
35 |
36 | // MARK: Example 2 (page from array)
37 |
38 | Observable
39 | .page(Array(1...10), by: 3, when: trigger)
40 | .subscribe(onNext: { print($0) })
41 |
42 | // print [1, 2 ,3]
43 | next(()) // print [4, 5, 6]
44 | next(()) // print [4, 5, 6]
45 | next(()) // print [10]
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RxPager
2 |
3 | [](https://travis-ci.org/RxSwiftCommunity/RxPager)
4 | [](http://cocoapods.org/pods/RxPager)
5 | [](http://cocoapods.org/pods/RxPager)
6 | [](http://cocoapods.org/pods/RxPager)
7 |
8 | ## Usage
9 |
10 | ```swift
11 | // MARK: Example 1
12 |
13 | typealias Page = [Int]
14 | typealias Callback = () -> Void
15 |
16 | // take previous Page, and create next one
17 | let nextPage = { (previousPage: Page?) -> Observable in
18 | let last = previousPage?.last ?? 0
19 | return Observable.just([last + 1, last + 2, last + 3])
20 | }
21 |
22 | // return true if there are more pages to be emitted
23 | let hasNext = { (page: Page) -> Bool in
24 | guard let last = page.last else { return true }
25 | return last < 10 // arbitrary condition for the demo
26 | }
27 |
28 | // create the pager
29 | let trigger = PublishSubject()
30 | let page$ = Observable.page(nextPage, while: hasNext, when: trigger)
31 | let next = trigger.onNext
32 |
33 | page$.subscribe(onNext: { print($0) })
34 | // print [1, 2 ,3]
35 |
36 | next() // print [4, 5, 6]
37 | next() // print [7, 8, 9]
38 | next() // print [10, 11, 12]
39 |
40 | // MARK: Example 2 (page from array)
41 |
42 | Observable
43 | .page(Array(1...10), by: 3, when: trigger)
44 | .subscribe(onNext: { print($0) })
45 |
46 | // print [1, 2 ,3]
47 | next() // print [4, 5, 6]
48 | next() // print [4, 5, 6]
49 | next() // print [10]
50 | ```
51 |
52 | See [Demo](https://github.com/pgherveou/RxPager/blob/master/Example/RxPager/PagerTableViewController.swift) for more examples
53 |
54 | ## Example
55 |
56 | To run the example project, or run the playground, clone the repo, and run `pod install` from the Example directory first.
57 |
58 | ## Requirements
59 |
60 | ## Installation
61 |
62 | RxPager is available through [CocoaPods](http://cocoapods.org). To install
63 | it, simply add the following line to your Podfile:
64 |
65 | ```ruby
66 | pod "RxPager"
67 | ```
68 |
69 | ## Credits
70 | This pod is inspired by inspired by @mttkay work https://gist.github.com/mttkay/24881a0ce986f6ec4b4d
71 | and was refactored using ideas discussed here https://github.com/RxSwiftCommunity/RxSwiftExt/issues/30
72 |
73 | ## License
74 |
75 | RxPager is available under the MIT license. See the LICENSE file for more info.
76 |
--------------------------------------------------------------------------------
/RxPager/Classes/RxPager.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import RxSwift
3 |
4 | // MARK: Observable + Pager
5 |
6 | extension Observable {
7 |
8 | /// Create a Pager Observable.
9 | ///
10 | /// - Parameters:
11 | /// - nextPage: The paging function used to generate new page.
12 | /// - hasNext: The hasNext function to define if there are more pages.
13 | /// - trigger: The Observable used to trigger next page.
14 | /// - Returns: The paged Observable.
15 | public static func page(make nextPage: @escaping (Element?) -> Observable,
16 | while hasNext: @escaping (Element) -> Bool,
17 | when trigger: Observable) -> Observable {
18 |
19 | // get next page and recurse
20 | func next(_ fromPage: Element?) -> Observable {
21 | return nextPage(fromPage).map { (page: Element) -> Observable in
22 | guard hasNext(page) else { return Observable.just(page) }
23 | return Observable.concat([
24 | Observable.just(page),
25 | Observable.never().take(until: trigger),
26 | next(page)
27 | ])
28 | }.flatMap { $0 }
29 | }
30 |
31 | return next(nil)
32 | }
33 |
34 | /// Create a Pager from an array
35 | ///
36 | /// - Parameters:
37 | /// - array: The array to page
38 | /// - pageSize: The size of each page emitted by the pager.
39 | /// - trigger: An Observable used to trigger next page load.
40 | /// - Returns: The paged Observable.
41 | public static func page(_ array: [Element], by pageSize: Int,
42 | when trigger: Observable) -> Observable<[Element]> {
43 |
44 | var index = array.startIndex
45 |
46 | func hasNext(_: [Element]) -> Bool {
47 | return index != array.endIndex
48 | }
49 |
50 | func nextPage(_: [Element]?) -> Observable<[Element]> {
51 | let newIndex = array.index(index, offsetBy: pageSize, limitedBy: array.endIndex) ?? array.endIndex
52 | let slice = array[index...just(Array(slice))
55 | }
56 |
57 | return Observable<[Element]>.page(make: nextPage, while: hasNext, when: trigger)
58 | }
59 | }
60 |
61 | // MARK: Pager
62 |
63 | /// A wrapper class that encapsulate both the Pager Observable and the trigger
64 | public struct Pager {
65 |
66 | /// page stream
67 | public let page: Observable
68 |
69 | // trigger used to call next page
70 | private let trigger = PublishSubject()
71 |
72 | /// Create a Pager
73 | ///
74 | /// - parameter nextPage: The paging function used to generate new page
75 | /// - parameter hasNext: The hasNext function to define if there are more pages
76 | public init(make nextPage: @escaping (T?) -> Observable, while hasNext: @escaping (T) -> Bool) {
77 | page = Observable.page(make: nextPage, while: hasNext, when: trigger.asObservable())
78 | }
79 |
80 | /// trigger the next page
81 | public func next() {
82 | trigger.onNext(())
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/Example/RxPager/PagerTableViewController.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import RxSwift
3 | import RxCocoa
4 | import RxPager
5 |
6 | // MARK: Helper
7 |
8 | private let startLoadingOffset: CGFloat = 20.0
9 | private func isNearTheBottomEdge(_ contentOffset: CGPoint, _ tableView: UITableView) -> Bool {
10 | return contentOffset.y +
11 | tableView.frame.size.height +
12 | startLoadingOffset > tableView.contentSize.height
13 | }
14 |
15 | // MARK: PagerTableViewController
16 |
17 | class PagerTableViewController: UITableViewController {
18 |
19 | /// Observable disposeBag
20 | private let disposeBag = DisposeBag()
21 |
22 | /// wether we should show the animating cell or not
23 | private var showAnimatingCell = true
24 |
25 | /// tableview dataSource
26 | private var dataSource: [Int] = [] {
27 | didSet {
28 | tableView.reloadData()
29 | }
30 | }
31 |
32 | /// pager trigger
33 | private lazy var loadNextPageTrigger: Observable = {
34 | return self.tableView.rx.contentOffset
35 | .flatMap { (offset) -> Observable in
36 | isNearTheBottomEdge(offset, self.tableView)
37 | ? Observable.just(Void())
38 | : Observable.empty()
39 | }
40 | }()
41 |
42 | /// Pager, that emit pages of [Int], and complete when last emitted int is greater than 100
43 | private lazy var page: Observable<[Int]> = {
44 | func nextPage(_ previousPage: [Int]?) -> Observable<[Int]> {
45 | let last = previousPage?.last ?? 0
46 | return Observable
47 | .just(Array(1...20).map { last + $0 })
48 | .delaySubscription(.milliseconds(500), scheduler: MainScheduler.instance)
49 | }
50 |
51 | func hasNext(_ page: [Int]?) -> Bool {
52 | guard let last = page?.last else { return true }
53 | return last < 100
54 | }
55 |
56 | return Observable.page(make: nextPage, while: hasNext, when: self.loadNextPageTrigger)
57 | }()
58 |
59 | override func viewDidLoad() {
60 | super.viewDidLoad()
61 |
62 | // scan, and update dataSource
63 | page
64 | .scan([Int](), accumulator: +)
65 | .subscribe(onNext: { [weak self] in self?.dataSource = $0 })
66 | .disposed(by: disposeBag)
67 |
68 | // update dataSource and reset the animating flag, when the stream complete
69 | page
70 | .subscribe(onCompleted: { [weak self] in
71 | self?.showAnimatingCell = false
72 | self?.tableView.reloadData()
73 | })
74 | .disposed(by: disposeBag)
75 | }
76 |
77 | // MARK: UITableViewController methods
78 |
79 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
80 | return dataSource.count + (showAnimatingCell ? 1 : 0)
81 | }
82 |
83 | override func tableView(_ tableView: UITableView,
84 | cellForRowAt indexPath: IndexPath) -> UITableViewCell {
85 | let cell: UITableViewCell?
86 |
87 | if showAnimatingCell && indexPath.row == dataSource.count {
88 | cell = tableView.dequeueReusableCell(withIdentifier: "loadingCell")
89 | } else {
90 | cell = tableView.dequeueReusableCell(withIdentifier: "pagerCell")
91 | cell?.textLabel?.text = "Row \(dataSource[(indexPath as NSIndexPath).row])"
92 | }
93 |
94 | return cell!
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/Example/RxPager/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Example/RxPager.xcodeproj/xcshareddata/xcschemes/RxPager-Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
48 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
80 |
82 |
88 |
89 |
90 |
91 |
92 |
93 |
99 |
101 |
107 |
108 |
109 |
110 |
112 |
113 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/Example/Tests/Tests.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import XCTest
3 | import RxSwift
4 | import RxPager
5 | import RxCocoa
6 |
7 | // MARK: Page
8 |
9 | /// a sample Page Data Struct
10 | struct Page {
11 | let values: [Int]
12 | let hasNext: Bool
13 | }
14 |
15 | // MARK: globals
16 |
17 | /// Delay block after `time` seconds.
18 | ///
19 | /// - Parameters:
20 | /// - time: The time to wait in seconds.
21 | /// - block: The block to executed after the delay.
22 | func delay(_ time: TimeInterval, block: @escaping () -> Void) {
23 | DispatchQueue.main.asyncAfter(
24 | deadline: .now() + Double(Int64(time * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: block)
25 | }
26 |
27 | /// Create a `Page` pager that emits 4 pages and complete.
28 | ///
29 | /// - Returns: A tuple with the pager and the trigger.
30 | func createPager() -> Pager {
31 | let nextPage = { (previousPage: Page?) -> Observable in
32 | let last = previousPage?.values.last ?? 0
33 | return Observable.just(Page(
34 | values: [last + 1, last + 2, last + 3],
35 | hasNext: last + 3 < 10)
36 | )
37 | }
38 |
39 | let hasNext = { (page: Page) -> Bool in
40 | return page.hasNext == true
41 | }
42 |
43 | return Pager(make: nextPage, while: hasNext)
44 | }
45 |
46 | /// Create a `Page` pager that emits 4 pages and complete.
47 | /// Each page is emitted asynchronously after a 0.1s delay
48 | ///
49 | /// - Returns: A tuple with the pager and the trigger
50 | func createASyncPager() -> Pager {
51 |
52 | let nextPage = { (previousPage: Page?) -> Observable in
53 | let last = previousPage?.values.last ?? 0
54 | return Observable.just(Page(
55 | values: [last + 1, last + 2, last + 3],
56 | hasNext: last + 3 < 10)
57 | ).delaySubscription(.milliseconds(100), scheduler: MainScheduler.instance)
58 | }
59 |
60 | let hasNext = { (page: Page) -> Bool in
61 | return page.hasNext == true
62 | }
63 |
64 | return Pager(make: nextPage, while: hasNext)
65 | }
66 |
67 | // MARK: Tests
68 |
69 | class Tests: XCTestCase {
70 |
71 | /// stream dispose bag
72 | var disposeBag = DisposeBag()
73 |
74 | override func tearDown() {
75 | // dispose current `disposeBag` and create a new one
76 | disposeBag = DisposeBag()
77 | }
78 |
79 | /// ensure that the first page is emitted
80 | func testGetFirstPage() {
81 | let expectation = self.expectation(description: "get first page")
82 | let pager = createPager()
83 |
84 | pager.page
85 | .subscribe(onNext: { page in
86 | XCTAssertEqual(page.values, [1, 2, 3])
87 | expectation.fulfill()
88 | })
89 | .disposed(by: disposeBag)
90 |
91 | waitForExpectations(timeout: 1, handler: nil)
92 | }
93 |
94 | /// ensure that the second page is emitted
95 | func testGetSecondPage() {
96 | let expectation = self.expectation(description: "get first two page")
97 | let pager = createPager()
98 |
99 | pager.page
100 | .skip(1)
101 | .subscribe(onNext: { page in
102 | XCTAssertEqual(page.values, [4, 5, 6])
103 | expectation.fulfill()
104 | })
105 | .disposed(by: disposeBag)
106 |
107 | pager.next()
108 | waitForExpectations(timeout: 1, handler: nil)
109 | }
110 |
111 | /// ensure that the third page is emitted
112 | func testGetThirdPage() {
113 | let expectation = self.expectation(description: "get first three page")
114 | let pager = createPager()
115 |
116 | pager.page
117 | .skip(2)
118 | .subscribe(onNext: { page in
119 | XCTAssertEqual(page.values, [7, 8, 9])
120 | expectation.fulfill()
121 | }).disposed(by: disposeBag)
122 |
123 | pager.next()
124 | pager.next()
125 | waitForExpectations(timeout: 1, handler: nil)
126 | }
127 |
128 | /// ensure that the completed event is emitted
129 | func testCompletePager() {
130 | let expectation = self.expectation(description: "get completed event")
131 | let pager = createPager()
132 |
133 | pager.page.subscribe(onCompleted: {
134 | expectation.fulfill()
135 | }).disposed(by: disposeBag)
136 |
137 | // starts with [1, 2 ,3]
138 | pager.next() // [4, 5, 6]
139 | pager.next() // [7, 8, 9]
140 | pager.next() // [10, 11, 12], completed
141 | waitForExpectations(timeout: 1, handler: nil)
142 | }
143 |
144 | /// ensure next is a noop when called more than once between two pages emission
145 | func testCantNextMoreThanOnceBeforeNextPage() {
146 | let expectation = self.expectation(description: "get first two page")
147 | let pager = createASyncPager()
148 |
149 | pager.page
150 | .subscribe(onNext: { page in
151 | // should only be called once
152 | XCTAssertEqual(page.values, [1, 2, 3])
153 |
154 | // wait for non event and fulfill
155 | delay(0.2) { expectation.fulfill() }
156 | })
157 | .disposed(by: disposeBag)
158 |
159 | pager.next() // should be a noop
160 | pager.next() // should be a noop
161 | waitForExpectations(timeout: 1, handler: nil)
162 | }
163 |
164 | func testPageFromSequence() {
165 | var pages: [[Int]] = []
166 | let arr = Array(0...10)
167 | let expected = [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10]]
168 | let expectation = self.expectation(description: "get pages from sequence")
169 |
170 | let trigger = PublishSubject()
171 |
172 | Observable
173 | .page(arr, by: 2, when: trigger)
174 | .subscribe(
175 | onNext: {
176 | pages.append($0)
177 | },
178 | onCompleted: {
179 | XCTAssert(pages.count == expected.count)
180 | zip(pages, expected).forEach { XCTAssert($0 == $1) }
181 | expectation.fulfill()
182 | }
183 | )
184 | .disposed(by: disposeBag)
185 |
186 | // start with [0, 1]
187 | trigger.onNext(()) // [2, 3]
188 | trigger.onNext(()) // [4, 5]
189 | trigger.onNext(()) // [6, 7]
190 | trigger.onNext(()) // [8, 9]
191 | trigger.onNext(()) // [10]
192 | waitForExpectations(timeout: 1, handler: nil)
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/Example/RxPager/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/Example/RxPager.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 04790720DC05235030C40BF6 /* Pods_RxPager_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15284551E7BB0E04ED4C7E56 /* Pods_RxPager_Tests.framework */; };
11 | 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; };
12 | 607FACD81AFB9204008FA782 /* PagerTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD71AFB9204008FA782 /* PagerTableViewController.swift */; };
13 | 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; };
14 | 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; };
15 | 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; };
16 | 607FACEC1AFB9204008FA782 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* Tests.swift */; };
17 | 682BC0ABFE1D9BD0AD920F43 /* Pods_RxPager_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B63E9E3C3AB6217BA93D73F /* Pods_RxPager_Example.framework */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXContainerItemProxy section */
21 | 607FACE61AFB9204008FA782 /* PBXContainerItemProxy */ = {
22 | isa = PBXContainerItemProxy;
23 | containerPortal = 607FACC81AFB9204008FA782 /* Project object */;
24 | proxyType = 1;
25 | remoteGlobalIDString = 607FACCF1AFB9204008FA782;
26 | remoteInfo = RxPager;
27 | };
28 | /* End PBXContainerItemProxy section */
29 |
30 | /* Begin PBXFileReference section */
31 | 15284551E7BB0E04ED4C7E56 /* Pods_RxPager_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RxPager_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
32 | 24BE205D749F1CEAEF25AE29 /* Pods-RxPager_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxPager_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-RxPager_Example/Pods-RxPager_Example.release.xcconfig"; sourceTree = ""; };
33 | 3B63E9E3C3AB6217BA93D73F /* Pods_RxPager_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RxPager_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
34 | 449F6AE7BAC4BDA0A039E2F0 /* Pods-RxPager_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxPager_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RxPager_Tests/Pods-RxPager_Tests.debug.xcconfig"; sourceTree = ""; };
35 | 607FACD01AFB9204008FA782 /* RxPager_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RxPager_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
36 | 607FACD41AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
37 | 607FACD51AFB9204008FA782 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
38 | 607FACD71AFB9204008FA782 /* PagerTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = PagerTableViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
39 | 607FACDA1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
40 | 607FACDC1AFB9204008FA782 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
41 | 607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
42 | 607FACE51AFB9204008FA782 /* RxPager_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RxPager_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
43 | 607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
44 | 607FACEB1AFB9204008FA782 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Tests.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
45 | 8144E3C2DC7C8219ADC5D128 /* Pods-RxPager_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxPager_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RxPager_Tests/Pods-RxPager_Tests.release.xcconfig"; sourceTree = ""; };
46 | A9287D6D431E296D8E3084B9 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; };
47 | C402DF3D8571427EDEEF40C1 /* RxPager.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = RxPager.podspec; path = ../RxPager.podspec; sourceTree = ""; };
48 | E4D2F41FCFE4D933A13A5D7E /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; lineEnding = 0; name = README.md; path = ../README.md; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.markdown; };
49 | E8148D94FE412363B5033868 /* Pods-RxPager_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxPager_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RxPager_Example/Pods-RxPager_Example.debug.xcconfig"; sourceTree = ""; };
50 | /* End PBXFileReference section */
51 |
52 | /* Begin PBXFrameworksBuildPhase section */
53 | 607FACCD1AFB9204008FA782 /* Frameworks */ = {
54 | isa = PBXFrameworksBuildPhase;
55 | buildActionMask = 2147483647;
56 | files = (
57 | 682BC0ABFE1D9BD0AD920F43 /* Pods_RxPager_Example.framework in Frameworks */,
58 | );
59 | runOnlyForDeploymentPostprocessing = 0;
60 | };
61 | 607FACE21AFB9204008FA782 /* Frameworks */ = {
62 | isa = PBXFrameworksBuildPhase;
63 | buildActionMask = 2147483647;
64 | files = (
65 | 04790720DC05235030C40BF6 /* Pods_RxPager_Tests.framework in Frameworks */,
66 | );
67 | runOnlyForDeploymentPostprocessing = 0;
68 | };
69 | /* End PBXFrameworksBuildPhase section */
70 |
71 | /* Begin PBXGroup section */
72 | 607FACC71AFB9204008FA782 = {
73 | isa = PBXGroup;
74 | children = (
75 | 607FACF51AFB993E008FA782 /* Podspec Metadata */,
76 | 607FACD21AFB9204008FA782 /* Example for RxPager */,
77 | 607FACE81AFB9204008FA782 /* Tests */,
78 | 607FACD11AFB9204008FA782 /* Products */,
79 | DB3A32F656CBCBD3BBBDDB34 /* Pods */,
80 | B8411F016EA9E32ED53F3A24 /* Frameworks */,
81 | );
82 | sourceTree = "";
83 | };
84 | 607FACD11AFB9204008FA782 /* Products */ = {
85 | isa = PBXGroup;
86 | children = (
87 | 607FACD01AFB9204008FA782 /* RxPager_Example.app */,
88 | 607FACE51AFB9204008FA782 /* RxPager_Tests.xctest */,
89 | );
90 | name = Products;
91 | sourceTree = "";
92 | };
93 | 607FACD21AFB9204008FA782 /* Example for RxPager */ = {
94 | isa = PBXGroup;
95 | children = (
96 | 607FACD51AFB9204008FA782 /* AppDelegate.swift */,
97 | 607FACD71AFB9204008FA782 /* PagerTableViewController.swift */,
98 | 607FACD91AFB9204008FA782 /* Main.storyboard */,
99 | 607FACDC1AFB9204008FA782 /* Images.xcassets */,
100 | 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */,
101 | 607FACD31AFB9204008FA782 /* Supporting Files */,
102 | );
103 | name = "Example for RxPager";
104 | path = RxPager;
105 | sourceTree = "";
106 | };
107 | 607FACD31AFB9204008FA782 /* Supporting Files */ = {
108 | isa = PBXGroup;
109 | children = (
110 | 607FACD41AFB9204008FA782 /* Info.plist */,
111 | );
112 | name = "Supporting Files";
113 | sourceTree = "";
114 | };
115 | 607FACE81AFB9204008FA782 /* Tests */ = {
116 | isa = PBXGroup;
117 | children = (
118 | 607FACEB1AFB9204008FA782 /* Tests.swift */,
119 | 607FACE91AFB9204008FA782 /* Supporting Files */,
120 | );
121 | path = Tests;
122 | sourceTree = "";
123 | };
124 | 607FACE91AFB9204008FA782 /* Supporting Files */ = {
125 | isa = PBXGroup;
126 | children = (
127 | 607FACEA1AFB9204008FA782 /* Info.plist */,
128 | );
129 | name = "Supporting Files";
130 | sourceTree = "";
131 | };
132 | 607FACF51AFB993E008FA782 /* Podspec Metadata */ = {
133 | isa = PBXGroup;
134 | children = (
135 | C402DF3D8571427EDEEF40C1 /* RxPager.podspec */,
136 | E4D2F41FCFE4D933A13A5D7E /* README.md */,
137 | A9287D6D431E296D8E3084B9 /* LICENSE */,
138 | );
139 | name = "Podspec Metadata";
140 | sourceTree = "";
141 | };
142 | B8411F016EA9E32ED53F3A24 /* Frameworks */ = {
143 | isa = PBXGroup;
144 | children = (
145 | 3B63E9E3C3AB6217BA93D73F /* Pods_RxPager_Example.framework */,
146 | 15284551E7BB0E04ED4C7E56 /* Pods_RxPager_Tests.framework */,
147 | );
148 | name = Frameworks;
149 | sourceTree = "";
150 | };
151 | DB3A32F656CBCBD3BBBDDB34 /* Pods */ = {
152 | isa = PBXGroup;
153 | children = (
154 | E8148D94FE412363B5033868 /* Pods-RxPager_Example.debug.xcconfig */,
155 | 24BE205D749F1CEAEF25AE29 /* Pods-RxPager_Example.release.xcconfig */,
156 | 449F6AE7BAC4BDA0A039E2F0 /* Pods-RxPager_Tests.debug.xcconfig */,
157 | 8144E3C2DC7C8219ADC5D128 /* Pods-RxPager_Tests.release.xcconfig */,
158 | );
159 | name = Pods;
160 | sourceTree = "";
161 | };
162 | /* End PBXGroup section */
163 |
164 | /* Begin PBXNativeTarget section */
165 | 607FACCF1AFB9204008FA782 /* RxPager_Example */ = {
166 | isa = PBXNativeTarget;
167 | buildConfigurationList = 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "RxPager_Example" */;
168 | buildPhases = (
169 | 5434266E288E796A8D206CD0 /* [CP] Check Pods Manifest.lock */,
170 | 607FACCC1AFB9204008FA782 /* Sources */,
171 | 607FACCD1AFB9204008FA782 /* Frameworks */,
172 | 607FACCE1AFB9204008FA782 /* Resources */,
173 | 33D5C859D040D4AD7F8FD3A9 /* [CP] Embed Pods Frameworks */,
174 | );
175 | buildRules = (
176 | );
177 | dependencies = (
178 | );
179 | name = RxPager_Example;
180 | productName = RxPager;
181 | productReference = 607FACD01AFB9204008FA782 /* RxPager_Example.app */;
182 | productType = "com.apple.product-type.application";
183 | };
184 | 607FACE41AFB9204008FA782 /* RxPager_Tests */ = {
185 | isa = PBXNativeTarget;
186 | buildConfigurationList = 607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget "RxPager_Tests" */;
187 | buildPhases = (
188 | CB568BDB9A4B615DE6B463ED /* [CP] Check Pods Manifest.lock */,
189 | 607FACE11AFB9204008FA782 /* Sources */,
190 | 607FACE21AFB9204008FA782 /* Frameworks */,
191 | 607FACE31AFB9204008FA782 /* Resources */,
192 | DBCECE1C24219FF94B8FA51E /* [CP] Embed Pods Frameworks */,
193 | );
194 | buildRules = (
195 | );
196 | dependencies = (
197 | 607FACE71AFB9204008FA782 /* PBXTargetDependency */,
198 | );
199 | name = RxPager_Tests;
200 | productName = Tests;
201 | productReference = 607FACE51AFB9204008FA782 /* RxPager_Tests.xctest */;
202 | productType = "com.apple.product-type.bundle.unit-test";
203 | };
204 | /* End PBXNativeTarget section */
205 |
206 | /* Begin PBXProject section */
207 | 607FACC81AFB9204008FA782 /* Project object */ = {
208 | isa = PBXProject;
209 | attributes = {
210 | LastSwiftUpdateCheck = 0720;
211 | LastUpgradeCheck = 0900;
212 | ORGANIZATIONNAME = CocoaPods;
213 | TargetAttributes = {
214 | 607FACCF1AFB9204008FA782 = {
215 | CreatedOnToolsVersion = 6.3.1;
216 | LastSwiftMigration = 1340;
217 | };
218 | 607FACE41AFB9204008FA782 = {
219 | CreatedOnToolsVersion = 6.3.1;
220 | LastSwiftMigration = 1340;
221 | TestTargetID = 607FACCF1AFB9204008FA782;
222 | };
223 | };
224 | };
225 | buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "RxPager" */;
226 | compatibilityVersion = "Xcode 3.2";
227 | developmentRegion = English;
228 | hasScannedForEncodings = 0;
229 | knownRegions = (
230 | English,
231 | en,
232 | Base,
233 | );
234 | mainGroup = 607FACC71AFB9204008FA782;
235 | productRefGroup = 607FACD11AFB9204008FA782 /* Products */;
236 | projectDirPath = "";
237 | projectRoot = "";
238 | targets = (
239 | 607FACCF1AFB9204008FA782 /* RxPager_Example */,
240 | 607FACE41AFB9204008FA782 /* RxPager_Tests */,
241 | );
242 | };
243 | /* End PBXProject section */
244 |
245 | /* Begin PBXResourcesBuildPhase section */
246 | 607FACCE1AFB9204008FA782 /* Resources */ = {
247 | isa = PBXResourcesBuildPhase;
248 | buildActionMask = 2147483647;
249 | files = (
250 | 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */,
251 | 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */,
252 | 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */,
253 | );
254 | runOnlyForDeploymentPostprocessing = 0;
255 | };
256 | 607FACE31AFB9204008FA782 /* Resources */ = {
257 | isa = PBXResourcesBuildPhase;
258 | buildActionMask = 2147483647;
259 | files = (
260 | );
261 | runOnlyForDeploymentPostprocessing = 0;
262 | };
263 | /* End PBXResourcesBuildPhase section */
264 |
265 | /* Begin PBXShellScriptBuildPhase section */
266 | 33D5C859D040D4AD7F8FD3A9 /* [CP] Embed Pods Frameworks */ = {
267 | isa = PBXShellScriptBuildPhase;
268 | buildActionMask = 2147483647;
269 | files = (
270 | );
271 | inputPaths = (
272 | "${PODS_ROOT}/Target Support Files/Pods-RxPager_Example/Pods-RxPager_Example-frameworks.sh",
273 | "${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework",
274 | "${BUILT_PRODUCTS_DIR}/RxPager/RxPager.framework",
275 | "${BUILT_PRODUCTS_DIR}/RxRelay/RxRelay.framework",
276 | "${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework",
277 | );
278 | name = "[CP] Embed Pods Frameworks";
279 | outputPaths = (
280 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxCocoa.framework",
281 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxPager.framework",
282 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxRelay.framework",
283 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework",
284 | );
285 | runOnlyForDeploymentPostprocessing = 0;
286 | shellPath = /bin/sh;
287 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-RxPager_Example/Pods-RxPager_Example-frameworks.sh\"\n";
288 | showEnvVarsInLog = 0;
289 | };
290 | 5434266E288E796A8D206CD0 /* [CP] Check Pods Manifest.lock */ = {
291 | isa = PBXShellScriptBuildPhase;
292 | buildActionMask = 2147483647;
293 | files = (
294 | );
295 | inputPaths = (
296 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
297 | "${PODS_ROOT}/Manifest.lock",
298 | );
299 | name = "[CP] Check Pods Manifest.lock";
300 | outputPaths = (
301 | "$(DERIVED_FILE_DIR)/Pods-RxPager_Example-checkManifestLockResult.txt",
302 | );
303 | runOnlyForDeploymentPostprocessing = 0;
304 | shellPath = /bin/sh;
305 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
306 | showEnvVarsInLog = 0;
307 | };
308 | CB568BDB9A4B615DE6B463ED /* [CP] Check Pods Manifest.lock */ = {
309 | isa = PBXShellScriptBuildPhase;
310 | buildActionMask = 2147483647;
311 | files = (
312 | );
313 | inputPaths = (
314 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
315 | "${PODS_ROOT}/Manifest.lock",
316 | );
317 | name = "[CP] Check Pods Manifest.lock";
318 | outputPaths = (
319 | "$(DERIVED_FILE_DIR)/Pods-RxPager_Tests-checkManifestLockResult.txt",
320 | );
321 | runOnlyForDeploymentPostprocessing = 0;
322 | shellPath = /bin/sh;
323 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
324 | showEnvVarsInLog = 0;
325 | };
326 | DBCECE1C24219FF94B8FA51E /* [CP] Embed Pods Frameworks */ = {
327 | isa = PBXShellScriptBuildPhase;
328 | buildActionMask = 2147483647;
329 | files = (
330 | );
331 | inputPaths = (
332 | "${PODS_ROOT}/Target Support Files/Pods-RxPager_Tests/Pods-RxPager_Tests-frameworks.sh",
333 | "${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework",
334 | "${BUILT_PRODUCTS_DIR}/RxPager/RxPager.framework",
335 | "${BUILT_PRODUCTS_DIR}/RxRelay/RxRelay.framework",
336 | "${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework",
337 | );
338 | name = "[CP] Embed Pods Frameworks";
339 | outputPaths = (
340 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxCocoa.framework",
341 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxPager.framework",
342 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxRelay.framework",
343 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework",
344 | );
345 | runOnlyForDeploymentPostprocessing = 0;
346 | shellPath = /bin/sh;
347 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-RxPager_Tests/Pods-RxPager_Tests-frameworks.sh\"\n";
348 | showEnvVarsInLog = 0;
349 | };
350 | /* End PBXShellScriptBuildPhase section */
351 |
352 | /* Begin PBXSourcesBuildPhase section */
353 | 607FACCC1AFB9204008FA782 /* Sources */ = {
354 | isa = PBXSourcesBuildPhase;
355 | buildActionMask = 2147483647;
356 | files = (
357 | 607FACD81AFB9204008FA782 /* PagerTableViewController.swift in Sources */,
358 | 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */,
359 | );
360 | runOnlyForDeploymentPostprocessing = 0;
361 | };
362 | 607FACE11AFB9204008FA782 /* Sources */ = {
363 | isa = PBXSourcesBuildPhase;
364 | buildActionMask = 2147483647;
365 | files = (
366 | 607FACEC1AFB9204008FA782 /* Tests.swift in Sources */,
367 | );
368 | runOnlyForDeploymentPostprocessing = 0;
369 | };
370 | /* End PBXSourcesBuildPhase section */
371 |
372 | /* Begin PBXTargetDependency section */
373 | 607FACE71AFB9204008FA782 /* PBXTargetDependency */ = {
374 | isa = PBXTargetDependency;
375 | target = 607FACCF1AFB9204008FA782 /* RxPager_Example */;
376 | targetProxy = 607FACE61AFB9204008FA782 /* PBXContainerItemProxy */;
377 | };
378 | /* End PBXTargetDependency section */
379 |
380 | /* Begin PBXVariantGroup section */
381 | 607FACD91AFB9204008FA782 /* Main.storyboard */ = {
382 | isa = PBXVariantGroup;
383 | children = (
384 | 607FACDA1AFB9204008FA782 /* Base */,
385 | );
386 | name = Main.storyboard;
387 | sourceTree = "";
388 | };
389 | 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */ = {
390 | isa = PBXVariantGroup;
391 | children = (
392 | 607FACDF1AFB9204008FA782 /* Base */,
393 | );
394 | name = LaunchScreen.xib;
395 | sourceTree = "";
396 | };
397 | /* End PBXVariantGroup section */
398 |
399 | /* Begin XCBuildConfiguration section */
400 | 607FACED1AFB9204008FA782 /* Debug */ = {
401 | isa = XCBuildConfiguration;
402 | buildSettings = {
403 | ALWAYS_SEARCH_USER_PATHS = NO;
404 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
405 | CLANG_CXX_LIBRARY = "libc++";
406 | CLANG_ENABLE_MODULES = YES;
407 | CLANG_ENABLE_OBJC_ARC = YES;
408 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
409 | CLANG_WARN_BOOL_CONVERSION = YES;
410 | CLANG_WARN_COMMA = YES;
411 | CLANG_WARN_CONSTANT_CONVERSION = YES;
412 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
413 | CLANG_WARN_EMPTY_BODY = YES;
414 | CLANG_WARN_ENUM_CONVERSION = YES;
415 | CLANG_WARN_INFINITE_RECURSION = YES;
416 | CLANG_WARN_INT_CONVERSION = YES;
417 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
418 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
419 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
420 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
421 | CLANG_WARN_STRICT_PROTOTYPES = YES;
422 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
423 | CLANG_WARN_UNREACHABLE_CODE = YES;
424 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
425 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
426 | COPY_PHASE_STRIP = NO;
427 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
428 | ENABLE_STRICT_OBJC_MSGSEND = YES;
429 | ENABLE_TESTABILITY = YES;
430 | GCC_C_LANGUAGE_STANDARD = gnu99;
431 | GCC_DYNAMIC_NO_PIC = NO;
432 | GCC_NO_COMMON_BLOCKS = YES;
433 | GCC_OPTIMIZATION_LEVEL = 0;
434 | GCC_PREPROCESSOR_DEFINITIONS = (
435 | "DEBUG=1",
436 | "$(inherited)",
437 | );
438 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
439 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
440 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
441 | GCC_WARN_UNDECLARED_SELECTOR = YES;
442 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
443 | GCC_WARN_UNUSED_FUNCTION = YES;
444 | GCC_WARN_UNUSED_VARIABLE = YES;
445 | IPHONEOS_DEPLOYMENT_TARGET = 8.3;
446 | MTL_ENABLE_DEBUG_INFO = YES;
447 | ONLY_ACTIVE_ARCH = YES;
448 | SDKROOT = iphoneos;
449 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
450 | SWIFT_VERSION = 4.0;
451 | };
452 | name = Debug;
453 | };
454 | 607FACEE1AFB9204008FA782 /* Release */ = {
455 | isa = XCBuildConfiguration;
456 | buildSettings = {
457 | ALWAYS_SEARCH_USER_PATHS = NO;
458 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
459 | CLANG_CXX_LIBRARY = "libc++";
460 | CLANG_ENABLE_MODULES = YES;
461 | CLANG_ENABLE_OBJC_ARC = YES;
462 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
463 | CLANG_WARN_BOOL_CONVERSION = YES;
464 | CLANG_WARN_COMMA = YES;
465 | CLANG_WARN_CONSTANT_CONVERSION = YES;
466 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
467 | CLANG_WARN_EMPTY_BODY = YES;
468 | CLANG_WARN_ENUM_CONVERSION = YES;
469 | CLANG_WARN_INFINITE_RECURSION = YES;
470 | CLANG_WARN_INT_CONVERSION = YES;
471 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
472 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
473 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
474 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
475 | CLANG_WARN_STRICT_PROTOTYPES = YES;
476 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
477 | CLANG_WARN_UNREACHABLE_CODE = YES;
478 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
479 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
480 | COPY_PHASE_STRIP = NO;
481 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
482 | ENABLE_NS_ASSERTIONS = NO;
483 | ENABLE_STRICT_OBJC_MSGSEND = YES;
484 | GCC_C_LANGUAGE_STANDARD = gnu99;
485 | GCC_NO_COMMON_BLOCKS = YES;
486 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
487 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
488 | GCC_WARN_UNDECLARED_SELECTOR = YES;
489 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
490 | GCC_WARN_UNUSED_FUNCTION = YES;
491 | GCC_WARN_UNUSED_VARIABLE = YES;
492 | IPHONEOS_DEPLOYMENT_TARGET = 8.3;
493 | MTL_ENABLE_DEBUG_INFO = NO;
494 | SDKROOT = iphoneos;
495 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
496 | SWIFT_VERSION = 4.0;
497 | VALIDATE_PRODUCT = YES;
498 | };
499 | name = Release;
500 | };
501 | 607FACF01AFB9204008FA782 /* Debug */ = {
502 | isa = XCBuildConfiguration;
503 | baseConfigurationReference = E8148D94FE412363B5033868 /* Pods-RxPager_Example.debug.xcconfig */;
504 | buildSettings = {
505 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
506 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
507 | INFOPLIST_FILE = RxPager/Info.plist;
508 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
509 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
510 | MODULE_NAME = ExampleApp;
511 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)";
512 | PRODUCT_NAME = "$(TARGET_NAME)";
513 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
514 | SWIFT_VERSION = 5.0;
515 | };
516 | name = Debug;
517 | };
518 | 607FACF11AFB9204008FA782 /* Release */ = {
519 | isa = XCBuildConfiguration;
520 | baseConfigurationReference = 24BE205D749F1CEAEF25AE29 /* Pods-RxPager_Example.release.xcconfig */;
521 | buildSettings = {
522 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
523 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
524 | INFOPLIST_FILE = RxPager/Info.plist;
525 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
526 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
527 | MODULE_NAME = ExampleApp;
528 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)";
529 | PRODUCT_NAME = "$(TARGET_NAME)";
530 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
531 | SWIFT_VERSION = 5.0;
532 | };
533 | name = Release;
534 | };
535 | 607FACF31AFB9204008FA782 /* Debug */ = {
536 | isa = XCBuildConfiguration;
537 | baseConfigurationReference = 449F6AE7BAC4BDA0A039E2F0 /* Pods-RxPager_Tests.debug.xcconfig */;
538 | buildSettings = {
539 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
540 | BUNDLE_LOADER = "$(TEST_HOST)";
541 | FRAMEWORK_SEARCH_PATHS = "$(inherited)";
542 | GCC_PREPROCESSOR_DEFINITIONS = (
543 | "DEBUG=1",
544 | "$(inherited)",
545 | );
546 | INFOPLIST_FILE = Tests/Info.plist;
547 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
548 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
549 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)";
550 | PRODUCT_NAME = "$(TARGET_NAME)";
551 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
552 | SWIFT_VERSION = 5.0;
553 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RxPager_Example.app/RxPager_Example";
554 | };
555 | name = Debug;
556 | };
557 | 607FACF41AFB9204008FA782 /* Release */ = {
558 | isa = XCBuildConfiguration;
559 | baseConfigurationReference = 8144E3C2DC7C8219ADC5D128 /* Pods-RxPager_Tests.release.xcconfig */;
560 | buildSettings = {
561 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
562 | BUNDLE_LOADER = "$(TEST_HOST)";
563 | FRAMEWORK_SEARCH_PATHS = "$(inherited)";
564 | INFOPLIST_FILE = Tests/Info.plist;
565 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
566 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
567 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)";
568 | PRODUCT_NAME = "$(TARGET_NAME)";
569 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
570 | SWIFT_VERSION = 5.0;
571 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RxPager_Example.app/RxPager_Example";
572 | };
573 | name = Release;
574 | };
575 | /* End XCBuildConfiguration section */
576 |
577 | /* Begin XCConfigurationList section */
578 | 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "RxPager" */ = {
579 | isa = XCConfigurationList;
580 | buildConfigurations = (
581 | 607FACED1AFB9204008FA782 /* Debug */,
582 | 607FACEE1AFB9204008FA782 /* Release */,
583 | );
584 | defaultConfigurationIsVisible = 0;
585 | defaultConfigurationName = Release;
586 | };
587 | 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "RxPager_Example" */ = {
588 | isa = XCConfigurationList;
589 | buildConfigurations = (
590 | 607FACF01AFB9204008FA782 /* Debug */,
591 | 607FACF11AFB9204008FA782 /* Release */,
592 | );
593 | defaultConfigurationIsVisible = 0;
594 | defaultConfigurationName = Release;
595 | };
596 | 607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget "RxPager_Tests" */ = {
597 | isa = XCConfigurationList;
598 | buildConfigurations = (
599 | 607FACF31AFB9204008FA782 /* Debug */,
600 | 607FACF41AFB9204008FA782 /* Release */,
601 | );
602 | defaultConfigurationIsVisible = 0;
603 | defaultConfigurationName = Release;
604 | };
605 | /* End XCConfigurationList section */
606 | };
607 | rootObject = 607FACC81AFB9204008FA782 /* Project object */;
608 | }
609 |
--------------------------------------------------------------------------------