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

@@ -26,10 +26,10 @@ private func generateSmallBackgroundImage(color: UIColor) -> UIImage? {
})
}
class LocationPinAnnotation: NSObject, MKAnnotation {
public class LocationPinAnnotation: NSObject, MKAnnotation {
let context: AccountContext
let theme: PresentationTheme
var coordinate: CLLocationCoordinate2D {
public var coordinate: CLLocationCoordinate2D {
willSet {
self.willChangeValue(forKey: "coordinate")
}
@@ -55,10 +55,10 @@ class LocationPinAnnotation: NSObject, MKAnnotation {
var isSelf = false
var selfPeer: EnginePeer?
var title: String? = ""
var subtitle: String? = ""
public var title: String? = ""
public var subtitle: String? = ""
init(context: AccountContext, theme: PresentationTheme, peer: EnginePeer?) {
public init(context: AccountContext, theme: PresentationTheme, peer: EnginePeer?) {
self.context = context
self.theme = theme
self.location = nil
@@ -71,7 +71,7 @@ class LocationPinAnnotation: NSObject, MKAnnotation {
super.init()
}
init(context: AccountContext, theme: PresentationTheme, location: TelegramMediaMap, queryId: Int64?, resultId: String?, forcedSelection: Bool = false) {
public init(context: AccountContext, theme: PresentationTheme, location: TelegramMediaMap, queryId: Int64?, resultId: String?, forcedSelection: Bool = false) {
self.context = context
self.theme = theme
self.location = location
@@ -84,7 +84,7 @@ class LocationPinAnnotation: NSObject, MKAnnotation {
super.init()
}
init(context: AccountContext, theme: PresentationTheme, message: EngineMessage, selfPeer: EnginePeer?, isSelf: Bool, heading: Int32?) {
public init(context: AccountContext, theme: PresentationTheme, message: EngineMessage, selfPeer: EnginePeer?, isSelf: Bool, heading: Int32?) {
self.context = context
self.theme = theme
self.location = nil
@@ -104,7 +104,7 @@ class LocationPinAnnotation: NSObject, MKAnnotation {
super.init()
}
var id: String {
public var id: String {
if let message = self.message {
return "\(message.id.id)"
} else if let peer = self.peer {
@@ -157,7 +157,7 @@ private func removePulseAnimations(layer: CALayer) {
layer.removeAnimation(forKey: "pulse-opacity")
}
class LocationPinAnnotationView: MKAnnotationView {
public class LocationPinAnnotationView: MKAnnotationView {
let shadowNode: ASImageNode
let pulseNode: ASImageNode
let backgroundNode: ASImageNode
@@ -178,17 +178,17 @@ class LocationPinAnnotationView: MKAnnotationView {
var headingKvoToken: NSKeyValueObservation?
override class var layerClass: AnyClass {
override public class var layerClass: AnyClass {
return LocationPinAnnotationLayer.self
}
func setZPosition(_ zPosition: CGFloat?) {
public func setZPosition(_ zPosition: CGFloat?) {
if let layer = self.layer as? LocationPinAnnotationLayer {
layer.customZPosition = zPosition
}
}
init(annotation: LocationPinAnnotation) {
public init(annotation: LocationPinAnnotation) {
self.shadowNode = ASImageNode()
self.shadowNode.image = UIImage(bundleImageName: "Location/PinShadow")
if let image = self.shadowNode.image {
@@ -244,7 +244,7 @@ class LocationPinAnnotationView: MKAnnotationView {
self.annotation = annotation
}
required init?(coder aDecoder: NSCoder) {
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@@ -252,7 +252,7 @@ class LocationPinAnnotationView: MKAnnotationView {
self.headingKvoToken?.invalidate()
}
var defaultZPosition: CGFloat {
public var defaultZPosition: CGFloat {
if let annotation = self.annotation as? LocationPinAnnotation {
if annotation.forcedSelection {
return 0.0
@@ -266,7 +266,7 @@ class LocationPinAnnotationView: MKAnnotationView {
}
}
override var annotation: MKAnnotation? {
override public var annotation: MKAnnotation? {
didSet {
if let annotation = self.annotation as? LocationPinAnnotation {
if let message = annotation.message {
@@ -363,14 +363,14 @@ class LocationPinAnnotationView: MKAnnotationView {
}
}
override func prepareForReuse() {
override public func prepareForReuse() {
self.previousPeerId = nil
self.smallNode.isHidden = true
self.backgroundNode.isHidden = false
self.appeared = false
}
override func setSelected(_ selected: Bool, animated: Bool) {
override public func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
if let annotation = self.annotation as? LocationPinAnnotation {
@@ -547,7 +547,7 @@ class LocationPinAnnotationView: MKAnnotationView {
}
var previousPeerId: EnginePeer.Id?
func setPeer(context: AccountContext, theme: PresentationTheme, peer: EnginePeer) {
public func setPeer(context: AccountContext, theme: PresentationTheme, peer: EnginePeer) {
let avatarNode: AvatarNode
if let currentAvatarNode = self.avatarNode {
avatarNode = currentAvatarNode
@@ -566,7 +566,7 @@ class LocationPinAnnotationView: MKAnnotationView {
}
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
override public func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if let labelNode = self.labelNode {
@@ -589,7 +589,7 @@ class LocationPinAnnotationView: MKAnnotationView {
}
var isRaised = false
func setRaised(_ raised: Bool, animated: Bool, completion: @escaping () -> Void = {}) {
public func setRaised(_ raised: Bool, animated: Bool, completion: @escaping () -> Void = {}) {
guard raised != self.isRaised else {
return
}
@@ -625,7 +625,7 @@ class LocationPinAnnotationView: MKAnnotationView {
}
}
func setCustom(_ custom: Bool, animated: Bool) {
public func setCustom(_ custom: Bool, animated: Bool) {
if let annotation = self.annotation as? LocationPinAnnotation {
self.iconNode.setSignal(venueIcon(engine: annotation.context.engine, type: "", background: false))
}
@@ -676,7 +676,7 @@ class LocationPinAnnotationView: MKAnnotationView {
self.dotNode.isHidden = !custom
}
func animateAppearance() {
public func animateAppearance() {
guard let annotation = self.annotation as? LocationPinAnnotation, annotation.location != nil && !annotation.forcedSelection else {
return
}
@@ -694,7 +694,7 @@ class LocationPinAnnotationView: MKAnnotationView {
}
}
override func layoutSubviews() {
override public func layoutSubviews() {
super.layoutSubviews()
guard !self.animating else {

View File

@@ -11,7 +11,7 @@ import AppBundle
import SolidRoundedButtonNode
import ShimmerEffect
final class LocationInfoListItem: ListViewItem {
public final class LocationInfoListItem: ListViewItem {
let presentationData: ItemListPresentationData
let engine: TelegramEngine
let location: TelegramMediaMap
@@ -75,7 +75,7 @@ final class LocationInfoListItem: ListViewItem {
}
}
final class LocationInfoListItemNode: ListViewItemNode {
public final class LocationInfoListItemNode: ListViewItemNode {
private let backgroundNode: ASDisplayNode
private var titleNode: TextNode?
private var subtitleNode: TextNode?
@@ -91,7 +91,7 @@ final class LocationInfoListItemNode: ListViewItemNode {
private var layoutParams: ListViewItemLayoutParams?
private var absoluteLocation: (CGRect, CGSize)?
required init() {
required public init() {
self.backgroundNode = ASDisplayNode()
self.backgroundNode.isLayerBacked = true
self.buttonNode = HighlightableButtonNode()
@@ -127,7 +127,7 @@ final class LocationInfoListItemNode: ListViewItemNode {
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
}
override func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) {
override public func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) {
if let item = self.item {
let makeLayout = self.asyncLayout()
let (nodeLayout, nodeApply) = makeLayout(item, params)
@@ -137,7 +137,7 @@ final class LocationInfoListItemNode: ListViewItemNode {
}
}
func asyncLayout() -> (_ item: LocationInfoListItem, _ params: ListViewItemLayoutParams) -> (ListViewItemNodeLayout, () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) {
public func asyncLayout() -> (_ item: LocationInfoListItem, _ params: ListViewItemLayoutParams) -> (ListViewItemNodeLayout, () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) {
let currentItem = self.item
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
@@ -205,6 +205,8 @@ final class LocationInfoListItemNode: ListViewItemNode {
strongSelf.backgroundNode.backgroundColor = item.presentationData.theme.list.plainBackgroundColor
}
strongSelf.backgroundNode.isHidden = params.isStandalone
let arguments = VenueIconArguments(defaultBackgroundColor: item.presentationData.theme.chat.inputPanel.actionControlFillColor, defaultForegroundColor: item.presentationData.theme.chat.inputPanel.actionControlForegroundColor)
if let updatedLocation = updatedLocation {
strongSelf.venueIconNode.setSignal(venueIcon(engine: item.engine, type: updatedLocation.venue?.type ?? "", background: true))
@@ -384,11 +386,11 @@ final class LocationInfoListItemNode: ListViewItemNode {
}
}
override func animateInsertion(_ currentTimestamp: Double, duration: Double, options: ListViewItemAnimationOptions) {
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, options: ListViewItemAnimationOptions) {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration * 0.5)
}
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false)
}

View File

@@ -34,7 +34,7 @@ private func generateShadowImage(theme: PresentationTheme, highlighted: Bool) ->
})?.stretchableImage(withLeftCapWidth: 13, topCapHeight: 0)
}
final class LocationMapHeaderNode: ASDisplayNode {
public final class LocationMapHeaderNode: ASDisplayNode {
private var presentationData: PresentationData
private let toggleMapModeSelection: () -> Void
private let goToUserLocation: () -> Void
@@ -44,8 +44,8 @@ final class LocationMapHeaderNode: ASDisplayNode {
private var displayingPlacesButton = false
private var proximityNotification: Bool?
let mapNode: LocationMapNode
var trackingMode: LocationTrackingMode = .none
public let mapNode: LocationMapNode
public var trackingMode: LocationTrackingMode = .none
private let optionsBackgroundNode: ASImageNode
private let optionsSeparatorNode: ASDisplayNode
@@ -59,7 +59,7 @@ final class LocationMapHeaderNode: ASDisplayNode {
private var validLayout: (ContainerViewLayout, CGFloat, CGFloat, CGFloat, CGSize)?
init(presentationData: PresentationData, toggleMapModeSelection: @escaping () -> Void, goToUserLocation: @escaping () -> Void, setupProximityNotification: @escaping (Bool) -> Void = { _ in }, showPlacesInThisArea: @escaping () -> Void = {}) {
public init(presentationData: PresentationData, toggleMapModeSelection: @escaping () -> Void, goToUserLocation: @escaping () -> Void, setupProximityNotification: @escaping (Bool) -> Void = { _ in }, showPlacesInThisArea: @escaping () -> Void = {}) {
self.presentationData = presentationData
self.toggleMapModeSelection = toggleMapModeSelection
self.goToUserLocation = goToUserLocation
@@ -131,7 +131,7 @@ final class LocationMapHeaderNode: ASDisplayNode {
self.placesButtonNode.addTarget(self, action: #selector(self.placesPressed), forControlEvents: .touchUpInside)
}
func updateState(mapMode: LocationMapMode, trackingMode: LocationTrackingMode, displayingMapModeOptions: Bool, displayingPlacesButton: Bool, proximityNotification: Bool?, animated: Bool) {
public func updateState(mapMode: LocationMapMode, trackingMode: LocationTrackingMode, displayingMapModeOptions: Bool, displayingPlacesButton: Bool, proximityNotification: Bool?, animated: Bool) {
self.mapNode.mapMode = mapMode
self.trackingMode = trackingMode
self.infoButtonNode.isSelected = displayingMapModeOptions
@@ -149,7 +149,7 @@ final class LocationMapHeaderNode: ASDisplayNode {
}
}
func updatePresentationData(_ presentationData: PresentationData) {
public func updatePresentationData(_ presentationData: PresentationData) {
self.presentationData = presentationData
self.optionsBackgroundNode.image = generateBackgroundImage(theme: presentationData.theme)
@@ -177,13 +177,13 @@ final class LocationMapHeaderNode: ASDisplayNode {
}
}
func updateLayout(layout: ContainerViewLayout, navigationBarHeight: CGFloat, topPadding: CGFloat, offset: CGFloat, size: CGSize, transition: ContainedViewLayoutTransition) {
public func updateLayout(layout: ContainerViewLayout, navigationBarHeight: CGFloat, topPadding: CGFloat, offset: CGFloat, size: CGSize, transition: ContainedViewLayoutTransition) {
self.validLayout = (layout, navigationBarHeight, topPadding, offset, size)
let mapHeight: CGFloat = floor(layout.size.height * 1.3)
let mapFrame = CGRect(x: 0.0, y: floorToScreenPixels((size.height - mapHeight + navigationBarHeight) / 2.0) + offset, width: size.width, height: mapHeight)
transition.updateFrame(node: self.mapNode, frame: mapFrame)
self.mapNode.updateLayout(size: mapFrame.size)
self.mapNode.updateLayout(size: mapFrame.size, topPadding: layout.intrinsicInsets.top)
let inset: CGFloat = 6.0
@@ -191,6 +191,8 @@ final class LocationMapHeaderNode: ASDisplayNode {
let placesButtonFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - placesButtonSize.width) / 2.0), y: self.displayingPlacesButton ? navigationBarHeight + topPadding + inset : 0.0), size: placesButtonSize)
transition.updateFrame(node: self.placesBackgroundNode, frame: placesButtonFrame)
transition.updateFrame(node: self.placesButtonNode, frame: CGRect(origin: CGPoint(), size: placesButtonSize))
transition.updateAlpha(node: self.placesBackgroundNode, alpha: self.displayingPlacesButton ? 1.0 : 0.0)
transition.updateAlpha(node: self.placesButtonNode, alpha: self.displayingPlacesButton ? 1.0 : 0.0)
transition.updateFrame(node: self.shadowNode, frame: CGRect(x: 0.0, y: size.height - 14.0, width: size.width, height: 14.0))
@@ -214,7 +216,7 @@ final class LocationMapHeaderNode: ASDisplayNode {
alphaTransition.updateAlpha(node: self.optionsBackgroundNode, alpha: optionsAlpha)
}
var forceIsHidden: Bool = false {
public var forceIsHidden: Bool = false {
didSet {
if let (layout, navigationBarHeight, topPadding, offset, size) = self.validLayout {
self.updateLayout(layout: layout, navigationBarHeight: navigationBarHeight, topPadding: topPadding, offset: offset, size: size, transition: .immediate)
@@ -222,11 +224,11 @@ final class LocationMapHeaderNode: ASDisplayNode {
}
}
func updateHighlight(_ highlighted: Bool) {
public func updateHighlight(_ highlighted: Bool) {
self.shadowNode.image = generateShadowImage(theme: self.presentationData.theme, highlighted: highlighted)
}
func proximityButtonFrame() -> CGRect? {
public func proximityButtonFrame() -> CGRect? {
if self.notificationButtonNode.alpha > 0.0 {
return self.optionsBackgroundNode.view.convert(self.notificationButtonNode.frame, to: self.view)
} else {

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

View File

@@ -6,14 +6,14 @@ import TelegramCore
import TelegramPresentationData
import SegmentedControlNode
final class LocationOptionsNode: ASDisplayNode {
public final class LocationOptionsNode: ASDisplayNode {
private var presentationData: PresentationData
private let backgroundNode: NavigationBackgroundNode
private let separatorNode: ASDisplayNode
private let segmentedControlNode: SegmentedControlNode
init(presentationData: PresentationData, updateMapMode: @escaping (LocationMapMode) -> Void) {
public init(presentationData: PresentationData, hasBackground: Bool = true, updateMapMode: @escaping (LocationMapMode) -> Void) {
self.presentationData = presentationData
self.backgroundNode = NavigationBackgroundNode(color: self.presentationData.theme.rootController.navigationBar.blurredBackgroundColor)
@@ -24,8 +24,11 @@ final class LocationOptionsNode: ASDisplayNode {
super.init()
self.addSubnode(self.backgroundNode)
self.addSubnode(self.separatorNode)
if hasBackground {
self.addSubnode(self.backgroundNode)
self.addSubnode(self.separatorNode)
}
self.addSubnode(self.segmentedControlNode)
self.segmentedControlNode.selectedIndexChanged = { index in
@@ -42,14 +45,14 @@ final class LocationOptionsNode: ASDisplayNode {
}
}
func updatePresentationData(_ presentationData: PresentationData) {
public func updatePresentationData(_ presentationData: PresentationData) {
self.presentationData = presentationData
self.backgroundNode.updateColor(color: self.presentationData.theme.rootController.navigationBar.blurredBackgroundColor, transition: .immediate)
self.separatorNode.backgroundColor = self.presentationData.theme.rootController.navigationBar.separatorColor
self.segmentedControlNode.updateTheme(SegmentedControlTheme(theme: self.presentationData.theme))
}
func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
public func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size))
self.backgroundNode.update(size: size, transition: transition)

View File

@@ -101,7 +101,7 @@ func stringForEstimatedDuration(strings: PresentationStrings, time: Double, form
}
}
func throttledUserLocation(_ userLocation: Signal<CLLocation?, NoError>) -> Signal<CLLocation?, NoError> {
public func throttledUserLocation(_ userLocation: Signal<CLLocation?, NoError>) -> Signal<CLLocation?, NoError> {
return userLocation
|> reduceLeft(value: nil) { current, updated, emit -> CLLocation? in
if let current = current {
@@ -126,13 +126,13 @@ func throttledUserLocation(_ userLocation: Signal<CLLocation?, NoError>) -> Sign
}
}
enum ExpectedTravelTime: Equatable {
public enum ExpectedTravelTime: Equatable {
case unknown
case calculating
case ready(Double)
}
func getExpectedTravelTime(coordinate: CLLocationCoordinate2D, transportType: MKDirectionsTransportType) -> Signal<ExpectedTravelTime, NoError> {
public func getExpectedTravelTime(coordinate: CLLocationCoordinate2D, transportType: MKDirectionsTransportType) -> Signal<ExpectedTravelTime, NoError> {
return Signal { subscriber in
subscriber.putNext(.calculating)

View File

@@ -41,159 +41,159 @@ private struct LocationViewTransaction {
let animated: Bool
}
private enum LocationViewEntryId: Hashable {
public enum LocationViewEntryId: Hashable {
case info
case toggleLiveLocation(Bool)
case liveLocation(UInt32)
}
private enum LocationViewEntry: Comparable, Identifiable {
public enum LocationViewEntry: Comparable, Identifiable {
case info(PresentationTheme, TelegramMediaMap, String?, Double?, ExpectedTravelTime, ExpectedTravelTime, ExpectedTravelTime, Bool)
case toggleLiveLocation(PresentationTheme, String, String, Double?, Double?, Bool, EngineMessage.Id?)
case liveLocation(PresentationTheme, PresentationDateTimeFormat, PresentationPersonNameOrder, EngineMessage, Double?, ExpectedTravelTime, ExpectedTravelTime, ExpectedTravelTime, Int)
var stableId: LocationViewEntryId {
public var stableId: LocationViewEntryId {
switch self {
case .info:
return .info
case let .toggleLiveLocation(_, _, _, _, _, additional, _):
return .toggleLiveLocation(additional)
case let .liveLocation(_, _, _, message, _, _, _, _, _):
return .liveLocation(message.stableId)
case .info:
return .info
case let .toggleLiveLocation(_, _, _, _, _, additional, _):
return .toggleLiveLocation(additional)
case let .liveLocation(_, _, _, message, _, _, _, _, _):
return .liveLocation(message.stableId)
}
}
static func ==(lhs: LocationViewEntry, rhs: LocationViewEntry) -> Bool {
public static func ==(lhs: LocationViewEntry, rhs: LocationViewEntry) -> Bool {
switch lhs {
case let .info(lhsTheme, lhsLocation, lhsAddress, lhsDistance, lhsDrivingTime, lhsTransitTime, lhsWalkingTime, lhsHasEta):
if case let .info(rhsTheme, rhsLocation, rhsAddress, rhsDistance, rhsDrivingTime, rhsTransitTime, rhsWalkingTime, rhsHasEta) = rhs, lhsTheme === rhsTheme, lhsLocation.venue?.id == rhsLocation.venue?.id, lhsAddress == rhsAddress, lhsDistance == rhsDistance, lhsDrivingTime == rhsDrivingTime, lhsTransitTime == rhsTransitTime, lhsWalkingTime == rhsWalkingTime, lhsHasEta == rhsHasEta {
return true
} else {
return false
}
case let .toggleLiveLocation(lhsTheme, lhsTitle, lhsSubtitle, lhsBeginTimestamp, lhsTimeout, lhsAdditional, lhsMessageId):
if case let .toggleLiveLocation(rhsTheme, rhsTitle, rhsSubtitle, rhsBeginTimestamp, rhsTimeout, rhsAdditional, rhsMessageId) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsSubtitle == rhsSubtitle, lhsBeginTimestamp == rhsBeginTimestamp, lhsTimeout == rhsTimeout, lhsAdditional == rhsAdditional, lhsMessageId == rhsMessageId {
return true
} else {
return false
}
case let .liveLocation(lhsTheme, lhsDateTimeFormat, lhsNameDisplayOrder, lhsMessage, lhsDistance, lhsDrivingTime, lhsTransitTime, lhsWalkingTime, lhsIndex):
if case let .liveLocation(rhsTheme, rhsDateTimeFormat, rhsNameDisplayOrder, rhsMessage, rhsDistance, rhsDrivingTime, rhsTransitTime, rhsWalkingTime, rhsIndex) = rhs, lhsTheme === rhsTheme, lhsDateTimeFormat == rhsDateTimeFormat, lhsNameDisplayOrder == rhsNameDisplayOrder, areMessagesEqual(lhsMessage, rhsMessage), lhsDistance == rhsDistance, lhsDrivingTime == rhsDrivingTime, lhsTransitTime == rhsTransitTime, lhsWalkingTime == rhsWalkingTime, lhsIndex == rhsIndex {
return true
} else {
return false
}
}
}
static func <(lhs: LocationViewEntry, rhs: LocationViewEntry) -> Bool {
switch lhs {
case .info:
switch rhs {
case .info:
return false
case .toggleLiveLocation, .liveLocation:
return true
}
case let .toggleLiveLocation(_, _, _, _, _, lhsAdditional, _):
switch rhs {
case .info:
return false
case let .toggleLiveLocation(_, _, _, _, _, rhsAdditional, _):
return !lhsAdditional && rhsAdditional
case .liveLocation:
return true
case let .info(lhsTheme, lhsLocation, lhsAddress, lhsDistance, lhsDrivingTime, lhsTransitTime, lhsWalkingTime, lhsHasEta):
if case let .info(rhsTheme, rhsLocation, rhsAddress, rhsDistance, rhsDrivingTime, rhsTransitTime, rhsWalkingTime, rhsHasEta) = rhs, lhsTheme === rhsTheme, lhsLocation.venue?.id == rhsLocation.venue?.id, lhsAddress == rhsAddress, lhsDistance == rhsDistance, lhsDrivingTime == rhsDrivingTime, lhsTransitTime == rhsTransitTime, lhsWalkingTime == rhsWalkingTime, lhsHasEta == rhsHasEta {
return true
} else {
return false
}
case let .toggleLiveLocation(lhsTheme, lhsTitle, lhsSubtitle, lhsBeginTimestamp, lhsTimeout, lhsAdditional, lhsMessageId):
if case let .toggleLiveLocation(rhsTheme, rhsTitle, rhsSubtitle, rhsBeginTimestamp, rhsTimeout, rhsAdditional, rhsMessageId) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsSubtitle == rhsSubtitle, lhsBeginTimestamp == rhsBeginTimestamp, lhsTimeout == rhsTimeout, lhsAdditional == rhsAdditional, lhsMessageId == rhsMessageId {
return true
} else {
return false
}
case let .liveLocation(lhsTheme, lhsDateTimeFormat, lhsNameDisplayOrder, lhsMessage, lhsDistance, lhsDrivingTime, lhsTransitTime, lhsWalkingTime, lhsIndex):
if case let .liveLocation(rhsTheme, rhsDateTimeFormat, rhsNameDisplayOrder, rhsMessage, rhsDistance, rhsDrivingTime, rhsTransitTime, rhsWalkingTime, rhsIndex) = rhs, lhsTheme === rhsTheme, lhsDateTimeFormat == rhsDateTimeFormat, lhsNameDisplayOrder == rhsNameDisplayOrder, areMessagesEqual(lhsMessage, rhsMessage), lhsDistance == rhsDistance, lhsDrivingTime == rhsDrivingTime, lhsTransitTime == rhsTransitTime, lhsWalkingTime == rhsWalkingTime, lhsIndex == rhsIndex {
return true
} else {
return false
}
}
}
public static func <(lhs: LocationViewEntry, rhs: LocationViewEntry) -> Bool {
switch lhs {
case .info:
switch rhs {
case .info:
return false
case .toggleLiveLocation, .liveLocation:
return true
}
case let .toggleLiveLocation(_, _, _, _, _, lhsAdditional, _):
switch rhs {
case .info:
return false
case let .toggleLiveLocation(_, _, _, _, _, rhsAdditional, _):
return !lhsAdditional && rhsAdditional
case .liveLocation:
return true
}
case let .liveLocation(_, _, _, _, _, _, _, _, lhsIndex):
switch rhs {
case .info, .toggleLiveLocation:
return false
case let .liveLocation(_, _, _, _, _, _, _, _, rhsIndex):
return lhsIndex < rhsIndex
}
case let .liveLocation(_, _, _, _, _, _, _, _, lhsIndex):
switch rhs {
case .info, .toggleLiveLocation:
return false
case let .liveLocation(_, _, _, _, _, _, _, _, rhsIndex):
return lhsIndex < rhsIndex
}
}
}
func item(context: AccountContext, presentationData: PresentationData, interaction: LocationViewInteraction?) -> ListViewItem {
switch self {
case let .info(_, location, address, distance, drivingTime, transitTime, walkingTime, hasEta):
let addressString: String?
if let address = address {
addressString = address
} else {
addressString = presentationData.strings.Map_Locating
}
let distanceString: String?
if let distance = distance {
distanceString = distance < 10 ? presentationData.strings.Map_YouAreHere : presentationData.strings.Map_DistanceAway(stringForDistance(strings: presentationData.strings, distance: distance)).string
} else {
distanceString = nil
}
return LocationInfoListItem(presentationData: ItemListPresentationData(presentationData), engine: context.engine, location: location, address: addressString, distance: distanceString, drivingTime: drivingTime, transitTime: transitTime, walkingTime: walkingTime, hasEta: hasEta, action: {
interaction?.goToCoordinate(location.coordinate)
}, drivingAction: {
interaction?.requestDirections(location, nil, .driving)
}, transitAction: {
interaction?.requestDirections(location, nil, .transit)
}, walkingAction: {
interaction?.requestDirections(location, nil, .walking)
})
case let .toggleLiveLocation(_, title, subtitle, beginTimstamp, timeout, additional, messageId):
var beginTimeAndTimeout: (Double, Double)?
if let beginTimstamp = beginTimstamp, let timeout = timeout {
beginTimeAndTimeout = (beginTimstamp, timeout)
} else {
beginTimeAndTimeout = nil
}
case let .info(_, location, address, distance, drivingTime, transitTime, walkingTime, hasEta):
let addressString: String?
if let address = address {
addressString = address
} else {
addressString = presentationData.strings.Map_Locating
}
let distanceString: String?
if let distance = distance {
distanceString = distance < 10 ? presentationData.strings.Map_YouAreHere : presentationData.strings.Map_DistanceAway(stringForDistance(strings: presentationData.strings, distance: distance)).string
} else {
distanceString = nil
}
return LocationInfoListItem(presentationData: ItemListPresentationData(presentationData), engine: context.engine, location: location, address: addressString, distance: distanceString, drivingTime: drivingTime, transitTime: transitTime, walkingTime: walkingTime, hasEta: hasEta, action: {
interaction?.goToCoordinate(location.coordinate)
}, drivingAction: {
interaction?.requestDirections(location, nil, .driving)
}, transitAction: {
interaction?.requestDirections(location, nil, .transit)
}, walkingAction: {
interaction?.requestDirections(location, nil, .walking)
})
case let .toggleLiveLocation(_, title, subtitle, beginTimstamp, timeout, additional, messageId):
var beginTimeAndTimeout: (Double, Double)?
if let beginTimstamp = beginTimstamp, let timeout = timeout {
beginTimeAndTimeout = (beginTimstamp, timeout)
} else {
beginTimeAndTimeout = nil
}
let icon: LocationActionListItemIcon
if let timeout, Int32(timeout) != liveLocationIndefinitePeriod, !additional {
icon = .extendLiveLocation
} else if beginTimeAndTimeout != nil {
icon = .stopLiveLocation
} else {
icon = .liveLocation
}
let icon: LocationActionListItemIcon
if let timeout, Int32(timeout) != liveLocationIndefinitePeriod, !additional {
icon = .extendLiveLocation
} else if beginTimeAndTimeout != nil {
icon = .stopLiveLocation
} else {
icon = .liveLocation
}
return LocationActionListItem(presentationData: ItemListPresentationData(presentationData), engine: context.engine, title: title, subtitle: subtitle, icon: icon, beginTimeAndTimeout: !additional ? beginTimeAndTimeout : nil, action: {
if beginTimeAndTimeout != nil {
if let timeout, Int32(timeout) != liveLocationIndefinitePeriod {
if additional {
interaction?.stopLiveLocation()
} else {
interaction?.sendLiveLocation(nil, true, messageId)
}
} else {
return LocationActionListItem(presentationData: ItemListPresentationData(presentationData), engine: context.engine, title: title, subtitle: subtitle, icon: icon, beginTimeAndTimeout: !additional ? beginTimeAndTimeout : nil, action: {
if beginTimeAndTimeout != nil {
if let timeout, Int32(timeout) != liveLocationIndefinitePeriod {
if additional {
interaction?.stopLiveLocation()
} else {
interaction?.sendLiveLocation(nil, true, messageId)
}
} else {
interaction?.sendLiveLocation(nil, false, nil)
interaction?.stopLiveLocation()
}
}, highlighted: { highlight in
interaction?.updateSendActionHighlight(highlight)
})
case let .liveLocation(_, dateTimeFormat, nameDisplayOrder, message, distance, drivingTime, transitTime, walkingTime, _):
var title: String?
if let author = message.author {
title = author.displayTitle(strings: presentationData.strings, displayOrder: nameDisplayOrder)
} else {
interaction?.sendLiveLocation(nil, false, nil)
}
return LocationLiveListItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: context, message: message, distance: distance, drivingTime: drivingTime, transitTime: transitTime, walkingTime: walkingTime, action: {
if let location = getLocation(from: message) {
interaction?.goToCoordinate(location.coordinate)
}
}, longTapAction: {}, drivingAction: {
if let location = getLocation(from: message) {
interaction?.requestDirections(location, title, .driving)
}
}, transitAction: {
if let location = getLocation(from: message) {
interaction?.requestDirections(location, title, .transit)
}
}, walkingAction: {
if let location = getLocation(from: message) {
interaction?.requestDirections(location, title, .walking)
}
})
}, highlighted: { highlight in
interaction?.updateSendActionHighlight(highlight)
})
case let .liveLocation(_, dateTimeFormat, nameDisplayOrder, message, distance, drivingTime, transitTime, walkingTime, _):
var title: String?
if let author = message.author {
title = author.displayTitle(strings: presentationData.strings, displayOrder: nameDisplayOrder)
}
return LocationLiveListItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: context, message: message, distance: distance, drivingTime: drivingTime, transitTime: transitTime, walkingTime: walkingTime, action: {
if let location = getLocation(from: message) {
interaction?.goToCoordinate(location.coordinate)
}
}, longTapAction: {}, drivingAction: {
if let location = getLocation(from: message) {
interaction?.requestDirections(location, title, .driving)
}
}, transitAction: {
if let location = getLocation(from: message) {
interaction?.requestDirections(location, title, .transit)
}
}, walkingAction: {
if let location = getLocation(from: message) {
interaction?.requestDirections(location, title, .walking)
}
})
}
}
}
@@ -208,22 +208,22 @@ private func preparedTransition(from fromEntries: [LocationViewEntry], to toEntr
return LocationViewTransaction(deletions: deletions, insertions: insertions, updates: updates, gotTravelTimes: gotTravelTimes, count: toEntries.count, animated: animated)
}
enum LocationViewLocation: Equatable {
public enum LocationViewLocation: Equatable {
case initial
case user
case coordinate(CLLocationCoordinate2D, Bool)
case custom
}
struct LocationViewState {
var mapMode: LocationMapMode
var displayingMapModeOptions: Bool
var selectedLocation: LocationViewLocation
var trackingMode: LocationTrackingMode
var updatingProximityRadius: Int32?
var cancellingProximityRadius: Bool
public struct LocationViewState {
public var mapMode: LocationMapMode
public var displayingMapModeOptions: Bool
public var selectedLocation: LocationViewLocation
public var trackingMode: LocationTrackingMode
public var updatingProximityRadius: Int32?
public var cancellingProximityRadius: Bool
init() {
public init() {
self.mapMode = .map
self.displayingMapModeOptions = false
self.selectedLocation = .initial
@@ -614,12 +614,12 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
switch state.selectedLocation {
case .initial:
if previousState?.selectedLocation != .initial {
strongSelf.headerNode.mapNode.setMapCenter(coordinate: location.coordinate, span: viewMapSpan, animated: previousState != nil)
strongSelf.headerNode.mapNode.setMapCenter(coordinate: location.coordinate, span: LocationMapNode.viewMapSpan, animated: previousState != nil)
}
case let .coordinate(coordinate, defaultSpan):
if let previousState = previousState, case let .coordinate(previousCoordinate, _) = previousState.selectedLocation, previousCoordinate == coordinate {
} else {
strongSelf.headerNode.mapNode.setMapCenter(coordinate: coordinate, span: defaultSpan ? defaultMapSpan : viewMapSpan, animated: true)
strongSelf.headerNode.mapNode.setMapCenter(coordinate: coordinate, span: defaultSpan ? LocationMapNode.defaultMapSpan : LocationMapNode.viewMapSpan, animated: true)
}
case .user:
if previousState?.selectedLocation != .user, let userLocation = userLocation {