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
dcd23387b3
commit
bc4dc9807b
@ -499,4 +499,41 @@ extension DeviceContactAddressData {
|
||||
}
|
||||
return dictionary
|
||||
}
|
||||
|
||||
public var string: String {
|
||||
var array: [String] = []
|
||||
if !self.street1.isEmpty {
|
||||
array.append(self.street1)
|
||||
}
|
||||
if !self.city.isEmpty {
|
||||
array.append(self.city)
|
||||
}
|
||||
if !self.state.isEmpty {
|
||||
array.append(self.state)
|
||||
}
|
||||
if !self.country.isEmpty {
|
||||
array.append(self.country)
|
||||
}
|
||||
if !self.postcode.isEmpty {
|
||||
array.append(self.postcode)
|
||||
}
|
||||
return array.joined(separator: " ")
|
||||
}
|
||||
|
||||
public var displayString: String {
|
||||
var array: [String] = []
|
||||
if !self.street1.isEmpty {
|
||||
array.append(self.street1)
|
||||
}
|
||||
if !self.city.isEmpty {
|
||||
array.append(self.city)
|
||||
}
|
||||
if !self.state.isEmpty {
|
||||
array.append(self.state)
|
||||
}
|
||||
if !self.country.isEmpty {
|
||||
array.append(self.country)
|
||||
}
|
||||
return array.joined(separator: ", ")
|
||||
}
|
||||
}
|
||||
|
@ -174,8 +174,8 @@ public func venueIcon(postbox: Postbox, type: String, background: Bool) -> Signa
|
||||
c.setFillColor(backgroundColor.cgColor)
|
||||
c.fillEllipse(in: CGRect(origin: CGPoint(), size: arguments.drawingRect.size))
|
||||
}
|
||||
let boundsSize = CGSize(width: arguments.drawingRect.size.width - 4.0 * 2.0, height: arguments.drawingRect.size.height - 4.0 * 2.0)
|
||||
if let image = iconImage, let cgImage = generateTintedImage(image: image, color: foregroundColor)?.cgImage {
|
||||
let boundsSize = CGSize(width: arguments.drawingRect.size.width - 4.0 * 2.0, height: arguments.drawingRect.size.height - 4.0 * 2.0)
|
||||
let fittedSize = image.size.aspectFitted(boundsSize)
|
||||
c.draw(cgImage, in: CGRect(origin: CGPoint(x: floor((arguments.drawingRect.width - fittedSize.width) / 2.0), y: floor((arguments.drawingRect.height - fittedSize.height) / 2.0)), size: fittedSize))
|
||||
} else if isBuiltinIcon {
|
||||
@ -191,7 +191,8 @@ public func venueIcon(postbox: Postbox, type: String, background: Bool) -> Signa
|
||||
image = nil
|
||||
}
|
||||
if let image = image, let pinImage = generateTintedImage(image: image, color: foregroundColor), let cgImage = pinImage.cgImage {
|
||||
c.draw(cgImage, in: CGRect(origin: CGPoint(x: floor((arguments.drawingRect.width - pinImage.size.width) / 2.0), y: floor((arguments.drawingRect.height - pinImage.size.height) / 2.0)), size: pinImage.size))
|
||||
let fittedSize = image.size.aspectFitted(boundsSize)
|
||||
c.draw(cgImage, in: CGRect(origin: CGPoint(x: floor((arguments.drawingRect.width - fittedSize.width) / 2.0), y: floor((arguments.drawingRect.height - fittedSize.height) / 2.0)), size: fittedSize))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ static_library(
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
"//submodules/DeviceAccess:DeviceAccess",
|
||||
"//submodules/ChatListSearchItemHeader:ChatListSearchItemHeader",
|
||||
"//submodules/PhoneNumberFormat:PhoneNumberFormat",
|
||||
"//submodules/PersistentStringHash:PersistentStringHash",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
73
submodules/LocationUI/Sources/CachedGeocodes.swift
Normal file
73
submodules/LocationUI/Sources/CachedGeocodes.swift
Normal file
@ -0,0 +1,73 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
import TelegramUIPreferences
|
||||
import PersistentStringHash
|
||||
import AccountContext
|
||||
import Geocoding
|
||||
|
||||
public final class CachedGeocode: PostboxCoding {
|
||||
public let latitude: Double
|
||||
public let longitude: Double
|
||||
|
||||
public init(latitude: Double, longitude: Double) {
|
||||
self.latitude = latitude
|
||||
self.longitude = longitude
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.latitude = decoder.decodeDoubleForKey("lat", orElse: 0.0)
|
||||
self.longitude = decoder.decodeDoubleForKey("lon", orElse: 0.0)
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeDouble(self.latitude, forKey: "lat")
|
||||
encoder.encodeDouble(self.longitude, forKey: "lon")
|
||||
}
|
||||
}
|
||||
|
||||
private func cachedGeocode(postbox: Postbox, address: DeviceContactAddressData) -> Signal<CachedGeocode?, NoError> {
|
||||
return postbox.transaction { transaction -> CachedGeocode? in
|
||||
let key = ValueBoxKey(length: 8)
|
||||
key.setInt64(0, value: Int64(bitPattern: address.string.persistentHashValue))
|
||||
if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedGeocodes, key: key)) as? CachedGeocode {
|
||||
return entry
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 10, highWaterItemCount: 20)
|
||||
|
||||
private func updateCachedGeocode(postbox: Postbox, address: DeviceContactAddressData, latitude: Double, longitude: Double) -> Signal<(Double, Double), NoError> {
|
||||
return postbox.transaction { transaction -> (Double, Double) in
|
||||
let key = ValueBoxKey(length: 8)
|
||||
key.setInt64(0, value: Int64(bitPattern: address.string.persistentHashValue))
|
||||
let id = ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedGeocodes, key: key)
|
||||
transaction.putItemCacheEntry(id: id, entry: CachedGeocode(latitude: latitude, longitude: longitude), collectionSpec: collectionSpec)
|
||||
return (latitude, longitude)
|
||||
}
|
||||
}
|
||||
|
||||
public func geocodeAddress(postbox: Postbox, address: DeviceContactAddressData) -> Signal<(Double, Double)?, NoError> {
|
||||
return cachedGeocode(postbox: postbox, address: address)
|
||||
|> mapToSignal { cached -> Signal<(Double, Double)?, NoError> in
|
||||
if let cached = cached {
|
||||
return .single((cached.latitude, cached.longitude))
|
||||
} else {
|
||||
return geocodeLocation(dictionary: address.dictionary)
|
||||
|> mapToSignal { coordinate in
|
||||
if let (latitude, longitude) = coordinate {
|
||||
return updateCachedGeocode(postbox: postbox, address: address, latitude: latitude, longitude: longitude)
|
||||
|> map(Optional.init)
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -115,7 +115,7 @@ class LocationPinAnnotationView: MKAnnotationView {
|
||||
}
|
||||
|
||||
self.iconNode = TransformImageNode()
|
||||
self.iconNode.bounds = CGRect(origin: CGPoint(), size: CGSize(width: 64.0, height: 64.0))
|
||||
self.iconNode.bounds = CGRect(origin: CGPoint(), size: CGSize(width: 60.0, height: 60.0))
|
||||
|
||||
self.smallIconNode = TransformImageNode()
|
||||
self.smallIconNode.frame = CGRect(origin: CGPoint(x: 15.0, y: 15.0), size: CGSize(width: 26.0, height: 26.0))
|
||||
@ -140,6 +140,14 @@ class LocationPinAnnotationView: MKAnnotationView {
|
||||
self.annotation = annotation
|
||||
}
|
||||
|
||||
var defaultZPosition: CGFloat {
|
||||
if let annotation = self.annotation as? LocationPinAnnotation, let venueType = annotation.location?.venue?.type, ["home", "work"].contains(venueType) {
|
||||
return -0.5
|
||||
} else {
|
||||
return -1.0
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
@ -386,46 +394,70 @@ class LocationPinAnnotationView: MKAnnotationView {
|
||||
}
|
||||
|
||||
func setCustom(_ custom: Bool, animated: Bool) {
|
||||
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)
|
||||
|
||||
let transition = {
|
||||
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
|
||||
}
|
||||
|
||||
let completion = {
|
||||
if !custom, let avatarNode = self.avatarNode {
|
||||
self.addSubnode(avatarNode)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
transition()
|
||||
}) { finished in
|
||||
if !custom, let avatarNode = self.avatarNode {
|
||||
self.addSubnode(avatarNode)
|
||||
}
|
||||
completion()
|
||||
self.animating = false
|
||||
}
|
||||
}
|
||||
|
||||
self.setNeedsLayout()
|
||||
} else {
|
||||
transition()
|
||||
completion()
|
||||
}
|
||||
self.setNeedsLayout()
|
||||
|
||||
self.dotNode.isHidden = !custom
|
||||
}
|
||||
|
||||
func animateAppearance() {
|
||||
self.smallNode.transform = CATransform3DMakeScale(0.1, 0.1, 1.0)
|
||||
|
||||
let avatarNodeTransform = self.avatarNode?.transform
|
||||
self.avatarNode?.transform = CATransform3DMakeScale(0.1, 0.1, 1.0)
|
||||
UIView.animate(withDuration: 0.55, delay: 0.0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.5, options: [], animations: {
|
||||
self.smallNode.transform = CATransform3DIdentity
|
||||
if let avatarNodeTransform = avatarNodeTransform {
|
||||
self.avatarNode?.transform = avatarNodeTransform
|
||||
}
|
||||
}) { _ in
|
||||
}
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
@ -456,10 +488,8 @@ class LocationPinAnnotationView: MKAnnotationView {
|
||||
if !self.appeared {
|
||||
self.appeared = true
|
||||
|
||||
self.smallNode.transform = CATransform3DMakeScale(0.1, 0.1, 1.0)
|
||||
UIView.animate(withDuration: 0.55, delay: 0.0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.5, options: [], animations: {
|
||||
self.smallNode.transform = CATransform3DIdentity
|
||||
}) { _ in
|
||||
if let annotation = annotation as? LocationPinAnnotation, annotation.location != nil {
|
||||
self.animateAppearance()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,17 @@ private class PickerAnnotationContainerView: UIView {
|
||||
}
|
||||
}
|
||||
|
||||
private class LocationMapView: MKMapView, UIGestureRecognizerDelegate {
|
||||
var customHitTest: ((CGPoint) -> Bool)?
|
||||
|
||||
@objc override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
if let customHitTest = self.customHitTest, customHitTest(gestureRecognizer.location(in: self)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
private let locationPromise = Promise<CLLocation?>(nil)
|
||||
|
||||
@ -41,8 +52,8 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
|
||||
private let pinDisposable = MetaDisposable()
|
||||
|
||||
private var mapView: MKMapView? {
|
||||
return self.view as? MKMapView
|
||||
private var mapView: LocationMapView? {
|
||||
return self.view as? LocationMapView
|
||||
}
|
||||
|
||||
var returnedToUserLocation = true
|
||||
@ -50,7 +61,9 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
var isDragging = false
|
||||
var beganInteractiveDragging: (() -> Void)?
|
||||
var endedInteractiveDragging: ((CLLocationCoordinate2D) -> Void)?
|
||||
|
||||
var annotationSelected: ((LocationPinAnnotation?) -> Void)?
|
||||
var userLocationAnnotationSelected: (() -> Void)?
|
||||
|
||||
override init() {
|
||||
self.pickerAnnotationContainerView = PickerAnnotationContainerView()
|
||||
@ -59,7 +72,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
super.init()
|
||||
|
||||
self.setViewBlock({
|
||||
return MKMapView()
|
||||
return LocationMapView()
|
||||
})
|
||||
}
|
||||
|
||||
@ -78,6 +91,18 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
self.mapView?.isRotateEnabled = self.isRotateEnabled
|
||||
self.mapView?.showsUserLocation = true
|
||||
self.mapView?.showsPointsOfInterest = false
|
||||
self.mapView?.customHitTest = { [weak self] point in
|
||||
guard let strongSelf = self, let annotationView = strongSelf.customUserLocationAnnotationView else {
|
||||
return false
|
||||
}
|
||||
|
||||
if let annotationRect = annotationView.superview?.convert(annotationView.frame.insetBy(dx: -16.0, dy: -16.0), to: strongSelf.mapView), annotationRect.contains(point) {
|
||||
strongSelf.userLocationAnnotationSelected?()
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
self.view.addSubview(self.pickerAnnotationContainerView)
|
||||
}
|
||||
@ -105,9 +130,16 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
}
|
||||
self.ignoreRegionChanges = false
|
||||
|
||||
if isUserLocation && !self.returnedToUserLocation {
|
||||
self.returnedToUserLocation = true
|
||||
self.pickerAnnotationView?.setRaised(true, animated: true)
|
||||
if isUserLocation {
|
||||
if !self.returnedToUserLocation {
|
||||
self.returnedToUserLocation = true
|
||||
self.pickerAnnotationView?.setRaised(true, animated: true)
|
||||
}
|
||||
} else if self.hasPickerAnnotation, let customUserLocationAnnotationView = self.customUserLocationAnnotationView, customUserLocationAnnotationView.isHidden {
|
||||
self.pickerAnnotationContainerView.isHidden = true
|
||||
customUserLocationAnnotationView.setSelected(false, animated: false)
|
||||
customUserLocationAnnotationView.isHidden = false
|
||||
customUserLocationAnnotationView.animateAppearance()
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,16 +154,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
self.returnedToUserLocation = false
|
||||
self.beganInteractiveDragging?()
|
||||
|
||||
if self.hasPickerAnnotation {
|
||||
self.customUserLocationAnnotationView?.isHidden = true
|
||||
self.pickerAnnotationContainerView.isHidden = false
|
||||
if let pickerAnnotationView = self.pickerAnnotationView, !pickerAnnotationView.isRaised {
|
||||
pickerAnnotationView.setCustom(true, animated: true)
|
||||
pickerAnnotationView.setRaised(true, animated: true)
|
||||
}
|
||||
self.resetAnnotationSelection()
|
||||
self.resetScheduledPin()
|
||||
}
|
||||
self.switchToPicking(raise: true, animated: true)
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -189,7 +212,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
view.addSubview(annotationView)
|
||||
}
|
||||
} else if let view = view as? LocationPinAnnotationView {
|
||||
view.setZPosition(-1.0)
|
||||
view.setZPosition(view.defaultZPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -213,7 +236,7 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
|
||||
if let view = view as? LocationPinAnnotationView {
|
||||
Queue.mainQueue().after(0.2) {
|
||||
view.setZPosition(-1.0)
|
||||
view.setZPosition(view.defaultZPosition)
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,6 +287,23 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func switchToPicking(raise: Bool = false, animated: Bool) {
|
||||
guard self.hasPickerAnnotation else {
|
||||
return
|
||||
}
|
||||
|
||||
self.customUserLocationAnnotationView?.isHidden = true
|
||||
self.pickerAnnotationContainerView.isHidden = false
|
||||
if let pickerAnnotationView = self.pickerAnnotationView, !pickerAnnotationView.isRaised {
|
||||
pickerAnnotationView.setCustom(true, animated: animated)
|
||||
if raise {
|
||||
pickerAnnotationView.setRaised(true, animated: animated)
|
||||
}
|
||||
}
|
||||
self.resetAnnotationSelection()
|
||||
self.resetScheduledPin()
|
||||
}
|
||||
|
||||
var customUserLocationAnnotationView: LocationPinAnnotationView? = nil
|
||||
var userLocationAnnotation: LocationPinAnnotation? = nil {
|
||||
didSet {
|
||||
|
@ -15,6 +15,7 @@ import AccountContext
|
||||
import AppBundle
|
||||
import CoreLocation
|
||||
import Geocoding
|
||||
import PhoneNumberFormat
|
||||
|
||||
private struct LocationPickerTransaction {
|
||||
let deletions: [ListViewDeleteItem]
|
||||
@ -323,13 +324,106 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let personalAddresses = self.context.account.postbox.peerView(id: self.context.account.peerId)
|
||||
|> mapToSignal { view -> Signal<(DeviceContactAddressData?, DeviceContactAddressData?)?, NoError> in
|
||||
if let user = peerViewMainPeer(view) as? TelegramUser, let phoneNumber = user.phone {
|
||||
return ((context.sharedContext.contactDataManager?.basicData() ?? .single([:])) |> take(1))
|
||||
|> mapToSignal { basicData -> Signal<DeviceContactExtendedData?, NoError> in
|
||||
var stableId: String?
|
||||
let queryPhoneNumber = formatPhoneNumber(phoneNumber)
|
||||
outer: for (id, data) in basicData {
|
||||
for phoneNumber in data.phoneNumbers {
|
||||
if formatPhoneNumber(phoneNumber.value) == queryPhoneNumber {
|
||||
stableId = id
|
||||
break outer
|
||||
}
|
||||
}
|
||||
}
|
||||
if let stableId = stableId {
|
||||
return (context.sharedContext.contactDataManager?.extendedData(stableId: stableId) ?? .single(nil))
|
||||
|> take(1)
|
||||
|> map { extendedData -> DeviceContactExtendedData? in
|
||||
return extendedData
|
||||
}
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
|> map { extendedData -> (DeviceContactAddressData?, DeviceContactAddressData?)? in
|
||||
if let extendedData = extendedData {
|
||||
var homeAddress: DeviceContactAddressData?
|
||||
var workAddress: DeviceContactAddressData?
|
||||
for address in extendedData.addresses {
|
||||
if address.label == "_$!<Home>!$_" {
|
||||
homeAddress = address
|
||||
} else if address.label == "_$!<Work>!$_" {
|
||||
workAddress = address
|
||||
}
|
||||
}
|
||||
return (homeAddress, workAddress)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
|
||||
let personalVenues: Signal<[TelegramMediaMap]?, NoError> = .single(nil)
|
||||
|> then(
|
||||
personalAddresses
|
||||
|> mapToSignal { homeAndWorkAddresses -> Signal<[TelegramMediaMap]?, NoError> in
|
||||
if let (homeAddress, workAddress) = homeAndWorkAddresses {
|
||||
let home: Signal<(Double, Double)?, NoError>
|
||||
let work: Signal<(Double, Double)?, NoError>
|
||||
if let address = homeAddress {
|
||||
home = geocodeAddress(postbox: context.account.postbox, address: address)
|
||||
} else {
|
||||
home = .single(nil)
|
||||
}
|
||||
if let address = workAddress {
|
||||
work = geocodeAddress(postbox: context.account.postbox, address: address)
|
||||
} else {
|
||||
work = .single(nil)
|
||||
}
|
||||
return combineLatest(home, work)
|
||||
|> map { homeCoordinate, workCoordinate -> [TelegramMediaMap]? in
|
||||
var venues: [TelegramMediaMap] = []
|
||||
if let (latitude, longitude) = homeCoordinate, let address = homeAddress {
|
||||
venues.append(TelegramMediaMap(latitude: latitude, longitude: longitude, geoPlace: nil, venue: MapVenue(title: presentationData.strings.Map_Home, address: address.displayString, provider: nil, id: "home", type: "home"), liveBroadcastingTimeout: nil))
|
||||
}
|
||||
if let (latitude, longitude) = workCoordinate, let address = workAddress {
|
||||
venues.append(TelegramMediaMap(latitude: latitude, longitude: longitude, geoPlace: nil, venue: MapVenue(title: presentationData.strings.Map_Work, address: address.displayString, provider: nil, id: "work", type: "work"), liveBroadcastingTimeout: nil))
|
||||
}
|
||||
return venues
|
||||
}
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
let venues: Signal<[TelegramMediaMap]?, NoError> = .single(nil)
|
||||
|> then(
|
||||
filteredUserLocation
|
||||
|> mapToSignal { location -> Signal<[TelegramMediaMap]?, NoError> in
|
||||
if let location = location, location.horizontalAccuracy > 0 {
|
||||
return nearbyVenues(account: context.account, latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
|
||||
|> map(Optional.init)
|
||||
return combineLatest(nearbyVenues(account: context.account, latitude: location.coordinate.latitude, longitude: location.coordinate.longitude), personalVenues)
|
||||
|> map { nearbyVenues, personalVenues -> [TelegramMediaMap]? in
|
||||
var resultVenues: [TelegramMediaMap] = []
|
||||
if let personalVenues = personalVenues {
|
||||
for venue in personalVenues {
|
||||
let venueLocation = CLLocation(latitude: venue.latitude, longitude: venue.longitude)
|
||||
if venueLocation.distance(from: location) < 500 {
|
||||
resultVenues.append(venue)
|
||||
}
|
||||
}
|
||||
}
|
||||
resultVenues.append(contentsOf: nearbyVenues)
|
||||
return resultVenues
|
||||
}
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
@ -436,6 +530,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
}
|
||||
if updateMap {
|
||||
strongSelf.headerNode.mapNode.setMapCenter(coordinate: coordinate, isUserLocation: false, animated: true)
|
||||
strongSelf.headerNode.mapNode.switchToPicking(animated: false)
|
||||
}
|
||||
case let .venue(venue):
|
||||
strongSelf.headerNode.mapNode.setMapCenter(coordinate: venue.coordinate, animated: true)
|
||||
@ -497,7 +592,6 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
guard let strongSelf = self, let (layout, navigationBarHeight) = strongSelf.validLayout, strongSelf.listNode.scrollEnabled else {
|
||||
return
|
||||
}
|
||||
|
||||
let overlap: CGFloat = 6.0
|
||||
strongSelf.listOffset = max(0.0, offset)
|
||||
let headerFrame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: max(0.0, offset + overlap)))
|
||||
@ -510,7 +604,6 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.updateState { state in
|
||||
var state = state
|
||||
state.displayingMapModeOptions = false
|
||||
@ -522,7 +615,6 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.updateState { state in
|
||||
var state = state
|
||||
state.displayingMapModeOptions = false
|
||||
@ -535,7 +627,6 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.updateState { state in
|
||||
var state = state
|
||||
if case .selecting = state.selectedLocation {
|
||||
@ -549,7 +640,6 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.updateState { state in
|
||||
var state = state
|
||||
state.displayingMapModeOptions = false
|
||||
@ -557,6 +647,18 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
self.headerNode.mapNode.userLocationAnnotationSelected = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.updateState { state in
|
||||
var state = state
|
||||
state.displayingMapModeOptions = false
|
||||
state.selectedLocation = .none
|
||||
return state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
@ -9,6 +9,7 @@ import WebSearchUI
|
||||
import InstantPageCache
|
||||
import SettingsUI
|
||||
import WallpaperResources
|
||||
import LocationUI
|
||||
|
||||
private var telegramUIDeclaredEncodables: Void = {
|
||||
declareEncodable(InAppNotificationSettings.self, f: { InAppNotificationSettings(decoder: $0) })
|
||||
@ -52,6 +53,7 @@ private var telegramUIDeclaredEncodables: Void = {
|
||||
declareEncodable(MediaPlaybackStoredState.self, f: { MediaPlaybackStoredState(decoder: $0) })
|
||||
declareEncodable(WebBrowserSettings.self, f: { WebBrowserSettings(decoder: $0) })
|
||||
declareEncodable(IntentsSettings.self, f: { IntentsSettings(decoder: $0) })
|
||||
declareEncodable(CachedGeocode.self, f: { CachedGeocode(decoder: $0) })
|
||||
return
|
||||
}()
|
||||
|
||||
|
@ -60,6 +60,7 @@ private enum ApplicationSpecificItemCacheCollectionIdValues: Int8 {
|
||||
case cachedInstantPages = 1
|
||||
case cachedWallpapers = 2
|
||||
case mediaPlaybackStoredState = 3
|
||||
case cachedGeocodes = 4
|
||||
}
|
||||
|
||||
public struct ApplicationSpecificItemCacheCollectionId {
|
||||
@ -67,6 +68,7 @@ public struct ApplicationSpecificItemCacheCollectionId {
|
||||
public static let cachedInstantPages = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.cachedInstantPages.rawValue)
|
||||
public static let cachedWallpapers = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.cachedWallpapers.rawValue)
|
||||
public static let mediaPlaybackStoredState = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.mediaPlaybackStoredState.rawValue)
|
||||
public static let cachedGeocodes = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.cachedGeocodes.rawValue)
|
||||
}
|
||||
|
||||
private enum ApplicationSpecificOrderedItemListCollectionIdValues: Int32 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user