Use the Emoji/Map/Poll view models. (#4458)

* Toggle emojis in the EmojiPickerScreenViewModel.

* Send locations in the StaticLocationScreen.

* Send polls in the PollFormScreen.
This commit is contained in:
Doug
2025-09-03 16:52:28 +01:00
committed by GitHub
parent 441f5ae975
commit eda37eb626
21 changed files with 398 additions and 255 deletions
@@ -16,7 +16,6 @@ enum LocationSharingViewError: Error, Hashable {
enum StaticLocationScreenViewModelAction {
case close
case openSystemSettings
case sendLocation(GeoURI, isUserLocation: Bool)
}
enum StaticLocationInteractionMode: Hashable {
@@ -11,12 +11,14 @@ import SwiftUI
struct StaticLocationScreenCoordinatorParameters {
let interactionMode: StaticLocationInteractionMode
let mapURLBuilder: MapTilerURLBuilderProtocol
let timelineController: TimelineControllerProtocol
let appMediator: AppMediatorProtocol
let analytics: AnalyticsService
let userIndicatorController: UserIndicatorControllerProtocol
}
enum StaticLocationScreenCoordinatorAction {
case close
case selectedLocation(GeoURI, isUserLocation: Bool)
}
final class StaticLocationScreenCoordinator: CoordinatorProtocol {
@@ -33,7 +35,11 @@ final class StaticLocationScreenCoordinator: CoordinatorProtocol {
init(parameters: StaticLocationScreenCoordinatorParameters) {
self.parameters = parameters
viewModel = StaticLocationScreenViewModel(interactionMode: parameters.interactionMode, mapURLBuilder: parameters.mapURLBuilder)
viewModel = StaticLocationScreenViewModel(interactionMode: parameters.interactionMode,
mapURLBuilder: parameters.mapURLBuilder,
timelineController: parameters.timelineController,
analytics: parameters.analytics,
userIndicatorController: parameters.userIndicatorController)
}
// MARK: - Public
@@ -46,8 +52,6 @@ final class StaticLocationScreenCoordinator: CoordinatorProtocol {
actionsSubject.send(.close)
case .openSystemSettings:
parameters.appMediator.openAppSettings()
case .sendLocation(let geoURI, let isUserLocation):
actionsSubject.send(.selectedLocation(geoURI, isUserLocation: isUserLocation))
}
}
.store(in: &cancellables)
@@ -11,13 +11,24 @@ import Foundation
typealias StaticLocationScreenViewModelType = StateStoreViewModelV2<StaticLocationScreenViewState, StaticLocationScreenViewAction>
class StaticLocationScreenViewModel: StaticLocationScreenViewModelType, StaticLocationScreenViewModelProtocol {
private let actionsSubject: PassthroughSubject<StaticLocationScreenViewModelAction, Never> = .init()
private let timelineController: TimelineControllerProtocol
private let analytics: AnalyticsService
private let userIndicatorController: UserIndicatorControllerProtocol
private let actionsSubject: PassthroughSubject<StaticLocationScreenViewModelAction, Never> = .init()
var actions: AnyPublisher<StaticLocationScreenViewModelAction, Never> {
actionsSubject.eraseToAnyPublisher()
}
init(interactionMode: StaticLocationInteractionMode, mapURLBuilder: MapTilerURLBuilderProtocol) {
init(interactionMode: StaticLocationInteractionMode,
mapURLBuilder: MapTilerURLBuilderProtocol,
timelineController: TimelineControllerProtocol,
analytics: AnalyticsService,
userIndicatorController: UserIndicatorControllerProtocol) {
self.timelineController = timelineController
self.analytics = analytics
self.userIndicatorController = userIndicatorController
super.init(initialViewState: .init(interactionMode: interactionMode, mapURLBuilder: mapURLBuilder))
}
@@ -28,7 +39,7 @@ class StaticLocationScreenViewModel: StaticLocationScreenViewModelType, StaticLo
case .selectLocation:
guard let coordinate = state.bindings.mapCenterLocation else { return }
let uncertainty = state.isSharingUserLocation ? context.geolocationUncertainty : nil
actionsSubject.send(.sendLocation(.init(coordinate: coordinate, uncertainty: uncertainty), isUserLocation: state.isSharingUserLocation))
Task { await sendLocation(.init(coordinate: coordinate, uncertainty: uncertainty), isUserLocation: state.isSharingUserLocation) }
case .userDidPan:
state.bindings.showsUserLocationMode = .show
case .centerToUser:
@@ -43,4 +54,34 @@ class StaticLocationScreenViewModel: StaticLocationScreenViewModelType, StaticLo
}
}
}
// MARK: - Private
private func sendLocation(_ geoURI: GeoURI, isUserLocation: Bool) async {
guard case .success = await timelineController.sendLocation(body: geoURI.bodyMessage,
geoURI: geoURI,
description: nil,
zoomLevel: 15,
assetType: isUserLocation ? .sender : .pin) else {
showErrorIndicator()
return
}
actionsSubject.send(.close)
analytics.trackComposer(inThread: false,
isEditing: false,
isReply: false,
messageType: isUserLocation ? .LocationUser : .LocationPin,
startsThread: nil)
}
private func showErrorIndicator() {
userIndicatorController.submitIndicator(UserIndicator(id: statusIndicatorID,
type: .toast,
title: L10n.errorUnknown,
iconName: "xmark"))
}
private var statusIndicatorID: String { "\(Self.self)-Status" }
}
@@ -148,13 +148,22 @@ struct StaticLocationScreen: View {
struct StaticLocationScreenViewer_Previews: PreviewProvider, TestablePreview {
static let viewModel = StaticLocationScreenViewModel(interactionMode: .viewOnly(geoURI: .init(latitude: 41.9027835,
longitude: 12.4963655)),
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration)
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
timelineController: MockTimelineController(),
analytics: ServiceLocator.shared.analytics,
userIndicatorController: UserIndicatorControllerMock())
static let pickerViewModel = StaticLocationScreenViewModel(interactionMode: .picker,
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration)
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
timelineController: MockTimelineController(),
analytics: ServiceLocator.shared.analytics,
userIndicatorController: UserIndicatorControllerMock())
static let descriptionViewModel = StaticLocationScreenViewModel(interactionMode: .viewOnly(geoURI: .init(latitude: 41.9027835,
longitude: 12.4963655),
description: "Cool position"),
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration)
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
timelineController: MockTimelineController(),
analytics: ServiceLocator.shared.analytics,
userIndicatorController: UserIndicatorControllerMock())
static var previews: some View {
NavigationStack {