How to simplify pager interaction with Rx

Issue #333

In a traditional pager with many pages of content, and a bottom navigation with previous and next button. Each page may have different content, and depending on each state, may block the next button.

The state of next button should state in real time depending on state in each page content, and when user moves back and forth between pages, the state of next button should be reflected as well.

We might have

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
extension ViewController: BottomNavigationDelegate {
func bottomNavigationCanGoNext(currentIndex: Int) -> Bool {}
func bottomNavigationDidMoveTo(index: Int) {}
}

extension ViewController: PreferencePageDelegate {
func preferencePageDidSelect(itemCount: Int) {}
}

extension ViewController: FormPageDelegate {
func formPageDidCheck(valid: Bool) {}
}

extension ViewController: ConsentPageDelegate {
func consentPageDidAccept(agree: Bool) {}
}

The indirect communications between each page, bottom navigation and ViewController get complicated and out of hands very quickly.

This is a perfect problem for Rx to solve. If we look closely, the state of next button is a derivative of current index, how many items selected in preferences, valid form and agreement status.

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
class BottomNavigation {
let index = PublishSubject<Int>()
}

class PreferencePage {
let itemCount = PublishSubject<Int>()
}

class FormPage {
let valid = PublishSubject<Bool>()
}

class ConsentPage {
let agree = PublishSubject<Bool>()
}

let canNext = Observable
.combineLatest(bottomNavigation.index, preferencePage.itemCount, formPage.valid, consentPage.agree)
.map({ (index, itemCount, valid, agree) -> Bool in
// Logic goes here to reduce, for example
switch index {
case 0: return true
case 1: return itemCount > 2
case 2: return valid
case 3: Return agree
default: return false
}
})

Comments