```swift=
// MARK: - Itinerary
public let ItineraryPlaceSearchConfigurationStream: PlaceSearchConfigurationStreaming {
init(waypointManager: WaypointManaging) {
fields = waypointManager.waypoints.enumerate().map { (index, value) in
// Value
var value: Place?
switch value.storage {
case .place(let place): value = place
default: value = nil
}
return Field(
value: value
context: index == 0 ? .origin : .destination
)
}
focusingIndex =
}
}
public final class ItineraryStepComponent {
public var searchConfigurationStream: PlaceSearchConfigurationStreaming {
shared { ItineraryPlaceSearchConfigurationStream(waypointManager: waypointManager) }
}
}
public final class ItineraryStepRouter {
func routeToPlaceSearch() {
let router = placeSearchBuilder.build(
listener: interactor,
configuration: searchConfigurationStream
)
...
}
}
public final class ItineraryStepInteractor: PlaceSearchListener {
let configuration: PlaceSearchConfigurationStreaming
// PlaceSearchListener
func didSelect(result: Place) {
let index = currentIndex
let waypoint = Waypoint(storage: .place(place))
waypointManager.update(waypoint: waypoint, at: index)
}
func didSelect(coordinate: Coordinate2D) {
let index = currentIndex
let waypoint = Waypoint(storage: .coordinate(coordinate))
waypointManager.update(waypoint: waypoint, at: index)
}
}
// MARK: - PlaceSearch
public protocol PlaceSearchListener {
func didSelect(result: Place)
func didSelect(coordinate: Coordinate2D)
}
public protocol PlaceMapInteractorListener {
func mapDidChange(location: Coordinate2D)
}
public protocol PlaceSearchConfigurationStreaming {
public struct Field {
public let value: Place?
// public let isFocused: Bool
public let context: LocationSearchContext
}
let fields: Observable<[Field]>
let focusingIndex: Observable<Int> // ???
}
public class PlaceSearchInteractor {
let configuration: PlaceSearchConfigurationStreaming
func mapDidChange(location: Coordinate2D) {
listener.didSelect(coordinate: location)
}
}
public struct PlacesSearchDependency {
let waypointStream: Observable<Waypoint>
}
// MARK: - TextSearch
public protocol TextSearchDependency {
var searchConfigurationStream: PlaceSearchConfigurationStreaming { get }
}
public final class TextSearchComponent: Component<TextSearchDependency>{
let dynamicDependency: PlacesSearchDependency
}
protocol TextSearchInteractorListener: PlacesSearchListener {
func didSelect(result: Place, at index: Int)
// inherited
// func goToViewMode(_ viewMode: ViewMode)
}
class TextSearchRouter {
}
class TextSearchInteractor {
weak var listener: TextSearchInteractorListener?
init(configuration: PlaceSearchConfigurationStreaming)
override func didBecomeActive() {
super.didBecomeActive()
setupObservers()
}
private func setupObservers() {
setupTextFieldObservers()
setupResultObservers()
}
private func setupTextFieldObservers() {
// listen to configuration and set/focus text field accordingly
let fieldValues = configuration.fields.map(\.value)
for index in 0..<fieldValues.count {
fieldValues[index]
.subscribe(
onNext: { [weak self] value in
self?.presenter.setFieldResult(searchResult, at: index)
self?.whatsTheNextStep() // go to next empty index?
}
)
.disposeOnDeactivate(interactor: self)
}
}
private func setupResultObservers() {
// Observe text field change from presenter/VC and update result collection view
}
// View listener
private func didSelect(result: Place, at index: Int) {
listner?.didSelect(result: result, at: index)
}
}
```