import Foundation import UIKit import Display import ComponentFlow import ListSectionComponent import MapKit import TelegramPresentationData import AppBundle final class MapPreviewComponent: Component { struct Location: Equatable { var latitude: Double var longitude: Double init(latitude: Double, longitude: Double) { self.latitude = latitude self.longitude = longitude } } let theme: PresentationTheme let location: Location let action: (() -> Void)? init( theme: PresentationTheme, location: Location, action: (() -> Void)? = nil ) { self.theme = theme self.location = location self.action = action } static func ==(lhs: MapPreviewComponent, rhs: MapPreviewComponent) -> Bool { if lhs.theme !== rhs.theme { return false } if lhs.location != rhs.location { return false } if (lhs.action == nil) != (rhs.action == nil) { return false } return true } final class View: HighlightTrackingButton, ListSectionComponent.ChildView { private var component: MapPreviewComponent? private weak var componentState: EmptyComponentState? private var mapView: MKMapView? private let pinShadowView: UIImageView private let pinView: UIImageView private let pinForegroundView: UIImageView var customUpdateIsHighlighted: ((Bool) -> Void)? private(set) var separatorInset: CGFloat = 0.0 override init(frame: CGRect) { self.pinShadowView = UIImageView() self.pinView = UIImageView() self.pinForegroundView = UIImageView() super.init(frame: frame) self.addSubview(self.pinShadowView) self.addSubview(self.pinView) self.addSubview(self.pinForegroundView) self.pinShadowView.image = UIImage(bundleImageName: "Chat/Message/LocationPinShadow") self.pinView.image = UIImage(bundleImageName: "Chat/Message/LocationPinBackground")?.withRenderingMode(.alwaysTemplate) self.pinForegroundView.image = UIImage(bundleImageName: "Chat/Message/LocationPinForeground")?.withRenderingMode(.alwaysTemplate) self.addTarget(self, action: #selector(self.pressed), for: .touchUpInside) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } @objc private func pressed() { self.component?.action?() } func update(component: MapPreviewComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { let previousComponent = self.component self.component = component self.componentState = state self.isEnabled = component.action != nil let size = CGSize(width: availableSize.width, height: 160.0) let mapView: MKMapView if let current = self.mapView { mapView = current } else { mapView = MKMapView() mapView.isUserInteractionEnabled = false self.mapView = mapView self.insertSubview(mapView, at: 0) } transition.setFrame(view: mapView, frame: CGRect(origin: CGPoint(), size: size)) let defaultMapSpan = MKCoordinateSpan(latitudeDelta: 0.016, longitudeDelta: 0.016) let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: component.location.latitude, longitude: component.location.longitude), span: defaultMapSpan) if previousComponent?.location != component.location { mapView.setRegion(region, animated: false) mapView.setVisibleMapRect(mapView.visibleMapRect, edgePadding: UIEdgeInsets(top: 70.0, left: 0.0, bottom: 0.0, right: 0.0), animated: true) } let pinImageSize = self.pinView.image?.size ?? CGSize(width: 62.0, height: 74.0) let pinFrame = CGRect(origin: CGPoint(x: floor((size.width - pinImageSize.width) * 0.5), y: floor((size.height - pinImageSize.height) * 0.5)), size: pinImageSize) transition.setFrame(view: self.pinShadowView, frame: pinFrame) transition.setFrame(view: self.pinView, frame: pinFrame) self.pinView.tintColor = component.theme.list.itemCheckColors.fillColor if let image = pinForegroundView.image { let pinIconFrame = CGRect(origin: CGPoint(x: pinFrame.minX + floor((pinFrame.width - image.size.width) * 0.5), y: pinFrame.minY + 15.0), size: image.size) transition.setFrame(view: self.pinForegroundView, frame: pinIconFrame) self.pinForegroundView.tintColor = component.theme.list.itemCheckColors.foregroundColor } return size } } func makeView() -> View { return View(frame: CGRect()) } func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) } }