// // 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?() } }