jsdw_ios/QuickLocation/Section/Home/HomeViewController.swift

181 lines
5.7 KiB
Swift

//
// HomeViewController.swift
// QuickLocation
//
// Created by on 2026/5/27.
//
import UIKit
import RxSwift
import CoreLocation
#if !targetEnvironment(simulator)
import MAMapKit
#endif
class HomeViewController: BaseViewController {
override var isNavigationBarHidden: Bool { true }
override var preferredStatusBarStyle: UIStatusBarStyle { .default }
// MARK: - Properties
fileprivate var rootView: HomeView!
private let locationManager = CLLocationManager()
private var currentHeading: Double = 0
private var members: [CircleMember] = []
private var currentUserMember: CircleMember?
override func loadView() {
#if !targetEnvironment(simulator)
MAMapView.updatePrivacyAgree(.didAgree)
MAMapView.updatePrivacyShow(.didShow, privacyInfo: .didContain)
#endif
rootView = HomeView(frame: UIScreen.main.bounds)
view = rootView
}
override func viewDidLoad() {
super.viewDidLoad()
setupMap()
setupLocation()
loadMembers()
requestUserInfo()
}
// MARK: - Map Setup
private func setupMap() {
#if !targetEnvironment(simulator)
rootView.mapView.delegate = self
let r = MAUserLocationRepresentation()
r.showsAccuracyRing = false
r.showsHeadingIndicator = false
rootView.mapView.update(r)
#endif
}
// MARK: - Location
private func setupLocation() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingHeading()
locationManager.startUpdatingLocation()
}
// MARK: - Members
private func loadMembers() {
members = .mock
currentUserMember = members.first { $0.isCurrentUser }
updateAnnotations()
centerOnMembers()
}
private func centerOnMembers() {
#if !targetEnvironment(simulator)
guard !members.isEmpty else { return }
if let current = currentUserMember {
rootView.mapView.setCenter(current.coordinate, animated: false)
} else if let first = members.first {
rootView.mapView.setCenter(first.coordinate, animated: false)
}
#endif
}
// MARK: - Annotations
private func updateAnnotations() {
#if !targetEnvironment(simulator)
let mapView = rootView.mapView
let existing = mapView.annotations ?? []
let existingMemberIDs = Set(existing.compactMap { ($0 as? MemberAnnotation)?.member.id })
let newMemberIDs = Set(members.map { $0.id })
let toRemove = existing.filter { ann in
guard let ma = ann as? MemberAnnotation else { return false }
return !newMemberIDs.contains(ma.member.id)
}
mapView.removeAnnotations(toRemove)
let toAdd = members.filter { !$0.isCurrentUser && !existingMemberIDs.contains($0.id) }
let annotations = toAdd.map { MemberAnnotation(member: $0) }
mapView.addAnnotations(annotations)
#endif
}
// MARK: - Heading
private func updateCurrentUserHeading() {
#if !targetEnvironment(simulator)
guard let annotations = rootView.mapView.annotations else { return }
for ann in annotations {
guard ann is MAUserLocation else { continue }
if let view = rootView.mapView.view(for: ann as! MAAnnotation) as? MemberAnnotationView {
view.updateHeading(currentHeading)
}
break
}
#endif
}
// MARK: - API
private func requestUserInfo() {
UserService.userInfo().subscribe { response in
}.disposed(by: disposeBag)
}
}
#if !targetEnvironment(simulator)
// MARK: - MAMapViewDelegate
extension HomeViewController: MAMapViewDelegate {
func mapView(_ mapView: MAMapView!, viewFor annotation: MAAnnotation!) -> MAAnnotationView! {
if annotation is MAUserLocation {
let identifier = "UserLocationAnnotation"
var view = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MemberAnnotationView
if view == nil {
view = MemberAnnotationView(annotation: annotation, reuseIdentifier: identifier)
}
if let currentUser = currentUserMember {
view?.configure(with: currentUser)
}
return view
}
guard let memberAnnotation = annotation as? MemberAnnotation else { return nil }
let identifier = "MemberAnnotation"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MemberAnnotationView
if annotationView == nil {
annotationView = MemberAnnotationView(annotation: memberAnnotation, reuseIdentifier: identifier)
} else {
annotationView?.annotation = memberAnnotation
}
annotationView?.configure(with: memberAnnotation.member)
return annotationView
}
}
#endif
// MARK: - CLLocationManagerDelegate
extension HomeViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
let h = newHeading.trueHeading
guard h >= 0 else { return }
currentHeading = h
updateCurrentUserHeading()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
#if !targetEnvironment(simulator)
guard let location = locations.last else { return }
rootView.mapView.setCenter(location.coordinate, animated: true)
#endif
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
}
}