-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathCuratedProjectsViewModel.swift
112 lines (91 loc) · 3.78 KB
/
CuratedProjectsViewModel.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
import Foundation
import KsApi
import Prelude
import ReactiveSwift
public typealias ProjectData = (project: Project, projects: [Project], refTag: RefTag)
public protocol CuratedProjectsViewModelInputs {
func configure(with categories: [KsApi.Category])
func doneButtonTapped()
func projectTapped(_ project: Project?)
func viewDidLoad()
}
public protocol CuratedProjectsViewModelOutputs {
var dismissViewController: Signal<Void, Never> { get }
var goToProject: Signal<ProjectData, Never> { get }
var isLoading: Signal<Bool, Never> { get }
var loadProjects: Signal<[Project], Never> { get }
var showErrorMessage: Signal<String, Never> { get }
}
public protocol CuratedProjectsViewModelType {
var inputs: CuratedProjectsViewModelInputs { get }
var outputs: CuratedProjectsViewModelOutputs { get }
}
public final class CuratedProjectsViewModel: CuratedProjectsViewModelType, CuratedProjectsViewModelInputs,
CuratedProjectsViewModelOutputs {
public init() {
let curatedProjects: Signal<[Project], Never> = self.categoriesSignal
.combineLatest(with: self.viewDidLoadSignal.ignoreValues())
.map(first)
.filter { !$0.isEmpty }
.flatMap { categories in
projects(from: categories)
.flatten()
.reduce([], +)
}
.map { $0.shuffled() }
self.loadProjects = curatedProjects
self.showErrorMessage = curatedProjects
.filter { $0.isEmpty }
.ignoreValues()
.map { _ in Strings.general_error_something_wrong() }
self.dismissViewController = self.doneButtonTappedSignal
self.isLoading = Signal.merge(
self.viewDidLoadSignal.mapConst(true),
curatedProjects.mapConst(false)
)
self.goToProject = curatedProjects
.takePairWhen(self.projectTappedSignal.skipNil())
.map { projects, project in (project, projects, RefTag.onboarding) }
}
private let (categoriesSignal, categoriesObserver) = Signal<[KsApi.Category], Never>.pipe()
public func configure(with categories: [KsApi.Category]) {
self.categoriesObserver.send(value: categories)
}
private let (doneButtonTappedSignal, doneButtonTappedObserver) = Signal<Void, Never>.pipe()
public func doneButtonTapped() {
self.doneButtonTappedObserver.send(value: ())
}
private let (projectTappedSignal, projectTappedObserver) = Signal<Project?, Never>.pipe()
public func projectTapped(_ project: Project?) {
self.projectTappedObserver.send(value: project)
}
private let (viewDidLoadSignal, viewDidLoadObserver) = Signal<Void, Never>.pipe()
public func viewDidLoad() {
self.viewDidLoadObserver.send(value: ())
}
public let dismissViewController: Signal<Void, Never>
public let goToProject: Signal<ProjectData, Never>
public let isLoading: Signal<Bool, Never>
public let loadProjects: Signal<[Project], Never>
public let showErrorMessage: Signal<String, Never>
public var inputs: CuratedProjectsViewModelInputs { return self }
public var outputs: CuratedProjectsViewModelOutputs { return self }
}
private func projects(from categories: [KsApi.Category])
-> SignalProducer<[[Project]], Never> {
return SignalProducer.combineLatest(producers(from: categories))
}
private func producers(from categories: [KsApi.Category])
-> [SignalProducer<[Project], Never>] {
let projectsPerCategory = Int(floor(Float(30 / categories.count)))
return categories.map { category in
let params = DiscoveryParams.defaults
|> DiscoveryParams.lens.category .~ category
|> DiscoveryParams.lens.state .~ .live
|> DiscoveryParams.lens.perPage .~ projectsPerCategory
return AppEnvironment.current.apiService.fetchDiscovery(params: params)
.ksr_delay(AppEnvironment.current.apiDelayInterval, on: AppEnvironment.current.scheduler)
.map { $0.projects }
.demoteErrors(replaceErrorWith: [])
}
}