// // 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) { } }