Fixed error on location picker screen
This commit is contained in:
parent
23224eb2bf
commit
81bdf64b61
@ -1657,7 +1657,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 160;
|
||||
CURRENT_PROJECT_VERSION = 161;
|
||||
DEVELOPMENT_TEAM = 46DTTB8X4S;
|
||||
INFOPLIST_FILE = AutoCat/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = AutoCat;
|
||||
@ -1686,7 +1686,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 160;
|
||||
CURRENT_PROJECT_VERSION = 161;
|
||||
DEVELOPMENT_TEAM = 46DTTB8X4S;
|
||||
INFOPLIST_FILE = AutoCat/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = AutoCat;
|
||||
|
||||
@ -39,7 +39,7 @@ class EventsViewModel: ACHudContainer {
|
||||
var showPasteAlert: Bool = false
|
||||
var pastedEvent: VehicleEventDto?
|
||||
|
||||
var onUpdate: (VehicleDto) -> Void
|
||||
var onUpdate: ((VehicleDto) -> Void)?
|
||||
|
||||
var isPasteAvailable: Bool {
|
||||
#if os(macOS)
|
||||
@ -54,11 +54,13 @@ class EventsViewModel: ACHudContainer {
|
||||
settingsService.user.hasPermission(.locationAuthor)
|
||||
}
|
||||
|
||||
init(apiService: ApiServiceProtocol,
|
||||
storageService: StorageServiceProtocol,
|
||||
settingsService: SettingsServiceProtocol,
|
||||
vehicle: VehicleDto,
|
||||
onUpdate: @escaping (VehicleDto) -> Void) {
|
||||
init(
|
||||
apiService: ApiServiceProtocol,
|
||||
storageService: StorageServiceProtocol,
|
||||
settingsService: SettingsServiceProtocol,
|
||||
vehicle: VehicleDto,
|
||||
onUpdate: ((VehicleDto) -> Void)? = nil
|
||||
) {
|
||||
|
||||
self.apiService = apiService
|
||||
self.storageService = storageService
|
||||
@ -93,7 +95,7 @@ class EventsViewModel: ACHudContainer {
|
||||
}
|
||||
|
||||
if !initialLoad {
|
||||
onUpdate(vehicle)
|
||||
onUpdate?(vehicle)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -33,12 +33,12 @@ class FiltersViewModel {
|
||||
|
||||
@ObservationIgnored var currentBrand: StringOption = .any
|
||||
|
||||
let onUpdate: (Filter) -> Void
|
||||
let onUpdate: ((Filter) -> Void)?
|
||||
|
||||
init(
|
||||
apiService: ApiServiceProtocol,
|
||||
filter: Filter,
|
||||
onUpdate: @escaping (Filter) -> Void
|
||||
onUpdate: ((Filter) -> Void)? = nil
|
||||
) {
|
||||
self.apiService = apiService
|
||||
self.filter = filter
|
||||
@ -65,7 +65,7 @@ class FiltersViewModel {
|
||||
}
|
||||
|
||||
func applyFilters() {
|
||||
onUpdate(filter)
|
||||
onUpdate?(filter)
|
||||
}
|
||||
|
||||
func nullifyTime(of date: Date?) -> Date? {
|
||||
|
||||
@ -27,7 +27,7 @@ struct LocationPickerScreen: View {
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Map(initialPosition: viewModel.position)
|
||||
Map(position: $viewModel.position)
|
||||
.mapControls {
|
||||
MapUserLocationButton()
|
||||
}
|
||||
@ -43,6 +43,7 @@ struct LocationPickerScreen: View {
|
||||
.foregroundColor(.blue)
|
||||
}
|
||||
//.ignoresSafeArea()
|
||||
.onAppear(perform: viewModel.onAppear)
|
||||
.navigationTitle(viewModel.event.location)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
|
||||
@ -18,19 +18,26 @@ final class LocationPickerViewModel {
|
||||
let locationService: LocationServiceProtocol
|
||||
|
||||
var event: VehicleEventDto
|
||||
var position: MapCameraPosition
|
||||
var position: MapCameraPosition = .automatic
|
||||
|
||||
var onUpdate: (VehicleEventDto) -> Void
|
||||
var onUpdate: ((VehicleEventDto) -> Void)?
|
||||
|
||||
@ObservationIgnored
|
||||
@AutoCancellable
|
||||
var geocoderTask: Task<Void, Never>?
|
||||
|
||||
init(
|
||||
locationService: LocationServiceProtocol,
|
||||
event: VehicleEventDto,
|
||||
onUpdate: @escaping (VehicleEventDto) -> Void
|
||||
onUpdate: ((VehicleEventDto) -> Void)? = nil
|
||||
) {
|
||||
|
||||
self.locationService = locationService
|
||||
self.event = event
|
||||
self.onUpdate = onUpdate
|
||||
}
|
||||
|
||||
func onAppear() {
|
||||
|
||||
if event.latitude == 0 && event.longitude == 0 {
|
||||
self.position = .userLocation(fallback: .automatic)
|
||||
@ -43,11 +50,24 @@ final class LocationPickerViewModel {
|
||||
func updateEvent(center: CLLocationCoordinate2D) async {
|
||||
event.latitude = center.latitude
|
||||
event.longitude = center.longitude
|
||||
event.address = try? await locationService.getAddressForLocation(latitude: center.latitude,
|
||||
longitude: center.longitude)
|
||||
|
||||
geocoderTask = Task {
|
||||
try? await Task.sleep(for: .milliseconds(200))
|
||||
|
||||
if Task.isCancelled {
|
||||
return
|
||||
}
|
||||
|
||||
event.address = try? await locationService.getAddressForLocation(
|
||||
latitude: center.latitude,
|
||||
longitude: center.longitude
|
||||
)
|
||||
}
|
||||
|
||||
_ = await geocoderTask?.result
|
||||
}
|
||||
|
||||
func done() {
|
||||
onUpdate(event)
|
||||
onUpdate?(event)
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,13 +28,13 @@ class NotesViewModel: ACHudContainer {
|
||||
var vehicle: VehicleDto
|
||||
var hud: ACHud?
|
||||
|
||||
var onUpdate: (VehicleDto) -> Void
|
||||
var onUpdate: ((VehicleDto) -> Void)?
|
||||
|
||||
init(
|
||||
storageService: StorageServiceProtocol,
|
||||
apiService: ApiServiceProtocol,
|
||||
vehicle: VehicleDto,
|
||||
onUpdate: @escaping (VehicleDto) -> Void
|
||||
onUpdate: ((VehicleDto) -> Void)? = nil
|
||||
) {
|
||||
|
||||
self.storageService = storageService
|
||||
@ -80,7 +80,7 @@ class NotesViewModel: ACHudContainer {
|
||||
await wrapWithToast(showProgress: false) { [weak self] in
|
||||
guard let self else { throw GenericError.somethingWentWrong }
|
||||
vehicle = try await storageOp()
|
||||
onUpdate(vehicle)
|
||||
onUpdate?(vehicle)
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -90,7 +90,7 @@ class NotesViewModel: ACHudContainer {
|
||||
let vehicle = try await apiOp()
|
||||
try await storageService.updateVehicle(dto: vehicle, policy: .ifExists)
|
||||
self.vehicle = vehicle
|
||||
onUpdate(vehicle)
|
||||
onUpdate?(vehicle)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ class ReportViewModel: ACHudContainer {
|
||||
var vehicle: VehicleDto
|
||||
var hud: ACHud?
|
||||
|
||||
let onUpdate: (VehicleDto) -> Void
|
||||
let onUpdate: ((VehicleDto) -> Void)?
|
||||
|
||||
var plateNumber: String {
|
||||
if vehicle.outdated, let current = vehicle.currentNumber {
|
||||
@ -55,12 +55,14 @@ class ReportViewModel: ACHudContainer {
|
||||
return URL(string: Constants.reportLinkBaseURL + "?token=" + jwt)
|
||||
}
|
||||
|
||||
init(apiService: ApiServiceProtocol,
|
||||
storageService: StorageServiceProtocol,
|
||||
settingsService: SettingsServiceProtocol,
|
||||
vehicle: VehicleDto,
|
||||
isPersistent: Bool,
|
||||
onUpdate: @escaping (VehicleDto) -> Void) {
|
||||
init(
|
||||
apiService: ApiServiceProtocol,
|
||||
storageService: StorageServiceProtocol,
|
||||
settingsService: SettingsServiceProtocol,
|
||||
vehicle: VehicleDto,
|
||||
isPersistent: Bool,
|
||||
onUpdate: ((VehicleDto) -> Void)? = nil
|
||||
) {
|
||||
|
||||
self.apiService = apiService
|
||||
self.storageService = storageService
|
||||
@ -97,12 +99,12 @@ class ReportViewModel: ACHudContainer {
|
||||
guard let self else { throw GenericError.somethingWentWrong }
|
||||
vehicle = try await apiService.checkVehicleGb(by: vehicle.getNumber())
|
||||
try await storageService.updateVehicle(dto: vehicle, policy: .ifExists)
|
||||
onUpdate(vehicle)
|
||||
onUpdate?(vehicle)
|
||||
}
|
||||
}
|
||||
|
||||
func onVehicleChanged(_ vehicle: VehicleDto) {
|
||||
self.vehicle = vehicle
|
||||
onUpdate(vehicle)
|
||||
onUpdate?(vehicle)
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,8 +140,8 @@ struct HistoryTests {
|
||||
let updatedVehicle: VehicleDto = .normal.addNote(text: "123")
|
||||
|
||||
given(storageServiceMock)
|
||||
.loadVehicles()
|
||||
.willReturn([.normal])
|
||||
.loadVehicles().willReturn([.normal])
|
||||
.loadVehicles().willReturn([updatedVehicle])
|
||||
|
||||
given(storageServiceMock)
|
||||
.dbFileURL
|
||||
@ -151,14 +151,6 @@ struct HistoryTests {
|
||||
.updateHistory(number: .any)
|
||||
.willReturn((vehicle: updatedVehicle, errors: []))
|
||||
|
||||
when(storageServiceMock)
|
||||
.loadVehicles()
|
||||
.perform {
|
||||
given(storageServiceMock)
|
||||
.loadVehicles()
|
||||
.willReturn([updatedVehicle])
|
||||
}
|
||||
|
||||
await viewModel.onAppear()
|
||||
await viewModel.updateVehicle(.normal)
|
||||
|
||||
@ -168,7 +160,7 @@ struct HistoryTests {
|
||||
|
||||
verify(storageServiceMock)
|
||||
.loadVehicles()
|
||||
.called(.exactly(3))
|
||||
.called(.exactly(2))
|
||||
|
||||
#expect(viewModel.vehicles.count == 1)
|
||||
#expect(viewModel.vehiclesFiltered.count == 1)
|
||||
|
||||
@ -22,32 +22,30 @@ struct LocationPickerTests {
|
||||
let longitude: CLLocationDegrees = 10
|
||||
let address = "Test Address"
|
||||
|
||||
let geocoderMock = MockGeocoderProtocol()
|
||||
let locationServiceMock = MockLocationServiceProtocol()
|
||||
|
||||
func makeViewModel(event: VehicleEventDto) -> LocationPickerViewModel {
|
||||
|
||||
let locationService = LocationService(
|
||||
geocoder: geocoderMock,
|
||||
locationManager: MockSwiftLocationProtocol(),
|
||||
settingsService: MockSettingsServiceProtocol()
|
||||
return LocationPickerViewModel(
|
||||
locationService: locationServiceMock,
|
||||
event: event
|
||||
)
|
||||
|
||||
return LocationPickerViewModel(locationService: locationService,
|
||||
event: event)
|
||||
}
|
||||
|
||||
@Test("Set initial location (user)")
|
||||
func setInitialLocationUser() async throws {
|
||||
|
||||
let viewModel = makeViewModel(event: .init(lat: 0, lon: 0, addedBy: nil))
|
||||
viewModel.onAppear()
|
||||
|
||||
#expect(viewModel.position == .userLocation(fallback: .automatic))
|
||||
}
|
||||
|
||||
|
||||
@Test("Set initial location (custom)")
|
||||
func setInitialLocationCustom() async throws {
|
||||
|
||||
let viewModel = makeViewModel(event: .init(lat: latitude, lon: longitude, addedBy: nil))
|
||||
viewModel.onAppear()
|
||||
|
||||
#expect(viewModel.position.region?.center.latitude == latitude)
|
||||
#expect(viewModel.position.region?.center.longitude == longitude)
|
||||
@ -58,12 +56,9 @@ struct LocationPickerTests {
|
||||
|
||||
let viewModel = makeViewModel(event: .init(lat: 0, lon: 0, addedBy: nil))
|
||||
|
||||
let location = CLLocation(latitude: latitude, longitude: longitude)
|
||||
let placemark = CLPlacemark(location: location, name: address, postalAddress: nil)
|
||||
|
||||
given(geocoderMock)
|
||||
.reverseGeocodeLocation(.any)
|
||||
.willReturn([placemark])
|
||||
given(locationServiceMock)
|
||||
.getAddressForLocation(latitude: .value(latitude), longitude: .value(longitude))
|
||||
.willReturn(address)
|
||||
|
||||
await viewModel.updateEvent(center: .init(latitude: latitude, longitude: longitude))
|
||||
|
||||
@ -71,4 +66,32 @@ struct LocationPickerTests {
|
||||
#expect(viewModel.event.longitude == longitude)
|
||||
#expect(viewModel.event.address == address)
|
||||
}
|
||||
|
||||
@Test("Update event (throttling)")
|
||||
func updateEventThrottling() async throws {
|
||||
|
||||
let viewModel = makeViewModel(event: .init(lat: 0, lon: 0, addedBy: nil))
|
||||
|
||||
let initialLocation = CLLocationCoordinate2D(latitude: 0, longitude: 0)
|
||||
let finalLocation = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
|
||||
|
||||
given(locationServiceMock)
|
||||
.getAddressForLocation(latitude: .value(0), longitude: .value(0)).willReturn("")
|
||||
.getAddressForLocation(latitude: .value(latitude), longitude: .value(longitude)).willReturn(address)
|
||||
|
||||
viewModel.onAppear()
|
||||
|
||||
async let task1: () = viewModel.updateEvent(center: initialLocation)
|
||||
async let task2: () = viewModel.updateEvent(center: initialLocation)
|
||||
async let task3: () = viewModel.updateEvent(center: finalLocation)
|
||||
_ = await (task1, task2, task3)
|
||||
|
||||
verify(locationServiceMock)
|
||||
.getAddressForLocation(latitude: .value(0), longitude: .value(0)).called(.never)
|
||||
.getAddressForLocation(latitude: .value(latitude), longitude: .value(longitude)).called(.once)
|
||||
|
||||
#expect(viewModel.event.latitude == latitude)
|
||||
#expect(viewModel.event.longitude == longitude)
|
||||
#expect(viewModel.event.address == address)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user