-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathEmptyStatesViewModel.swift
160 lines (130 loc) · 5.1 KB
/
EmptyStatesViewModel.swift
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
29
30
31
32
33
34
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import KsApi
import Prelude
import ReactiveSwift
import UIKit
public enum EmptyState: String {
case activity
case recommended
case socialNoPledges = "social_no_pledges"
case socialDisabled = "social_disabled"
case starred
}
public protocol EmptyStatesViewModelInputs {
/// Call to configure with the view controller that needs an empty state.
func configureWith(emptyState: EmptyState?)
/// Call when main button is tapped.
func mainButtonTapped()
/// Call to set the empty state if it is not known at the time of instanciation.
func setEmptyState(_ emptyState: EmptyState)
/// Call when the view controller's viewWillAppear method is called.
func viewWillAppear()
}
public protocol EmptyStatesViewModelOutputs {
/// Emits a constant float value for the bottom layout constraint.
var bottomLayoutConstraintConstant: Signal<CGFloat, Never> { get }
/// Emits the button text.
var mainButtonText: Signal<String, Never> { get }
/// Emits to notify the delegate to go to Discovery with params.
var notifyDelegateToGoToDiscovery: Signal<DiscoveryParams?, Never> { get }
/// Emits to notify the delegate to go to Friends.
var notifyDelegateToGoToFriends: Signal<(), Never> { get }
/// Emits the subtitle label text.
var subtitleLabelText: Signal<String, Never> { get }
/// Emits the title label text.
var titleLabelText: Signal<String, Never> { get }
}
public protocol EmptyStatesViewModelType {
var inputs: EmptyStatesViewModelInputs { get }
var outputs: EmptyStatesViewModelOutputs { get }
}
public final class EmptyStatesViewModel: EmptyStatesViewModelType, EmptyStatesViewModelInputs,
EmptyStatesViewModelOutputs {
public init() {
let emptyState = Signal.combineLatest(
self.emptyStateProperty.signal.skipNil(),
self.viewWillAppearProperty.signal.take(first: 1)
)
.map(first)
self.mainButtonText = emptyState.map(buttonText(emptyState:))
self.subtitleLabelText = emptyState.map(textForSubtitle(emptyState:))
self.titleLabelText = emptyState.map(textForTitle(emptyState:))
self.notifyDelegateToGoToDiscovery = emptyState
.takeWhen(self.mainButtonTappedProperty.signal)
.filter { $0 != .socialDisabled && $0 != .socialNoPledges }
.map { emptyState -> DiscoveryParams? in
guard emptyState != .activity else { return nil }
return DiscoveryParams.defaults |> DiscoveryParams.lens.sort .~ .magic
}
self.notifyDelegateToGoToFriends = emptyState
.takeWhen(self.mainButtonTappedProperty.signal)
.filter { $0 == .socialDisabled || $0 == .socialNoPledges }
.ignoreValues()
self.bottomLayoutConstraintConstant = emptyState
.map { _ in Styles.grid(5) }
// Tracking
self.mainButtonTappedProperty.signal.observeValues { _ in
AppEnvironment.current.ksrAnalytics.trackExploreButtonClicked()
}
}
fileprivate let emptyStateProperty = MutableProperty<EmptyState?>(nil)
public func configureWith(emptyState: EmptyState?) {
self.emptyStateProperty.value = emptyState
}
fileprivate let mainButtonTappedProperty = MutableProperty(())
public func mainButtonTapped() {
self.mainButtonTappedProperty.value = ()
}
public func setEmptyState(_ emptyState: EmptyState) {
self.emptyStateProperty.value = emptyState
}
fileprivate let viewWillAppearProperty = MutableProperty(())
public func viewWillAppear() {
self.viewWillAppearProperty.value = ()
}
public let bottomLayoutConstraintConstant: Signal<CGFloat, Never>
public let mainButtonText: Signal<String, Never>
public let notifyDelegateToGoToDiscovery: Signal<DiscoveryParams?, Never>
public let notifyDelegateToGoToFriends: Signal<(), Never>
public let subtitleLabelText: Signal<String, Never>
public let titleLabelText: Signal<String, Never>
public var inputs: EmptyStatesViewModelInputs { return self }
public var outputs: EmptyStatesViewModelOutputs { return self }
}
private func textForSubtitle(emptyState: EmptyState) -> String {
switch emptyState {
case .activity:
return Strings.Find_projects_youll_love_in_art_design_film()
case .socialDisabled:
return Strings.Follow_your_Facebook_friends_and_keep_up_with_the_projects()
case .socialNoPledges:
return Strings.Your_friends_havent_backed_any_projects_yet()
case .recommended:
return Strings.Once_you_back_a_project_well_share()
case .starred:
return Strings.Tap_the_star_on_each_project_page_to_save_it()
}
}
private func textForTitle(emptyState: EmptyState) -> String {
switch emptyState {
case .activity:
return Strings.Bring_creative_projects_to_life()
case .socialDisabled:
return Strings.Its_better_with_friends()
case .socialNoPledges:
return Strings.No_pledges_from_friends_yet()
case .recommended:
return Strings.Just_for_you()
case .starred:
return Strings.Something_catch_your_eye()
}
}
private func buttonText(emptyState: EmptyState) -> String {
switch emptyState {
case .socialDisabled:
return Strings.Find_and_follow_friends()
case .socialNoPledges:
return Strings.Follow_more_friends()
case .activity, .recommended, .starred:
return Strings.Explore_projects()
}
}