mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Location picker fixes
This commit is contained in:
parent
06f3b42cde
commit
3b931cfd96
@ -5145,3 +5145,4 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"AuthSessions.AddDevice" = "Add Device";
|
||||
|
||||
"Map.SendThisPlace" = "Send This Place";
|
||||
"Map.SetThisPlace" = "Set This Place";
|
||||
|
@ -79,7 +79,7 @@ private func generateLiveLocationIcon(theme: PresentationTheme) -> UIImage {
|
||||
}!
|
||||
}
|
||||
|
||||
public class LocationActionListItem: ListViewItem {
|
||||
final class LocationActionListItem: ListViewItem {
|
||||
let presentationData: ItemListPresentationData
|
||||
let account: Account
|
||||
let title: String
|
||||
@ -136,7 +136,7 @@ public class LocationActionListItem: ListViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
class LocationActionListItemNode: ListViewItemNode {
|
||||
final class LocationActionListItemNode: ListViewItemNode {
|
||||
private let backgroundNode: ASDisplayNode
|
||||
private let separatorNode: ASDisplayNode
|
||||
private let highlightedBackgroundNode: ASDisplayNode
|
||||
|
@ -2,6 +2,7 @@ import Foundation
|
||||
import UIKit
|
||||
import MapKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import SyncCore
|
||||
import TelegramCore
|
||||
@ -30,14 +31,26 @@ class LocationPinAnnotation: NSObject, MKAnnotation {
|
||||
let account: Account
|
||||
let theme: PresentationTheme
|
||||
var coordinate: CLLocationCoordinate2D
|
||||
let location: TelegramMediaMap
|
||||
let location: TelegramMediaMap?
|
||||
let peer: Peer?
|
||||
|
||||
var title: String? = ""
|
||||
var subtitle: String? = ""
|
||||
|
||||
init(account: Account, theme: PresentationTheme, peer: Peer) {
|
||||
self.account = account
|
||||
self.theme = theme
|
||||
self.location = nil
|
||||
self.peer = peer
|
||||
self.coordinate = kCLLocationCoordinate2DInvalid
|
||||
super.init()
|
||||
}
|
||||
|
||||
init(account: Account, theme: PresentationTheme, location: TelegramMediaMap) {
|
||||
self.account = account
|
||||
self.theme = theme
|
||||
self.location = location
|
||||
self.peer = nil
|
||||
self.coordinate = location.coordinate
|
||||
super.init()
|
||||
}
|
||||
@ -133,20 +146,29 @@ class LocationPinAnnotationView: MKAnnotationView {
|
||||
override var annotation: MKAnnotation? {
|
||||
didSet {
|
||||
if let annotation = self.annotation as? LocationPinAnnotation {
|
||||
let venueType = annotation.location.venue?.type ?? ""
|
||||
let color = venueType.isEmpty ? annotation.theme.list.itemAccentColor : venueIconColor(type: venueType)
|
||||
self.backgroundNode.image = generateTintedImage(image: UIImage(bundleImageName: "Location/PinBackground"), color: color)
|
||||
self.iconNode.setSignal(venueIcon(postbox: annotation.account.postbox, type: annotation.location.venue?.type ?? "", background: false))
|
||||
self.smallIconNode.setSignal(venueIcon(postbox: annotation.account.postbox, type: annotation.location.venue?.type ?? "", background: false))
|
||||
self.smallNode.image = generateSmallBackgroundImage(color: color)
|
||||
self.dotNode.image = generateFilledCircleImage(diameter: 6.0, color: color)
|
||||
|
||||
self.dotNode.isHidden = false
|
||||
|
||||
if !self.isSelected {
|
||||
self.dotNode.alpha = 0.0
|
||||
self.shadowNode.isHidden = true
|
||||
self.smallNode.isHidden = false
|
||||
if let peer = annotation.peer {
|
||||
self.iconNode.isHidden = true
|
||||
self.dotNode.isHidden = true
|
||||
self.backgroundNode.image = UIImage(bundleImageName: "Location/PinBackground")
|
||||
|
||||
self.setPeer(account: annotation.account, theme: annotation.theme, peer: peer)
|
||||
self.setSelected(true, animated: false)
|
||||
} else if let location = annotation.location {
|
||||
let venueType = annotation.location?.venue?.type ?? ""
|
||||
let color = venueType.isEmpty ? annotation.theme.list.itemAccentColor : venueIconColor(type: venueType)
|
||||
self.backgroundNode.image = generateTintedImage(image: UIImage(bundleImageName: "Location/PinBackground"), color: color)
|
||||
self.iconNode.setSignal(venueIcon(postbox: annotation.account.postbox, type: venueType, background: false))
|
||||
self.smallIconNode.setSignal(venueIcon(postbox: annotation.account.postbox, type: venueType, background: false))
|
||||
self.smallNode.image = generateSmallBackgroundImage(color: color)
|
||||
self.dotNode.image = generateFilledCircleImage(diameter: 6.0, color: color)
|
||||
|
||||
self.dotNode.isHidden = false
|
||||
|
||||
if !self.isSelected {
|
||||
self.dotNode.alpha = 0.0
|
||||
self.shadowNode.isHidden = true
|
||||
self.smallNode.isHidden = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -165,6 +187,17 @@ class LocationPinAnnotationView: MKAnnotationView {
|
||||
|
||||
self.animating = true
|
||||
if selected {
|
||||
let avatarSnapshot = self.avatarNode?.view.snapshotContentTree()
|
||||
if let avatarSnapshot = avatarSnapshot, let avatarNode = self.avatarNode {
|
||||
self.smallNode.view.addSubview(avatarSnapshot)
|
||||
avatarSnapshot.layer.transform = avatarNode.transform
|
||||
avatarSnapshot.center = CGPoint(x: self.smallNode.frame.width / 2.0, y: self.smallNode.frame.height / 2.0)
|
||||
|
||||
avatarNode.transform = CATransform3DIdentity
|
||||
self.backgroundNode.addSubnode(avatarNode)
|
||||
avatarNode.position = CGPoint(x: self.backgroundNode.frame.width / 2.0, y: self.backgroundNode.frame.height / 2.0 - 5.0)
|
||||
}
|
||||
|
||||
self.shadowNode.position = CGPoint(x: self.shadowNode.position.x, y: self.shadowNode.position.y + self.shadowNode.frame.height / 2.0)
|
||||
self.shadowNode.anchorPoint = CGPoint(x: 0.5, y: 1.0)
|
||||
self.shadowNode.isHidden = false
|
||||
@ -184,11 +217,27 @@ class LocationPinAnnotationView: MKAnnotationView {
|
||||
|
||||
self.smallNode.isHidden = true
|
||||
self.smallNode.transform = CATransform3DIdentity
|
||||
|
||||
if let avatarNode = self.avatarNode {
|
||||
self.addSubnode(avatarNode)
|
||||
avatarSnapshot?.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
self.dotNode.alpha = 1.0
|
||||
self.dotNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
} else {
|
||||
let avatarSnapshot = self.avatarNode?.view.snapshotContentTree()
|
||||
if let avatarSnapshot = avatarSnapshot, let avatarNode = self.avatarNode {
|
||||
self.backgroundNode.view.addSubview(avatarSnapshot)
|
||||
avatarSnapshot.layer.transform = avatarNode.transform
|
||||
avatarSnapshot.center = CGPoint(x: self.backgroundNode.frame.width / 2.0, y: self.backgroundNode.frame.height / 2.0 - 5.0)
|
||||
|
||||
avatarNode.transform = CATransform3DMakeScale(0.64, 0.64, 1.0)
|
||||
self.smallNode.addSubnode(avatarNode)
|
||||
avatarNode.position = CGPoint(x: self.smallNode.frame.width / 2.0, y: self.smallNode.frame.height / 2.0)
|
||||
}
|
||||
|
||||
self.smallNode.isHidden = false
|
||||
self.smallNode.transform = CATransform3DMakeScale(0.01, 0.01, 1.0)
|
||||
|
||||
@ -209,6 +258,11 @@ class LocationPinAnnotationView: MKAnnotationView {
|
||||
|
||||
self.shadowNode.isHidden = true
|
||||
self.shadowNode.transform = CATransform3DIdentity
|
||||
|
||||
if let avatarNode = self.avatarNode {
|
||||
self.addSubnode(avatarNode)
|
||||
avatarSnapshot?.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
let previousAlpha = self.dotNode.alpha
|
||||
@ -249,6 +303,7 @@ class LocationPinAnnotationView: MKAnnotationView {
|
||||
if let avatarNode = self.avatarNode {
|
||||
avatarNode.position = self.isSelected ? CGPoint(x: UIScreenPixel, y: -41.0) : CGPoint()
|
||||
avatarNode.transform = self.isSelected ? CATransform3DIdentity : CATransform3DMakeScale(0.64, 0.64, 1.0)
|
||||
avatarNode.view.superview?.bringSubviewToFront(avatarNode.view)
|
||||
}
|
||||
|
||||
if !self.appeared {
|
||||
@ -277,9 +332,77 @@ class LocationPinAnnotationView: MKAnnotationView {
|
||||
avatarNode.setPeer(account: account, theme: theme, peer: peer)
|
||||
}
|
||||
|
||||
func setRaised(_ raised: Bool, avatar: Bool, animated: Bool, completion: @escaping () -> Void = {}) {
|
||||
private var raised = false
|
||||
func setRaised(_ raised: Bool, animated: Bool, completion: @escaping () -> Void = {}) {
|
||||
guard raised != self.raised else {
|
||||
return
|
||||
}
|
||||
|
||||
self.raised = raised
|
||||
self.shadowNode.layer.removeAllAnimations()
|
||||
|
||||
if animated {
|
||||
if raised {
|
||||
let previousPosition = self.shadowNode.position
|
||||
self.shadowNode.layer.animatePosition(from: previousPosition, to: CGPoint(x: UIScreenPixel, y: -66.0), duration: 0.2, delay: 0.0, timingFunction: kCAMediaTimingFunctionSpring) { finished in
|
||||
if finished {
|
||||
completion()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
UIView.animate(withDuration: 0.2, delay: 0.0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.0, options: [.allowAnimatedContent], animations: {
|
||||
self.shadowNode.position = CGPoint(x: UIScreenPixel, y: -36.0)
|
||||
}) { finished in
|
||||
if finished {
|
||||
completion()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.shadowNode.position = CGPoint(x: UIScreenPixel, y: raised ? -66.0 : -36.0)
|
||||
completion()
|
||||
}
|
||||
}
|
||||
|
||||
func setCustom(_ custom: Bool, animated: Bool) {
|
||||
if animated {
|
||||
self.animating = true
|
||||
|
||||
if let annotation = self.annotation as? LocationPinAnnotation {
|
||||
self.iconNode.setSignal(venueIcon(postbox: annotation.account.postbox, type: "", background: false))
|
||||
}
|
||||
|
||||
if let avatarNode = self.avatarNode {
|
||||
self.backgroundNode.addSubnode(avatarNode)
|
||||
avatarNode.position = CGPoint(x: self.backgroundNode.frame.width / 2.0, y: self.backgroundNode.frame.height / 2.0 - 5.0)
|
||||
}
|
||||
self.shadowNode.position = CGPoint(x: UIScreenPixel, y: -36.0)
|
||||
self.backgroundNode.position = CGPoint(x: self.shadowNode.frame.width / 2.0, y: self.shadowNode.frame.height / 2.0)
|
||||
self.iconNode.position = CGPoint(x: self.shadowNode.frame.width / 2.0, y: self.shadowNode.frame.height / 2.0 - 5.0)
|
||||
|
||||
Queue.mainQueue().after(0.01) {
|
||||
UIView.transition(with: self.backgroundNode.view, duration: 0.2, options: [.transitionCrossDissolve, .allowAnimatedContent], animations: {
|
||||
let color: UIColor
|
||||
if custom, let annotation = self.annotation as? LocationPinAnnotation {
|
||||
color = annotation.theme.list.itemAccentColor
|
||||
} else {
|
||||
color = .white
|
||||
}
|
||||
self.backgroundNode.image = generateTintedImage(image: UIImage(bundleImageName: "Location/PinBackground"), color: color)
|
||||
self.avatarNode?.isHidden = custom
|
||||
self.iconNode.isHidden = !custom
|
||||
}) { finished in
|
||||
if !custom, let avatarNode = self.avatarNode {
|
||||
self.addSubnode(avatarNode)
|
||||
}
|
||||
self.animating = false
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
}
|
||||
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
|
||||
self.dotNode.isHidden = !custom
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,9 +23,20 @@ public enum LocationMapMode {
|
||||
}
|
||||
}
|
||||
|
||||
class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
private class PickerAnnotationContainerView: UIView {
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
let result = super.hitTest(point, with: event)
|
||||
if result == self {
|
||||
return nil
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
private let locationPromise = Promise<CLLocation?>(nil)
|
||||
|
||||
private let pickerAnnotationContainerView: PickerAnnotationContainerView
|
||||
private weak var userLocationAnnotationView: MKAnnotationView?
|
||||
|
||||
private var mapView: MKMapView? {
|
||||
@ -33,12 +44,15 @@ class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
}
|
||||
|
||||
var ignoreRegionChanges = false
|
||||
var dragging = false
|
||||
var isDragging = false
|
||||
var beganInteractiveDragging: (() -> Void)?
|
||||
var endedInteractiveDragging: ((CLLocationCoordinate2D) -> Void)?
|
||||
var annotationSelected: ((LocationPinAnnotation?) -> Void)?
|
||||
|
||||
override init() {
|
||||
self.pickerAnnotationContainerView = PickerAnnotationContainerView()
|
||||
self.pickerAnnotationContainerView.isHidden = true
|
||||
|
||||
super.init()
|
||||
|
||||
self.setViewBlock({
|
||||
@ -61,6 +75,8 @@ class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
self.mapView?.isRotateEnabled = self.isRotateEnabled
|
||||
self.mapView?.showsUserLocation = true
|
||||
self.mapView?.showsPointsOfInterest = false
|
||||
|
||||
self.view.addSubview(self.pickerAnnotationContainerView)
|
||||
}
|
||||
|
||||
var isRotateEnabled: Bool = true {
|
||||
@ -75,7 +91,7 @@ class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func setMapCenter(coordinate: CLLocationCoordinate2D, span: MKCoordinateSpan = defaultMapSpan, offset: CGPoint = CGPoint(), animated: Bool = false) {
|
||||
func setMapCenter(coordinate: CLLocationCoordinate2D, span: MKCoordinateSpan = defaultMapSpan, offset: CGPoint = CGPoint(), isUserLocation: Bool = false, animated: Bool = false) {
|
||||
let region = MKCoordinateRegion(center: coordinate, span: span)
|
||||
self.ignoreRegionChanges = true
|
||||
if offset == CGPoint() {
|
||||
@ -94,16 +110,23 @@ class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
|
||||
for gestureRecognizer in gestureRecognizers {
|
||||
if gestureRecognizer.state == .began || gestureRecognizer.state == .ended {
|
||||
self.dragging = true
|
||||
self.isDragging = true
|
||||
self.beganInteractiveDragging?()
|
||||
|
||||
if self.hasPickerAnnotation {
|
||||
self.customUserLocationAnnotationView?.isHidden = true
|
||||
self.pickerAnnotationContainerView.isHidden = false
|
||||
self.pickerAnnotationView?.setCustom(true, animated: true)
|
||||
self.resetAnnotationSelection()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
|
||||
if self.dragging, let coordinate = self.mapCenterCoordinate {
|
||||
self.dragging = false
|
||||
if self.isDragging, let coordinate = self.mapCenterCoordinate {
|
||||
self.isDragging = false
|
||||
self.endedInteractiveDragging?(coordinate)
|
||||
}
|
||||
}
|
||||
@ -140,6 +163,9 @@ class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
for view in views {
|
||||
if view.annotation is MKUserLocation {
|
||||
self.userLocationAnnotationView = view
|
||||
if let annotationView = self.customUserLocationAnnotationView {
|
||||
view.addSubview(annotationView)
|
||||
}
|
||||
} else if let view = view as? LocationPinAnnotationView {
|
||||
view.setZPosition(-1.0)
|
||||
}
|
||||
@ -156,16 +182,27 @@ class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
}
|
||||
|
||||
self.annotationSelected?(annotation)
|
||||
|
||||
if let annotationView = self.customUserLocationAnnotationView, annotationView.isSelected {
|
||||
annotationView.setSelected(false, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
|
||||
if let view = view as? LocationPinAnnotationView {
|
||||
view.setZPosition(-1.0)
|
||||
Queue.mainQueue().after(0.2) {
|
||||
view.setZPosition(-1.0)
|
||||
}
|
||||
}
|
||||
|
||||
Queue.mainQueue().after(0.05) {
|
||||
if mapView.selectedAnnotations.isEmpty {
|
||||
self.annotationSelected?(nil)
|
||||
if !self.isDragging {
|
||||
self.annotationSelected?(nil)
|
||||
}
|
||||
if let annotationView = self.customUserLocationAnnotationView, !annotationView.isSelected {
|
||||
annotationView.setSelected(true, animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -190,6 +227,39 @@ class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
var pickerAnnotationView: LocationPinAnnotationView? = nil
|
||||
var hasPickerAnnotation: Bool = false {
|
||||
didSet {
|
||||
if self.hasPickerAnnotation, let annotation = self.userLocationAnnotation {
|
||||
let pickerAnnotationView = LocationPinAnnotationView(annotation: annotation)
|
||||
pickerAnnotationView.center = CGPoint(x: self.pickerAnnotationContainerView.frame.width / 2.0, y: self.pickerAnnotationContainerView.frame.height / 2.0 + 16.0)
|
||||
self.pickerAnnotationContainerView.addSubview(pickerAnnotationView)
|
||||
self.pickerAnnotationView = pickerAnnotationView
|
||||
} else {
|
||||
self.pickerAnnotationView?.removeFromSuperview()
|
||||
self.pickerAnnotationView = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var customUserLocationAnnotationView: LocationPinAnnotationView? = nil
|
||||
var userLocationAnnotation: LocationPinAnnotation? = nil {
|
||||
didSet {
|
||||
if let annotation = self.userLocationAnnotation {
|
||||
let annotationView = LocationPinAnnotationView(annotation: annotation)
|
||||
annotationView.frame = annotationView.frame.offsetBy(dx: 21.0, dy: 22.0)
|
||||
if let parentView = self.userLocationAnnotationView {
|
||||
parentView.addSubview(annotationView)
|
||||
}
|
||||
self.customUserLocationAnnotationView = annotationView
|
||||
|
||||
self.pickerAnnotationView?.annotation = annotation
|
||||
} else {
|
||||
self.customUserLocationAnnotationView?.removeFromSuperview()
|
||||
self.customUserLocationAnnotationView = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var annotations: [LocationPinAnnotation] = [] {
|
||||
didSet {
|
||||
@ -199,7 +269,7 @@ class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
|
||||
var dict: [String: LocationPinAnnotation] = [:]
|
||||
for annotation in self.annotations {
|
||||
if let identifier = annotation.location.venue?.id {
|
||||
if let identifier = annotation.location?.venue?.id {
|
||||
dict[identifier] = annotation
|
||||
}
|
||||
}
|
||||
@ -210,7 +280,7 @@ class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
continue
|
||||
}
|
||||
|
||||
if let identifier = annotation.location.venue?.id, let updatedAnnotation = dict[identifier] {
|
||||
if let identifier = annotation.location?.venue?.id, let updatedAnnotation = dict[identifier] {
|
||||
annotation.coordinate = updatedAnnotation.coordinate
|
||||
dict[identifier] = nil
|
||||
} else {
|
||||
@ -222,4 +292,13 @@ class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
mapView.addAnnotations(Array(dict.values))
|
||||
}
|
||||
}
|
||||
|
||||
override func layout() {
|
||||
super.layout()
|
||||
|
||||
self.pickerAnnotationContainerView.frame = CGRect(x: 0.0, y: floorToScreenPixels((self.frame.size.height - self.frame.size.width) / 2.0), width: self.frame.size.width, height: self.frame.size.width)
|
||||
if let pickerAnnotationView = self.pickerAnnotationView {
|
||||
pickerAnnotationView.center = CGPoint(x: self.pickerAnnotationContainerView.frame.width / 2.0, y: self.pickerAnnotationContainerView.frame.height / 2.0 + 16.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -238,6 +238,8 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
private let listNode: ListView
|
||||
private let headerNode: LocationMapHeaderNode
|
||||
private let activityIndicator: ActivityIndicator
|
||||
private let shadeNode: ASDisplayNode
|
||||
private let innerShadeNode: ASDisplayNode
|
||||
|
||||
private let optionsNode: LocationOptionsNode
|
||||
private(set) var searchContainerNode: LocationSearchContainerNode?
|
||||
@ -274,6 +276,12 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
|
||||
self.activityIndicator = ActivityIndicator(type: .custom(self.presentationData.theme.list.itemSecondaryTextColor, 22.0, 1.0, false))
|
||||
|
||||
self.shadeNode = ASDisplayNode()
|
||||
self.shadeNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||
self.shadeNode.alpha = 0.0
|
||||
self.innerShadeNode = ASDisplayNode()
|
||||
self.innerShadeNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||
|
||||
super.init()
|
||||
|
||||
self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||
@ -282,6 +290,8 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
self.addSubnode(self.headerNode)
|
||||
self.addSubnode(self.optionsNode)
|
||||
self.listNode.addSubnode(self.activityIndicator)
|
||||
self.shadeNode.addSubnode(self.innerShadeNode)
|
||||
self.addSubnode(self.shadeNode)
|
||||
|
||||
let userLocation: Signal<CLLocation?, NoError> = self.headerNode.mapNode.userLocation
|
||||
let filteredUserLocation: Signal<CLLocation?, NoError> = userLocation
|
||||
@ -328,14 +338,34 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData, state, userLocation, venues in
|
||||
if let strongSelf = self {
|
||||
var entries: [LocationPickerEntry] = []
|
||||
|
||||
switch state.selectedLocation {
|
||||
case let .location(coordinate, address):
|
||||
entries.append(.location(presentationData.theme, presentationData.strings.Map_SendThisLocation, address ?? presentationData.strings.Map_Locating, nil, coordinate))
|
||||
let title: String
|
||||
switch strongSelf.mode {
|
||||
case .share:
|
||||
title = presentationData.strings.Map_SendThisLocation
|
||||
case .pick:
|
||||
title = presentationData.strings.Map_SetThisLocation
|
||||
}
|
||||
entries.append(.location(presentationData.theme, title, address ?? presentationData.strings.Map_Locating, nil, coordinate))
|
||||
case .selecting:
|
||||
entries.append(.location(presentationData.theme, presentationData.strings.Map_SendThisLocation, presentationData.strings.Map_Locating, nil, nil))
|
||||
let title: String
|
||||
switch strongSelf.mode {
|
||||
case .share:
|
||||
title = presentationData.strings.Map_SendThisLocation
|
||||
case .pick:
|
||||
title = presentationData.strings.Map_SetThisLocation
|
||||
}
|
||||
entries.append(.location(presentationData.theme, title, presentationData.strings.Map_Locating, nil, nil))
|
||||
case let .venue(venue):
|
||||
entries.append(.location(presentationData.theme, presentationData.strings.Map_SendThisPlace, venue.venue?.title ?? "", venue, venue.coordinate))
|
||||
let title: String
|
||||
switch strongSelf.mode {
|
||||
case .share:
|
||||
title = presentationData.strings.Map_SendThisPlace
|
||||
case .pick:
|
||||
title = presentationData.strings.Map_SetThisPlace
|
||||
}
|
||||
entries.append(.location(presentationData.theme, title, venue.venue?.title ?? "", venue, venue.coordinate))
|
||||
case .none:
|
||||
let title: String
|
||||
switch strongSelf.mode {
|
||||
@ -380,7 +410,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
switch state.selectedLocation {
|
||||
case .none:
|
||||
if let userLocation = userLocation {
|
||||
strongSelf.headerNode.mapNode.setMapCenter(coordinate: userLocation.coordinate, animated: previousUserLocation != nil)
|
||||
strongSelf.headerNode.mapNode.setMapCenter(coordinate: userLocation.coordinate, isUserLocation: true, animated: previousUserLocation != nil)
|
||||
}
|
||||
strongSelf.headerNode.mapNode.resetAnnotationSelection()
|
||||
case .selecting:
|
||||
@ -421,9 +451,13 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
strongSelf.geocodingDisposable.set((reverseGeocodeLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] placemark in
|
||||
if let strongSelf = self {
|
||||
var address = placemark?.fullAddress ?? ""
|
||||
if address.isEmpty {
|
||||
address = presentationData.strings.Map_Unknown
|
||||
}
|
||||
strongSelf.updateState { state in
|
||||
var state = state
|
||||
state.selectedLocation = .location(coordinate, placemark?.fullAddress)
|
||||
state.selectedLocation = .location(coordinate, address)
|
||||
return state
|
||||
}
|
||||
}
|
||||
@ -434,8 +468,13 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
}
|
||||
})
|
||||
|
||||
if case let .share(_, selfPeer, _) = self.mode, let peer = selfPeer {
|
||||
self.headerNode.mapNode.userLocationAnnotation = LocationPinAnnotation(account: context.account, theme: self.presentationData.theme, peer: peer)
|
||||
self.headerNode.mapNode.hasPickerAnnotation = true
|
||||
}
|
||||
|
||||
self.listNode.updateFloatingHeaderOffset = { [weak self] offset, listTransition in
|
||||
guard let strongSelf = self, let (layout, navigationBarHeight) = strongSelf.validLayout else {
|
||||
guard let strongSelf = self, let (layout, navigationBarHeight) = strongSelf.validLayout, strongSelf.listNode.scrollEnabled else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -494,7 +533,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
strongSelf.updateState { state in
|
||||
var state = state
|
||||
state.displayingMapModeOptions = false
|
||||
state.selectedLocation = annotation.flatMap { .venue($0.location) } ?? .none
|
||||
state.selectedLocation = annotation?.location.flatMap { .venue($0) } ?? .none
|
||||
return state
|
||||
}
|
||||
}
|
||||
@ -513,6 +552,8 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
self.listNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||
self.headerNode.updatePresentationData(self.presentationData)
|
||||
self.optionsNode.updatePresentationData(self.presentationData)
|
||||
self.shadeNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||
self.innerShadeNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||
self.searchContainerNode?.updatePresentationData(self.presentationData)
|
||||
}
|
||||
|
||||
@ -604,10 +645,24 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
|
||||
let optionsHeight: CGFloat = 38.0
|
||||
|
||||
let pickingCustomLocation = self.state.selectedLocation.isCustom
|
||||
|
||||
var actionHeight: CGFloat?
|
||||
self.listNode.forEachItemNode { itemNode in
|
||||
if let itemNode = itemNode as? LocationActionListItemNode {
|
||||
if actionHeight == nil {
|
||||
actionHeight = itemNode.frame.height
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let topInset: CGFloat = floor((layout.size.height - navigationHeight) / 2.0 + navigationHeight)
|
||||
let overlap: CGFloat = 6.0
|
||||
let headerHeight: CGFloat
|
||||
if let listOffset = self.listOffset {
|
||||
if pickingCustomLocation, let actionHeight = actionHeight {
|
||||
self.listOffset = topInset
|
||||
headerHeight = layout.size.height - actionHeight - layout.intrinsicInsets.bottom + overlap - 2.0
|
||||
} else if let listOffset = self.listOffset {
|
||||
headerHeight = max(0.0, listOffset + overlap)
|
||||
} else {
|
||||
headerHeight = topInset + overlap
|
||||
@ -615,14 +670,27 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
let headerFrame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: headerHeight))
|
||||
transition.updateFrame(node: self.headerNode, frame: headerFrame)
|
||||
self.headerNode.updateLayout(layout: layout, navigationBarHeight: navigationHeight, padding: self.state.displayingMapModeOptions ? optionsHeight : 0.0, size: headerFrame.size, transition: transition)
|
||||
|
||||
transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||
|
||||
var insets = layout.insets(options: [.input])
|
||||
|
||||
|
||||
let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition)
|
||||
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: UIEdgeInsets(top: topInset, left: 0.0, bottom: layout.intrinsicInsets.bottom, right: 0.0), headerInsets: UIEdgeInsets(top: navigationHeight, left: 0.0, bottom: layout.intrinsicInsets.bottom, right: 0.0), scrollIndicatorInsets: UIEdgeInsets(top: topInset + 3.0, left: 0.0, bottom: layout.intrinsicInsets.bottom, right: 0.0), duration: duration, curve: curve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
self.listNode.scrollEnabled = !self.state.selectedLocation.isCustom
|
||||
let scrollToItem: ListViewScrollToItem?
|
||||
if pickingCustomLocation {
|
||||
scrollToItem = ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: curve, directionHint: .Up)
|
||||
} else {
|
||||
scrollToItem = nil
|
||||
}
|
||||
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: scrollToItem, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: UIEdgeInsets(top: topInset, left: 0.0, bottom: layout.intrinsicInsets.bottom, right: 0.0), headerInsets: UIEdgeInsets(top: navigationHeight, left: 0.0, bottom: layout.intrinsicInsets.bottom, right: 0.0), scrollIndicatorInsets: UIEdgeInsets(top: topInset + 3.0, left: 0.0, bottom: layout.intrinsicInsets.bottom, right: 0.0), duration: duration, curve: curve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
self.listNode.scrollEnabled = !pickingCustomLocation
|
||||
|
||||
var listFrame: CGRect = CGRect(origin: CGPoint(), size: layout.size)
|
||||
if pickingCustomLocation {
|
||||
listFrame.origin.y = headerHeight - topInset - overlap
|
||||
}
|
||||
transition.updateFrame(node: self.listNode, frame: listFrame)
|
||||
transition.updateAlpha(node: self.shadeNode, alpha: pickingCustomLocation ? 1.0 : 0.0)
|
||||
transition.updateFrame(node: self.shadeNode, frame: CGRect(x: 0.0, y: listFrame.minY + topInset + (actionHeight ?? 0.0) - 3.0, width: layout.size.width, height: 10000.0))
|
||||
self.shadeNode.isUserInteractionEnabled = pickingCustomLocation
|
||||
self.innerShadeNode.frame = CGRect(x: 0.0, y: 4.0, width: layout.size.width, height: 10000.0)
|
||||
self.innerShadeNode.alpha = layout.intrinsicInsets.bottom > 0.0 ? 1.0 : 0.0
|
||||
|
||||
self.layoutActivityIndicator(transition: transition)
|
||||
|
||||
@ -645,5 +713,6 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
|
||||
func updateSendActionHighlight(_ highlighted: Bool) {
|
||||
self.headerNode.updateHighlight(highlighted)
|
||||
self.shadeNode.backgroundColor = highlighted ? self.presentationData.theme.list.itemHighlightedBackgroundColor : self.presentationData.theme.list.plainBackgroundColor
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5821,7 +5821,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return
|
||||
}
|
||||
let hasLiveLocation = peer.id.namespace != Namespaces.Peer.SecretChat && peer.id != strongSelf.context.account.peerId && !strongSelf.presentationInterfaceState.isScheduledMessages
|
||||
let controller = LocationPickerController(context: strongSelf.context, mode: .share(peer: peer, selfPeer: peer, hasLiveLocation: hasLiveLocation), completion: { [weak self] location, _ in
|
||||
let controller = LocationPickerController(context: strongSelf.context, mode: .share(peer: peer, selfPeer: selfPeer, hasLiveLocation: hasLiveLocation), completion: { [weak self] location, _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user