Story search

This commit is contained in:
Isaac
2024-06-07 15:22:11 +04:00
parent 9094bb23b8
commit 571e2164b2
28 changed files with 1236 additions and 447 deletions

View File

@@ -5,8 +5,6 @@ import Display
import SwiftSignalKit
import MapKit
let defaultMapSpan = MKCoordinateSpan(latitudeDelta: 0.016, longitudeDelta: 0.016)
let viewMapSpan = MKCoordinateSpan(latitudeDelta: 0.008, longitudeDelta: 0.008)
private let pinOffset = CGPoint(x: 0.0, y: 33.0)
public enum LocationMapMode {
@@ -128,7 +126,10 @@ private func generateProximityDim(size: CGSize) -> UIImage {
})!
}
final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
public final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
public static let defaultMapSpan = MKCoordinateSpan(latitudeDelta: 0.016, longitudeDelta: 0.016)
public static let viewMapSpan = MKCoordinateSpan(latitudeDelta: 0.008, longitudeDelta: 0.008)
class ProximityCircleRenderer: MKCircleRenderer {
override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
super.draw(mapRect, zoomScale: zoomScale, in: context)
@@ -204,7 +205,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
private var circleOverlay: MKCircle?
var activeProximityRadius: Double? {
public var activeProximityRadius: Double? {
didSet {
if let activeProximityRadius = self.activeProximityRadius {
if let circleOverlay = self.circleOverlay {
@@ -225,7 +226,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
}
override init() {
override public init() {
self.pickerAnnotationContainerView = PickerAnnotationContainerView()
self.pickerAnnotationContainerView.isHidden = true
@@ -236,7 +237,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
})
}
override func didLoad() {
override public func didLoad() {
super.didLoad()
self.headingArrowView = UIImageView()
@@ -292,7 +293,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
}
var trackingMode: LocationTrackingMode = .none {
public var trackingMode: LocationTrackingMode = .none {
didSet {
self.mapView?.userTrackingMode = self.trackingMode.userTrackingMode
if self.trackingMode == .followWithHeading && self.headingArrowView?.image != nil {
@@ -303,11 +304,18 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
}
var topPadding: CGFloat = 0.0
var mapOffset: CGFloat = 0.0
func setMapCenter(coordinate: CLLocationCoordinate2D, radius: Double, insets: UIEdgeInsets, offset: CGFloat, animated: Bool = false) {
var hasValidLayout: Bool = false
var pendingSetMapCenter: (coordinate: CLLocationCoordinate2D, span: MKCoordinateSpan, offset: CGPoint, isUserLocation: Bool, hidePicker: Bool, animated: Bool)?
public func setMapCenter(coordinate: CLLocationCoordinate2D, radius: Double, insets: UIEdgeInsets, offset: CGFloat, animated: Bool = false) {
self.mapOffset = offset
self.ignoreRegionChanges = true
var insets = insets
insets.top += self.topPadding
let mapRect = MKMapRect(region: MKCoordinateRegion(center: coordinate, latitudinalMeters: radius * 2.0, longitudinalMeters: radius * 2.0))
self.mapView?.setVisibleMapRect(mapRect, edgePadding: insets, animated: animated)
self.ignoreRegionChanges = false
@@ -315,16 +323,34 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
self.proximityDimView.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY + offset)
}
func setMapCenter(coordinate: CLLocationCoordinate2D, span: MKCoordinateSpan = defaultMapSpan, offset: CGPoint = CGPoint(), isUserLocation: Bool = false, hidePicker: Bool = false, animated: Bool = false) {
public func setMapCenter(coordinate: CLLocationCoordinate2D, span: MKCoordinateSpan = defaultMapSpan, offset: CGPoint = CGPoint(), isUserLocation: Bool = false, hidePicker: Bool = false, animated: Bool = false) {
self.pendingSetMapCenter = (
coordinate, span, offset, isUserLocation, hidePicker, animated
)
if self.hasValidLayout {
self.applyPendingSetMapCenter()
}
}
private func applyPendingSetMapCenter() {
if !self.hasValidLayout {
return
}
guard let (coordinate, span, offset, isUserLocation, hidePicker, animated) = self.pendingSetMapCenter else {
return
}
self.pendingSetMapCenter = nil
let region = MKCoordinateRegion(center: coordinate, span: span)
self.ignoreRegionChanges = true
if offset == CGPoint() {
if offset == CGPoint() && self.topPadding == 0.0 {
self.mapView?.setRegion(region, animated: animated)
} else {
let mapRect = MKMapRect(region: region)
self.mapView?.setVisibleMapRect(mapRect, edgePadding: UIEdgeInsets(top: offset.y, left: offset.x, bottom: 0.0, right: 0.0), animated: animated)
self.mapView?.setVisibleMapRect(mapRect, edgePadding: UIEdgeInsets(top: offset.y + self.topPadding, left: offset.x, bottom: 0.0, right: 0.0), animated: animated)
}
self.ignoreRegionChanges = false
self.ignoreRegionChanges = false
if isUserLocation {
if !self.returnedToUserLocation {
@@ -339,7 +365,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
}
func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
public func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
guard !self.ignoreRegionChanges, let scrollView = mapView.subviews.first, let gestureRecognizers = scrollView.gestureRecognizers else {
return
}
@@ -356,7 +382,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
}
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
public func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
let wasDragging = self.isDragging
if self.isDragging {
self.isDragging = false
@@ -372,7 +398,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
}
func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
public func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
guard let location = userLocation.location else {
return
}
@@ -380,11 +406,11 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
self.locationPromise.set(.single(location))
}
func mapView(_ mapView: MKMapView, didFailToLocateUserWithError error: Error) {
public func mapView(_ mapView: MKMapView, didFailToLocateUserWithError error: Error) {
self.locationPromise.set(.single(nil))
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
public func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation === mapView.userLocation {
return nil
}
@@ -400,7 +426,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
return nil
}
func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
public func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
for view in views {
if view.annotation is MKUserLocation {
self.defaultUserLocationAnnotation = view.annotation
@@ -424,7 +450,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
public func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
guard let annotation = view.annotation as? LocationPinAnnotation else {
return
}
@@ -440,7 +466,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
}
func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
public func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
if let view = view as? LocationPinAnnotationView {
Queue.mainQueue().after(0.2) {
view.setZPosition(view.defaultZPosition)
@@ -459,7 +485,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
public func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if let circle = overlay as? MKCircle {
let renderer = ProximityCircleRenderer(circle: circle)
renderer.fillColor = .clear
@@ -472,7 +498,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
}
var distancesToAllAnnotations: Signal<[Double], NoError> {
public var distancesToAllAnnotations: Signal<[Double], NoError> {
let poll = Signal<[LocationPinAnnotation], NoError> { [weak self] subscriber in
if let strongSelf = self {
subscriber.putNext(strongSelf.annotations)
@@ -497,30 +523,30 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
}
var currentUserLocation: CLLocation? {
public var currentUserLocation: CLLocation? {
return self.mapView?.userLocation.location
}
var userLocation: Signal<CLLocation?, NoError> {
public var userLocation: Signal<CLLocation?, NoError> {
return .single(self.currentUserLocation)
|> then (self.locationPromise.get())
}
var mapCenterCoordinate: CLLocationCoordinate2D? {
public var mapCenterCoordinate: CLLocationCoordinate2D? {
guard let mapView = self.mapView else {
return nil
}
return mapView.convert(CGPoint(x: (mapView.frame.width + pinOffset.x) / 2.0, y: (mapView.frame.height + pinOffset.y) / 2.0), toCoordinateFrom: mapView)
}
var mapSpan: MKCoordinateSpan? {
public var mapSpan: MKCoordinateSpan? {
guard let mapView = self.mapView else {
return nil
}
return mapView.region.span
}
func resetAnnotationSelection() {
public func resetAnnotationSelection() {
guard let mapView = self.mapView else {
return
}
@@ -529,8 +555,8 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
}
var pickerAnnotationView: LocationPinAnnotationView? = nil
var hasPickerAnnotation: Bool = false {
public var pickerAnnotationView: LocationPinAnnotationView? = nil
public var hasPickerAnnotation: Bool = false {
didSet {
if self.hasPickerAnnotation, let annotation = self.userLocationAnnotation {
let pickerAnnotationView = LocationPinAnnotationView(annotation: annotation)
@@ -544,7 +570,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
}
func switchToPicking(raise: Bool = false, animated: Bool) {
public func switchToPicking(raise: Bool = false, animated: Bool) {
guard self.hasPickerAnnotation else {
return
}
@@ -561,8 +587,8 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
self.resetScheduledPin()
}
var customUserLocationAnnotationView: LocationPinAnnotationView? = nil
var userLocationAnnotation: LocationPinAnnotation? = nil {
public var customUserLocationAnnotationView: LocationPinAnnotationView? = nil
public var userLocationAnnotation: LocationPinAnnotation? = nil {
didSet {
if let annotation = self.userLocationAnnotation {
self.customUserLocationAnnotationView?.removeFromSuperview()
@@ -582,7 +608,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
}
var userHeading: CGFloat? = nil {
public var userHeading: CGFloat? = nil {
didSet {
if let heading = self.userHeading {
self.headingArrowView?.isHidden = false
@@ -594,7 +620,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
}
var annotations: [LocationPinAnnotation] = [] {
public var annotations: [LocationPinAnnotation] = [] {
didSet {
guard let mapView = self.mapView else {
return
@@ -709,7 +735,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
self.pinDisposable.set(nil)
}
func showAll(animated: Bool = true) {
public func showAll(animated: Bool = true) {
guard let mapView = self.mapView else {
return
}
@@ -736,11 +762,17 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
}
}
func updateLayout(size: CGSize) {
self.proximityDimView.frame = CGRect(origin: CGPoint(x: 0.0, y: self.mapOffset), size: size)
public func updateLayout(size: CGSize, topPadding: CGFloat) {
self.hasValidLayout = true
self.topPadding = topPadding
self.proximityDimView.frame = CGRect(origin: CGPoint(x: 0.0, y: self.topPadding + self.mapOffset), size: size)
self.pickerAnnotationContainerView.frame = CGRect(x: 0.0, y: floorToScreenPixels((size.height - size.width) / 2.0), width: size.width, height: size.width)
if let pickerAnnotationView = self.pickerAnnotationView {
pickerAnnotationView.center = CGPoint(x: self.pickerAnnotationContainerView.frame.width / 2.0, y: self.pickerAnnotationContainerView.frame.height / 2.0)
}
self.applyPendingSetMapCenter()
}
}