Files
suixinkan_uikit/suixinkan/Features/LocationReport/ViewModels/LocationReportViewModel.swift

202 lines
6.5 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// LocationReportViewModel.swift
// suixinkan
//
import Foundation
/// ViewModel Android `LocationReportViewModel` +
final class LocationReportViewModel {
private(set) var currentLatitude: Double?
private(set) var currentLongitude: Double?
private(set) var currentAddress: String?
private(set) var isLocating = false
private(set) var isMarking = false
private(set) var markerLatitude: Double?
private(set) var markerLongitude: Double?
private(set) var markerAddress: String?
private(set) var showOnlineStatusDialog = false
private(set) var showLocationReportSuccessDialog = false
private(set) var reportTimeText = ""
let locationStateStore: HomeLocationStateStore
let locationReportService: LocationReportService
var onStateChange: (() -> Void)?
var onShowMessage: ((String) -> Void)?
private let locationProvider: any LocationProviding
init(
locationStateStore: HomeLocationStateStore = .shared,
locationProvider: any LocationProviding = LocationProvider.shared
) {
self.locationStateStore = locationStateStore
self.locationProvider = locationProvider
self.locationReportService = LocationReportService(
locationStateStore: locationStateStore,
locationProvider: locationProvider
)
self.locationStateStore.observe(self) { [weak self] in
self?.notifyStateChange()
}
}
deinit {
locationStateStore.removeObserver(self)
}
var isOnline: Bool { locationStateStore.isOnline }
var countdownDisplayText: String { locationStateStore.countdownDisplayTextSingleHour }
var reminderMinutes: Int { locationStateStore.reminderMinutes }
var isReporting: Bool { locationReportService.isReporting }
/// 线
func restoreStateIfNeeded() {
locationStateStore.restoreStateIfNeeded()
notifyStateChange()
}
///
func startLocation() {
guard !isLocating else { return }
isLocating = true
notifyStateChange()
Task {
defer {
isLocating = false
notifyStateChange()
}
do {
let snapshot = try await locationProvider.requestSnapshot()
currentLatitude = snapshot.latitude
currentLongitude = snapshot.longitude
currentAddress = snapshot.address.isEmpty
? String(format: "%.5f, %.5f", snapshot.latitude, snapshot.longitude)
: snapshot.address
notifyStateChange()
} catch {
onShowMessage?((error as? LocalizedError)?.errorDescription ?? error.localizedDescription)
}
}
}
func toggleMarking() {
isMarking.toggle()
if !isMarking {
markerLatitude = nil
markerLongitude = nil
markerAddress = nil
}
notifyStateChange()
}
///
func setMarkerLocation(latitude: Double, longitude: Double) {
guard isMarking else { return }
markerLatitude = latitude
markerLongitude = longitude
markerAddress = nil
notifyStateChange()
Task {
let address = await locationProvider.reverseGeocode(latitude: latitude, longitude: longitude)
markerAddress = address.isEmpty
? String(format: "%.5f, %.5f", latitude, longitude)
: address
notifyStateChange()
}
}
func showOnlineStatusSwitchDialog() {
showOnlineStatusDialog = true
notifyStateChange()
}
func hideOnlineStatusSwitchDialog() {
showOnlineStatusDialog = false
notifyStateChange()
}
func hideLocationReportSuccessDialog() {
showLocationReportSuccessDialog = false
notifyStateChange()
}
func updateReminderMinutes(_ minutes: Int) {
locationStateStore.updateReminderMinutes(minutes)
notifyStateChange()
}
func switchOnlineStatus(api: HomeAPI) async {
hideOnlineStatusSwitchDialog()
do {
let goingOnline = !isOnline
if let result = try await locationReportService.switchOnlineStatus(api: api) {
applyReportSuccess(result)
onShowMessage?(goingOnline ? "已切换到在线状态,正在上报位置" : "已切换到离线状态")
} else {
onShowMessage?("已切换到离线状态")
}
} catch let error as LocationReportServiceError {
onShowMessage?(error.localizedDescription)
} catch {
onShowMessage?(error.localizedDescription)
}
}
/// type=2 type=1
func reportLocation(api: HomeAPI) async {
if isMarking {
guard let lat = markerLatitude, let lng = markerLongitude else {
onShowMessage?("请先在地图上选择标记点")
return
}
await reportCoordinates(api: api, latitude: lat, longitude: lng, address: markerAddress, type: 2)
return
}
guard let lat = currentLatitude, let lng = currentLongitude else {
onShowMessage?("正在定位中,请稍候")
return
}
await reportCoordinates(api: api, latitude: lat, longitude: lng, address: currentAddress, type: 1)
}
private func reportCoordinates(
api: HomeAPI,
latitude: Double,
longitude: Double,
address: String?,
type: Int
) async {
do {
let result = try await locationReportService.reportWithCoordinates(
api: api,
latitude: latitude,
longitude: longitude,
address: address,
type: type
)
applyReportSuccess(result)
onShowMessage?("位置上报成功")
} catch let error as LocationReportServiceError {
onShowMessage?(error.localizedDescription)
} catch {
onShowMessage?(error.localizedDescription)
}
}
private func applyReportSuccess(_ result: LocationReportSuccessResult) {
if result.shouldShowSuccessDialog {
reportTimeText = result.reportTimeText
showLocationReportSuccessDialog = true
}
notifyStateChange()
}
private func notifyStateChange() {
onStateChange?()
}
}