Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom card state #53

Merged
merged 1 commit into from
Jun 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions CardParts/src/Classes/CardPartsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import UIKit
import RxSwift
import RxCocoa

public enum CardState {
case none
case loading
case empty
case hasData
public enum CardState: Hashable {
case none
case loading
case empty
case hasData
case custom(String)
}

class CardStateData {
Expand Down
20 changes: 13 additions & 7 deletions Example/CardParts/StateCardController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import RxCocoa

class StateCardController : CardPartsViewController {

let customStateKey = "myCustomState"

init() {
super.init(nibName: nil, bundle: nil)
startRandomHides()
Expand All @@ -33,20 +35,24 @@ class StateCardController : CardPartsViewController {

let textPart = CardPartTextView(type: .normal)
textPart.text = "Watch me change states!"

setupCardParts([textPart])

let spacerPart = CardPartSpacerView(height: 200)
let loadingCardPart = CardPartTextView(type: .normal)
loadingCardPart.text = "I am a loading state"

setupCardParts([textPart], forState: .empty)
setupCardParts([spacerPart], forState: .hasData)
let customCardPart = CardPartTextView(type: .normal)
customCardPart.text = "I am a custom state that you can make!"

setupCardParts([textPart], forState: .empty)
setupCardParts([loadingCardPart], forState: .loading)
setupCardParts([customCardPart], forState: .custom(customStateKey))
}

@objc func toggleHidden() {
if state == .empty {
state = .hasData
} else {
state = .loading
} else if state == .loading {
state = .custom(customStateKey)
} else if state == .custom(customStateKey) {
state = .empty
}
}
Expand Down
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -719,32 +719,48 @@ Add the above orientedView to any list of card parts or an existing stack view t
CardPartsViewController can optionally support the notion of card states, where a card can be in 3 different states: loading, empty, and hasData. For each state you can specify a unique set of card parts to display. Then when the CardPartsViewController state property is changed, the framework will automatically switch the card parts to display the card parts for that state. Typically you would bind the state property to a state property in your view model so that when the view model changes state the card parts are changed. A simple example:

```swift
public enum CardState {
case none
case loading
case empty
case hasData
case custom(String)
}

class TestCardController : CardPartsViewController {

var viewModel = TestViewModel()
var titlePart = CardPartTitleView(type: .titleOnly)
var textPart = CardPartTextView(type: .normal)
var loadingText = CardPartTextView(type: .normal)
var emptyText = CardPartTextView(type: .normal)
var customText = CardPartTextView(type: .normal)

override func viewDidLoad() {
super.viewDidLoad()

viewModel.title.asObservable().bind(to: titlePart.reactive.title).disposed(by: bag)
viewModel.text.asObservable().bind(to: textPart.reactive.text).disposed(by: bag)
viewModel.title.asObservable().bind(to: titlePart.rx.title).disposed(by: bag)
viewModel.text.asObservable().bind(to: textPart.rx.text).disposed(by: bag)

loadingText.text = "Loading..."
emptyText.text = "No data found."
customText.text = "I am some custom state"

viewModel.state.asObservable().bind(to: self.rx.state).disposed(by: bag)

setupCardParts([titlePart, textPart], forState: .hasData)
setupCardParts([titlePart, loadingText], forState: .loading)
setupCardParts([titlePart, emptyText], forState: .empty)
setupCardParts([titlePart, customText], forState: .custom("myCustomState"))
}
}
```

*Note: There is a `custom(String)` state which allows you to use more than our predefined set of states:*
```swift
.custom("myCustomState")
```

## Data Binding
Data binding is implemented using the RxSwift library (https://github.com/ReactiveX/RxSwift). View models should expose their data as bindable properties using the Variable class. In the example above the view model might look like this:
```swift
Expand Down