Merge commit '33d946f8db623b378af48d9d56c8d9d9406bbabf' into experimental-2

This commit is contained in:
Ali 2020-10-29 21:11:34 +04:00
commit a33810566d
22 changed files with 4211 additions and 3938 deletions

View File

@ -4366,9 +4366,7 @@ Sorry for the inconvenience.";
"Channel.DiscussionGroup.UnlinkGroup" = "Unlink Group"; "Channel.DiscussionGroup.UnlinkGroup" = "Unlink Group";
"Channel.DiscussionGroup.UnlinkChannel" = "Unlink Channel"; "Channel.DiscussionGroup.UnlinkChannel" = "Unlink Channel";
"Channel.DiscussionGroup.PublicChannelLink" = "Do you want to make %1$@ the discussion board for %2$@?"; "Channel.DiscussionGroup.PublicChannelLink" = "Do you want to make %1$@ the discussion board for %2$@?";
"Channel.DiscussionGroup.PrivateChannelLink" = "Do you want to make %1$@ the discussion board for %2$@? "Channel.DiscussionGroup.PrivateChannelLink" = "Do you want to make %1$@ the discussion board for %2$@?\n\nAny member of this group will be able to see messages in the channel.";
Any member of this group will be able to see messages in the channel.";
"Channel.DiscussionGroup.MakeHistoryPublic" = "Warning: If you set this private group as the disccussion group for your channel, all channel subscribers will be able to access the group. \"Chat history for new members\" will be switched to Visible."; "Channel.DiscussionGroup.MakeHistoryPublic" = "Warning: If you set this private group as the disccussion group for your channel, all channel subscribers will be able to access the group. \"Chat history for new members\" will be switched to Visible.";
"Channel.DiscussionGroup.MakeHistoryPublicProceed" = "Proceed"; "Channel.DiscussionGroup.MakeHistoryPublicProceed" = "Proceed";
@ -5840,6 +5838,7 @@ Any member of this group will be able to see messages in the channel.";
"Notification.ProximityReached" = "%1$@ is now within %2$@ from %3$@"; "Notification.ProximityReached" = "%1$@ is now within %2$@ from %3$@";
"Notification.ProximityReachedYou" = "%1$@ is now within %2$@ from you"; "Notification.ProximityReachedYou" = "%1$@ is now within %2$@ from you";
"Notification.ProximityYouReached" = "You are now within %1$@ from %2$@";
"Location.ProximityNotification.Title" = "Proximity Alert"; "Location.ProximityNotification.Title" = "Proximity Alert";
"Location.ProximityNotification.Notify" = "Notify me within %@"; "Location.ProximityNotification.Notify" = "Notify me within %@";
@ -5880,6 +5879,11 @@ Any member of this group will be able to see messages in the channel.";
"Location.LiveLocationRequired.Description" = "For the alert to work, please share your live location in this chat."; "Location.LiveLocationRequired.Description" = "For the alert to work, please share your live location in this chat.";
"Location.LiveLocationRequired.ShareLocation" = "Share Location"; "Location.LiveLocationRequired.ShareLocation" = "Share Location";
"Location.ProximityAlertSetTitle" = "Proximity alert set";
"Location.ProximityAlertSetText" = "We will notify you once %1$@ is within %2$@ from you.";
"Location.ProximityAlertSetTextGroup" = "We will notify you once any other group member is within %@ from you.";
"Location.ProximityAlertCancelled" = "Proximity alert cancelled";
"Stats.Message.Views" = "Views"; "Stats.Message.Views" = "Views";
"Stats.Message.PublicShares" = "Public Shares"; "Stats.Message.PublicShares" = "Public Shares";
"Stats.Message.PrivateShares" = "Private Shares"; "Stats.Message.PrivateShares" = "Private Shares";

View File

@ -34,8 +34,11 @@ public final class LiveLocationManagerImpl: LiveLocationManager {
} }
private let deviceLocationDisposable = MetaDisposable() private let deviceLocationDisposable = MetaDisposable()
private let updateCoordinateDisposable = MetaDisposable()
private var messagesDisposable: Disposable? private var messagesDisposable: Disposable?
private var deviceLocationPromise = Promise<(CLLocation, Double?)>()
private var broadcastToMessageIds: [MessageId: Int32] = [:] private var broadcastToMessageIds: [MessageId: Int32] = [:]
private var stopMessageIds = Set<MessageId>() private var stopMessageIds = Set<MessageId>()
@ -106,26 +109,36 @@ public final class LiveLocationManagerImpl: LiveLocationManager {
|> deliverOn(self.queue)).start(next: { [weak self] value in |> deliverOn(self.queue)).start(next: { [weak self] value in
if let strongSelf = self { if let strongSelf = self {
if value { if value {
let queue = strongSelf.queue strongSelf.deviceLocationDisposable.set(strongSelf.locationManager.push(mode: .precise, updated: { [weak self] location, heading in
strongSelf.deviceLocationDisposable.set(strongSelf.locationManager.push(mode: .precise, updated: { location, heading in self?.deviceLocationPromise.set(.single((location, heading)))
queue.async {
var effectiveHeading = heading ?? location.course
if location.speed > 1.0 {
effectiveHeading = location.course
}
self?.updateDeviceCoordinate(location.coordinate, accuracyRadius: location.horizontalAccuracy, heading: effectiveHeading)
}
})) }))
} else { } else {
strongSelf.deviceLocationDisposable.set(nil) strongSelf.deviceLocationDisposable.set(nil)
} }
} }
}) })
let throttledDeviceLocation = self.deviceLocationPromise.get()
|> mapToThrottled { next -> Signal<(CLLocation, Double?), NoError> in
return .single(next) |> then(.complete() |> delay(4.0, queue: Queue.concurrentDefaultQueue()))
}
self.updateCoordinateDisposable.set((throttledDeviceLocation
|> deliverOn(self.queue)).start(next: { [weak self] location, heading in
if let strongSelf = self {
var effectiveHeading = heading ?? location.course
if location.speed > 1.0 {
effectiveHeading = location.course
}
strongSelf.updateDeviceCoordinate(location.coordinate, accuracyRadius: location.horizontalAccuracy, heading: effectiveHeading)
}
}))
} }
deinit { deinit {
self.requiredLocationTypeDisposable?.dispose() self.requiredLocationTypeDisposable?.dispose()
self.deviceLocationDisposable.dispose() self.deviceLocationDisposable.dispose()
self.updateCoordinateDisposable.dispose()
self.messagesDisposable?.dispose() self.messagesDisposable?.dispose()
self.editMessageDisposables.dispose() self.editMessageDisposables.dispose()
self.invalidationTimer?.0.invalidate() self.invalidationTimer?.0.invalidate()

View File

@ -5,6 +5,7 @@ import Display
import TelegramPresentationData import TelegramPresentationData
private let textFont = Font.with(size: 13.0, design: .round, traits: [.bold]) private let textFont = Font.with(size: 13.0, design: .round, traits: [.bold])
private let smallTextFont = Font.with(size: 11.0, design: .round, traits: [.bold])
private class ChatMessageLiveLocationTimerNodeParams: NSObject { private class ChatMessageLiveLocationTimerNodeParams: NSObject {
let backgroundColor: UIColor let backgroundColor: UIColor
@ -119,10 +120,16 @@ public final class ChatMessageLiveLocationTimerNode: ASDisplayNode {
path.lineCapStyle = .round path.lineCapStyle = .round
path.stroke() path.stroke()
let attributes: [NSAttributedString.Key: Any] = [.font: textFont, .foregroundColor: parameters.foregroundColor] let attributes: [NSAttributedString.Key: Any] = [.font: parameters.string.count > 2 ? smallTextFont : textFont, .foregroundColor: parameters.foregroundColor]
let nsString = parameters.string as NSString let nsString = parameters.string as NSString
let size = nsString.size(withAttributes: attributes) let size = nsString.size(withAttributes: attributes)
nsString.draw(at: CGPoint(x: floor((bounds.size.width - size.width) / 2.0), y: floor((bounds.size.height - size.height) / 2.0)), withAttributes: attributes)
var offset: CGFloat = 0.0
if parameters.string.count > 2 {
offset = UIScreenPixel
}
nsString.draw(at: CGPoint(x: floor((bounds.size.width - size.width) / 2.0), y: floor((bounds.size.height - size.height) / 2.0) + offset), withAttributes: attributes)
} }
} }
} }

View File

@ -38,6 +38,7 @@ static_library(
"//submodules/LiveLocationTimerNode:LiveLocationTimerNode", "//submodules/LiveLocationTimerNode:LiveLocationTimerNode",
"//submodules/TelegramNotices:TelegramNotices", "//submodules/TelegramNotices:TelegramNotices",
"//submodules/TooltipUI:TooltipUI", "//submodules/TooltipUI:TooltipUI",
"//submodules/UndoUI:UndoUI",
], ],
frameworks = [ frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework", "$SDKROOT/System/Library/Frameworks/Foundation.framework",

View File

@ -39,6 +39,7 @@ swift_library(
"//submodules/LiveLocationTimerNode:LiveLocationTimerNode", "//submodules/LiveLocationTimerNode:LiveLocationTimerNode",
"//submodules/TelegramNotices:TelegramNotices", "//submodules/TelegramNotices:TelegramNotices",
"//submodules/TooltipUI:TooltipUI", "//submodules/TooltipUI:TooltipUI",
"//submodules/UndoUI:UndoUI",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -239,7 +239,10 @@ final class LocationActionListItemNode: ListViewItemNode {
let titleSpacing: CGFloat = 1.0 let titleSpacing: CGFloat = 1.0
let bottomInset: CGFloat = hasSeparator ? 0.0 : 4.0 let bottomInset: CGFloat = hasSeparator ? 0.0 : 4.0
let contentSize = CGSize(width: params.width, height: verticalInset * 2.0 + titleLayout.size.height + titleSpacing + subtitleLayout.size.height + bottomInset) var contentSize = CGSize(width: params.width, height: verticalInset * 2.0 + titleLayout.size.height + titleSpacing + subtitleLayout.size.height + bottomInset)
if hasSeparator {
contentSize.height = max(52.0, contentSize.height)
}
let nodeLayout = ListViewItemNodeLayout(contentSize: contentSize, insets: UIEdgeInsets()) let nodeLayout = ListViewItemNodeLayout(contentSize: contentSize, insets: UIEdgeInsets())
return (nodeLayout, { [weak self] in return (nodeLayout, { [weak self] in

View File

@ -52,6 +52,7 @@ class LocationPinAnnotation: NSObject, MKAnnotation {
} }
} }
var isSelf = false
var selfPeer: Peer? var selfPeer: Peer?
var title: String? = "" var title: String? = ""
var subtitle: String? = "" var subtitle: String? = ""
@ -78,11 +79,12 @@ class LocationPinAnnotation: NSObject, MKAnnotation {
super.init() super.init()
} }
init(context: AccountContext, theme: PresentationTheme, message: Message, selfPeer: Peer?, heading: Int32?) { init(context: AccountContext, theme: PresentationTheme, message: Message, selfPeer: Peer?, isSelf: Bool, heading: Int32?) {
self.context = context self.context = context
self.theme = theme self.theme = theme
self.location = nil self.location = nil
self.peer = nil self.peer = nil
self.isSelf = isSelf
self.message = message self.message = message
if let location = getLocation(from: message) { if let location = getLocation(from: message) {
self.coordinate = location.coordinate self.coordinate = location.coordinate
@ -311,6 +313,7 @@ class LocationPinAnnotationView: MKAnnotationView {
self.smallNode.image = generateSmallBackgroundImage(color: color) self.smallNode.image = generateSmallBackgroundImage(color: color)
self.dotNode.image = generateFilledCircleImage(diameter: 6.0, color: color) self.dotNode.image = generateFilledCircleImage(diameter: 6.0, color: color)
self.iconNode.isHidden = false
self.dotNode.isHidden = false self.dotNode.isHidden = false
if !self.isSelected { if !self.isSelected {
@ -354,6 +357,7 @@ class LocationPinAnnotationView: MKAnnotationView {
} }
override func prepareForReuse() { override func prepareForReuse() {
self.previousPeerId = nil
self.smallNode.isHidden = true self.smallNode.isHidden = true
self.backgroundNode.isHidden = false self.backgroundNode.isHidden = false
self.appeared = false self.appeared = false

View File

@ -28,16 +28,18 @@ final class LocationDistancePickerScreen: ViewController {
private let context: AccountContext private let context: AccountContext
private let style: LocationDistancePickerScreenStyle private let style: LocationDistancePickerScreenStyle
private let distances: Signal<[Double], NoError> private let distances: Signal<[Double], NoError>
private let compactDisplayTitle: String?
private let updated: (Int32?) -> Void private let updated: (Int32?) -> Void
private let completion: (Int32, @escaping () -> Void) -> Void private let completion: (Int32, @escaping () -> Void) -> Void
private let willDismiss: () -> Void private let willDismiss: () -> Void
private var presentationDataDisposable: Disposable? private var presentationDataDisposable: Disposable?
init(context: AccountContext, style: LocationDistancePickerScreenStyle, distances: Signal<[Double], NoError>, updated: @escaping (Int32?) -> Void, completion: @escaping (Int32, @escaping () -> Void) -> Void, willDismiss: @escaping () -> Void) { init(context: AccountContext, style: LocationDistancePickerScreenStyle, compactDisplayTitle: String?, distances: Signal<[Double], NoError>, updated: @escaping (Int32?) -> Void, completion: @escaping (Int32, @escaping () -> Void) -> Void, willDismiss: @escaping () -> Void) {
self.context = context self.context = context
self.style = style self.style = style
self.distances = distances self.distances = distances
self.compactDisplayTitle = compactDisplayTitle
self.updated = updated self.updated = updated
self.completion = completion self.completion = completion
self.willDismiss = willDismiss self.willDismiss = willDismiss
@ -67,7 +69,7 @@ final class LocationDistancePickerScreen: ViewController {
} }
override public func loadDisplayNode() { override public func loadDisplayNode() {
self.displayNode = LocationDistancePickerScreenNode(context: self.context, style: self.style, distances: self.distances) self.displayNode = LocationDistancePickerScreenNode(context: self.context, style: self.style, compactDisplayTitle: self.compactDisplayTitle, distances: self.distances)
self.controllerNode.updated = { [weak self] distance in self.controllerNode.updated = { [weak self] distance in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -173,6 +175,7 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
private let context: AccountContext private let context: AccountContext
private let controllerStyle: LocationDistancePickerScreenStyle private let controllerStyle: LocationDistancePickerScreenStyle
private var presentationData: PresentationData private var presentationData: PresentationData
private var compactDisplayTitle: String?
private var distances: [Double] = [] private var distances: [Double] = []
private let dimNode: ASDisplayNode private let dimNode: ASDisplayNode
@ -186,10 +189,14 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
private let cancelButton: HighlightableButtonNode private let cancelButton: HighlightableButtonNode
private let doneButton: SolidRoundedButtonNode private let doneButton: SolidRoundedButtonNode
private let measureButtonTitleNode: ImmediateTextNode
private var pickerView: TimerPickerView? private var pickerView: TimerPickerView?
private let unitLabelNode: ImmediateTextNode private let unitLabelNode: ImmediateTextNode
private let smallUnitLabelNode: ImmediateTextNode private let smallUnitLabelNode: ImmediateTextNode
private var pickerTimer: SwiftSignalKit.Timer?
private var containerLayout: (ContainerViewLayout, CGFloat)? private var containerLayout: (ContainerViewLayout, CGFloat)?
private var distancesDisposable: Disposable? private var distancesDisposable: Disposable?
@ -199,10 +206,11 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
var dismiss: (() -> Void)? var dismiss: (() -> Void)?
var cancel: (() -> Void)? var cancel: (() -> Void)?
init(context: AccountContext, style: LocationDistancePickerScreenStyle, distances: Signal<[Double], NoError>) { init(context: AccountContext, style: LocationDistancePickerScreenStyle, compactDisplayTitle: String?, distances: Signal<[Double], NoError>) {
self.context = context self.context = context
self.controllerStyle = style self.controllerStyle = style
self.presentationData = context.sharedContext.currentPresentationData.with { $0 } self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.compactDisplayTitle = compactDisplayTitle
self.wrappingScrollNode = ASScrollNode() self.wrappingScrollNode = ASScrollNode()
self.wrappingScrollNode.view.alwaysBounceVertical = true self.wrappingScrollNode.view.alwaysBounceVertical = true
@ -256,9 +264,10 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
self.doneButton.title = self.presentationData.strings.Conversation_Timer_Send self.doneButton.title = self.presentationData.strings.Conversation_Timer_Send
self.unitLabelNode = ImmediateTextNode() self.unitLabelNode = ImmediateTextNode()
self.smallUnitLabelNode = ImmediateTextNode() self.smallUnitLabelNode = ImmediateTextNode()
self.measureButtonTitleNode = ImmediateTextNode()
super.init() super.init()
self.backgroundColor = nil self.backgroundColor = nil
@ -314,6 +323,8 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
deinit { deinit {
self.distancesDisposable?.dispose() self.distancesDisposable?.dispose()
self.pickerTimer?.invalidate()
} }
func setupPickerView() { func setupPickerView() {
@ -338,6 +349,18 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
self.contentContainerNode.addSubnode(self.unitLabelNode) self.contentContainerNode.addSubnode(self.unitLabelNode)
self.contentContainerNode.addSubnode(self.smallUnitLabelNode) self.contentContainerNode.addSubnode(self.smallUnitLabelNode)
self.pickerTimer?.invalidate()
let pickerTimer = SwiftSignalKit.Timer(timeout: 0.4, repeat: true, completion: { [weak self] in
if let strongSelf = self {
if strongSelf.update() {
strongSelf.updateDoneButtonTitle()
}
}
}, queue: Queue.mainQueue())
self.pickerTimer = pickerTimer
pickerTimer.start()
self.updateDoneButtonTitle() self.updateDoneButtonTitle()
} }
@ -364,19 +387,38 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
let largeValue = unitValues[selectedLargeRow] let largeValue = unitValues[selectedLargeRow]
let smallValue = smallUnitValues[selectedSmallRow] let smallValue = smallUnitValues[selectedSmallRow]
var value = largeValue * 1000 + smallValue * 10 let value = largeValue * 1000 + smallValue * 10
if !self.usesMetricSystem { var formattedValue = String(format: "%0.1f", CGFloat(value) / 1000.0)
value = Int32(Double(value) * 1.60934) if smallValue == 5 {
formattedValue = formattedValue.replacingOccurrences(of: ".1", with: ".05").replacingOccurrences(of: ",1", with: ",05")
} }
let distance = stringForDistance(strings: self.presentationData.strings, distance: CLLocationDistance(value)) let distance = self.usesMetricSystem ? "\(formattedValue) \(self.presentationData.strings.Location_ProximityNotification_DistanceKM)" : "\(formattedValue) \(self.presentationData.strings.Location_ProximityNotification_DistanceMI)"
self.doneButton.title = self.presentationData.strings.Location_ProximityNotification_Notify(distance).0
let shortTitle = self.presentationData.strings.Location_ProximityNotification_Notify(distance).0
var longTitle: String?
if let displayTitle = self.compactDisplayTitle, let (layout, _) = self.containerLayout {
let title = self.presentationData.strings.Location_ProximityNotification_NotifyLong(displayTitle, distance).0
let width = horizontalContainerFillingSizeForLayout(layout: layout, sideInset: layout.safeInsets.left)
self.measureButtonTitleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(17.0), textColor: .black)
let titleSize = self.measureButtonTitleNode.updateLayout(CGSize(width: width * 2.0, height: 50.0))
if titleSize.width < width - 70.0 {
longTitle = title
}
}
self.doneButton.title = longTitle ?? shortTitle
self.textNode.attributedText = NSAttributedString(string: self.presentationData.strings.Location_ProximityNotification_AlreadyClose(distance).0, font: Font.regular(14.0), textColor: self.presentationData.theme.actionSheet.secondaryTextColor) self.textNode.attributedText = NSAttributedString(string: self.presentationData.strings.Location_ProximityNotification_AlreadyClose(distance).0, font: Font.regular(14.0), textColor: self.presentationData.theme.actionSheet.secondaryTextColor)
if let (layout, navigationBarHeight) = self.containerLayout { if let (layout, navigationBarHeight) = self.containerLayout {
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate) self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
} }
if let distance = self.distances.last, Double(value) > distance { var convertedValue = Double(value)
if !self.usesMetricSystem {
convertedValue = Double(convertedValue) * 1.60934
}
if let distance = self.distances.last, convertedValue > distance {
self.doneButton.alpha = 0.0 self.doneButton.alpha = 0.0
self.doneButton.isUserInteractionEnabled = false self.doneButton.isUserInteractionEnabled = false
self.textNode.alpha = 1.0 self.textNode.alpha = 1.0
@ -388,27 +430,42 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
} }
} }
fileprivate func update() { var previousReportedValue: Int32?
fileprivate func update() -> Bool {
if let pickerView = self.pickerView { if let pickerView = self.pickerView {
let largeValue = unitValues[pickerView.selectedRow(inComponent: 0)] let selectedLargeRow = pickerView.selectedRow(inComponent: 0)
let smallValue = smallUnitValues[pickerView.selectedRow(inComponent: 1)] var selectedSmallRow = pickerView.selectedRow(inComponent: 1)
if selectedLargeRow == 0 && selectedSmallRow == 0 {
selectedSmallRow = 1
}
let largeValue = unitValues[selectedLargeRow]
let smallValue = smallUnitValues[selectedSmallRow]
var value = largeValue * 1000 + smallValue * 10 var value = largeValue * 1000 + smallValue * 10
if !self.usesMetricSystem { if !self.usesMetricSystem {
value = Int32(Double(value) * 1.60934) value = Int32(Double(value) * 1.60934)
} }
if let previousReportedValue = self.previousReportedValue, value == previousReportedValue {
return false
} else {
self.updated?(value) self.updated?(value)
self.previousReportedValue = value
return true
}
} else {
return false
} }
} }
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView.selectedRow(inComponent: 0) == 0 && pickerView.selectedRow(inComponent: 1) == 0 { if pickerView.selectedRow(inComponent: 0) == 0 && pickerView.selectedRow(inComponent: 1) == 0 {
pickerView.selectRow(1, inComponent: 1, animated: true) pickerView.selectRow(1, inComponent: 1, animated: true)
} else { }
self.updateDoneButtonTitle() self.updateDoneButtonTitle()
self.update() self.update()
} }
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if component == 0 { if component == 0 {
@ -540,6 +597,7 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
} }
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
var hadValidLayout = self.containerLayout != nil
self.containerLayout = (layout, navigationBarHeight) self.containerLayout = (layout, navigationBarHeight)
var insets = layout.insets(options: [.statusBar, .input]) var insets = layout.insets(options: [.statusBar, .input])
@ -595,5 +653,9 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
transition.updateFrame(node: self.smallUnitLabelNode, frame: CGRect(origin: CGPoint(x: floor(pickerFrame.width / 4.0 * 3.0) + 50.0, y: floor(pickerFrame.center.y - smallUnitLabelSize.height / 2.0)), size: smallUnitLabelSize)) transition.updateFrame(node: self.smallUnitLabelNode, frame: CGRect(origin: CGPoint(x: floor(pickerFrame.width / 4.0 * 3.0) + 50.0, y: floor(pickerFrame.center.y - smallUnitLabelSize.height / 2.0)), size: smallUnitLabelSize))
transition.updateFrame(node: self.contentContainerNode, frame: contentContainerFrame) transition.updateFrame(node: self.contentContainerNode, frame: contentContainerFrame)
if !hadValidLayout {
self.updateDoneButtonTitle()
}
} }
} }

View File

@ -178,7 +178,7 @@ final class LocationLiveListItemNode: ListViewItemNode {
var subtitle = timeString var subtitle = timeString
if let distance = item.distance { if let distance = item.distance {
let distanceString = item.presentationData.strings.Map_DistanceAway(stringForDistance(strings: item.presentationData.strings, distance: distance)).0 let distanceString = item.presentationData.strings.Map_DistanceAway(shortStringForDistance(strings: item.presentationData.strings, distance: Int32(distance))).0
subtitle = "\(timeString)\(distanceString)" subtitle = "\(timeString)\(distanceString)"
} }

View File

@ -180,7 +180,7 @@ final class LocationMapHeaderNode: ASDisplayNode {
func updateLayout(layout: ContainerViewLayout, navigationBarHeight: CGFloat, topPadding: CGFloat, offset: CGFloat, size: CGSize, transition: ContainedViewLayoutTransition) { func updateLayout(layout: ContainerViewLayout, navigationBarHeight: CGFloat, topPadding: CGFloat, offset: CGFloat, size: CGSize, transition: ContainedViewLayoutTransition) {
self.validLayout = (layout, navigationBarHeight, topPadding, offset, size) self.validLayout = (layout, navigationBarHeight, topPadding, offset, size)
let mapHeight: CGFloat = floor(layout.size.height * 1.5) 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) 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) transition.updateFrame(node: self.mapNode, frame: mapFrame)
self.mapNode.updateLayout(size: mapFrame.size) self.mapNode.updateLayout(size: mapFrame.size)

View File

@ -158,6 +158,8 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
private weak var userLocationAnnotationView: MKAnnotationView? private weak var userLocationAnnotationView: MKAnnotationView?
private var headingArrowView: UIImageView? private var headingArrowView: UIImageView?
private weak var defaultUserLocationAnnotation: MKAnnotation?
private let pinDisposable = MetaDisposable() private let pinDisposable = MetaDisposable()
private var mapView: LocationMapView? { private var mapView: LocationMapView? {
@ -253,11 +255,16 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
self.mapView?.showsUserLocation = true self.mapView?.showsUserLocation = true
self.mapView?.showsPointsOfInterest = false self.mapView?.showsPointsOfInterest = false
self.mapView?.customHitTest = { [weak self] point in self.mapView?.customHitTest = { [weak self] point in
guard let strongSelf = self, let annotationView = strongSelf.customUserLocationAnnotationView else { guard let strongSelf = self else {
return false return false
} }
if let annotationRect = annotationView.superview?.convert(annotationView.frame.insetBy(dx: -16.0, dy: -16.0), to: strongSelf.mapView), annotationRect.contains(point) { if let annotationView = strongSelf.customUserLocationAnnotationView, let annotationRect = annotationView.superview?.convert(annotationView.frame.insetBy(dx: -16.0, dy: -16.0), to: strongSelf.mapView), annotationRect.contains(point) {
strongSelf.userLocationAnnotationSelected?()
return true
}
if let userAnnotation = strongSelf.defaultUserLocationAnnotation, let annotationView = strongSelf.mapView?.view(for: userAnnotation), let annotationRect = annotationView.superview?.convert(annotationView.frame.insetBy(dx: -16.0, dy: -16.0), to: strongSelf.mapView), annotationRect.contains(point) {
strongSelf.userLocationAnnotationSelected?() strongSelf.userLocationAnnotationSelected?()
return true return true
} }
@ -390,6 +397,9 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) { func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
for view in views { for view in views {
if view.annotation is MKUserLocation { if view.annotation is MKUserLocation {
self.defaultUserLocationAnnotation = view.annotation
view.canShowCallout = false
self.userLocationAnnotationView = view self.userLocationAnnotationView = view
if let headingArrowView = self.headingArrowView { if let headingArrowView = self.headingArrowView {
view.addSubview(headingArrowView) view.addSubview(headingArrowView)
@ -471,6 +481,9 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
var distances: [Double] = [] var distances: [Double] = []
if let userLocation = userLocation { if let userLocation = userLocation {
for annotation in annotations { for annotation in annotations {
if annotation.isSelf {
continue
}
distances.append(userLocation.distance(from: CLLocation(latitude: annotation.coordinate.latitude, longitude: annotation.coordinate.longitude))) distances.append(userLocation.distance(from: CLLocation(latitude: annotation.coordinate.latitude, longitude: annotation.coordinate.longitude)))
} }
} }
@ -483,7 +496,8 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
} }
var userLocation: Signal<CLLocation?, NoError> { var userLocation: Signal<CLLocation?, NoError> {
return self.locationPromise.get() return .single(self.currentUserLocation)
|> then (self.locationPromise.get())
} }
var mapCenterCoordinate: CLLocationCoordinate2D? { var mapCenterCoordinate: CLLocationCoordinate2D? {
@ -693,15 +707,15 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
guard let mapView = self.mapView else { guard let mapView = self.mapView else {
return return
} }
var annotations: [MKAnnotation] = [] var coordinates: [CLLocationCoordinate2D] = []
if let userAnnotation = self.userLocationAnnotation { if let location = self.currentUserLocation {
annotations.append(userAnnotation) coordinates.append(location.coordinate)
} }
annotations.append(contentsOf: self.annotations) coordinates.append(contentsOf: self.annotations.map { $0.coordinate })
var zoomRect: MKMapRect? var zoomRect: MKMapRect?
for annotation in annotations { for coordinate in coordinates {
let pointRegionRect = MKMapRect(region: MKCoordinateRegion(center: annotation.coordinate, latitudinalMeters: 100, longitudinalMeters: 100)) let pointRegionRect = MKMapRect(region: MKCoordinateRegion(center: coordinate, latitudinalMeters: 100, longitudinalMeters: 100))
if let currentZoomRect = zoomRect { if let currentZoomRect = zoomRect {
zoomRect = currentZoomRect.union(pointRegionRect) zoomRect = currentZoomRect.union(pointRegionRect)
} else { } else {

View File

@ -7,6 +7,7 @@ import SyncCore
import Postbox import Postbox
import SwiftSignalKit import SwiftSignalKit
import TelegramPresentationData import TelegramPresentationData
import TelegramStringFormatting
import AccountContext import AccountContext
import AppBundle import AppBundle
import CoreLocation import CoreLocation
@ -14,6 +15,7 @@ import PresentationDataUtils
import OpenInExternalAppUI import OpenInExternalAppUI
import ShareController import ShareController
import DeviceAccess import DeviceAccess
import UndoUI
public class LocationViewParams { public class LocationViewParams {
let sendLiveLocation: (TelegramMediaMap) -> Void let sendLiveLocation: (TelegramMediaMap) -> Void
@ -194,12 +196,31 @@ public final class LocationViewController: ViewController {
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
Queue.mainQueue().after(0.5) {
strongSelf.controllerNode.updateState { state in strongSelf.controllerNode.updateState { state in
var state = state var state = state
state.cancellingProximityRadius = false state.cancellingProximityRadius = false
return state return state
} }
}
}) })
strongSelf.dismissAllTooltips()
strongSelf.present(
UndoOverlayController(
presentationData: strongSelf.presentationData,
content: .setProximityAlert(
title: strongSelf.presentationData.strings.Location_ProximityAlertCancelled,
text: "",
cancelled: true
),
elevatedLayout: false,
action: { action in
return true
}
),
in: .current
)
} }
} else { } else {
DeviceAccess.authorizeAccess(to: .location(.live), locationManager: strongSelf.locationManager, presentationData: strongSelf.presentationData, present: { c, a in DeviceAccess.authorizeAccess(to: .location(.live), locationManager: strongSelf.locationManager, presentationData: strongSelf.presentationData, present: { c, a in
@ -212,7 +233,18 @@ public final class LocationViewController: ViewController {
} }
strongSelf.controllerNode.setProximityIndicator(radius: 0) strongSelf.controllerNode.setProximityIndicator(radius: 0)
let controller = LocationDistancePickerScreen(context: context, style: .default, distances: strongSelf.controllerNode.headerNode.mapNode.distancesToAllAnnotations, updated: { [weak self] distance in let _ = (strongSelf.context.account.postbox.loadedPeerWithId(strongSelf.subject.id.peerId)
|> deliverOnMainQueue).start(next: { [weak self] peer in
guard let strongSelf = self else {
return
}
var compactDisplayTitle: String?
if let peer = peer as? TelegramUser {
compactDisplayTitle = peer.compactDisplayTitle
}
let controller = LocationDistancePickerScreen(context: context, style: .default, compactDisplayTitle: compactDisplayTitle, distances: strongSelf.controllerNode.headerNode.mapNode.distancesToAllAnnotations, updated: { [weak self] distance in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
@ -233,12 +265,39 @@ public final class LocationViewController: ViewController {
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
Queue.mainQueue().after(0.5) {
strongSelf.controllerNode.updateState { state in strongSelf.controllerNode.updateState { state in
var state = state var state = state
state.updatingProximityRadius = nil state.updatingProximityRadius = nil
return state return state
} }
}
}) })
var text: String
let distanceString = shortStringForDistance(strings: strongSelf.presentationData.strings, distance: distance)
if let compactDisplayTitle = compactDisplayTitle {
text = strongSelf.presentationData.strings.Location_ProximityAlertSetText(compactDisplayTitle, distanceString).0
} else {
text = strongSelf.presentationData.strings.Location_ProximityAlertSetTextGroup(distanceString).0
}
strongSelf.dismissAllTooltips()
strongSelf.present(
UndoOverlayController(
presentationData: strongSelf.presentationData,
content: .setProximityAlert(
title: strongSelf.presentationData.strings.Location_ProximityAlertSetTitle,
text: text,
cancelled: false
),
elevatedLayout: false,
action: { action in
return true
}
),
in: .current
)
} else { } else {
strongSelf.present(textAlertController(context: strongSelf.context, title: strongSelf.presentationData.strings.Location_LiveLocationRequired_Title, text: strongSelf.presentationData.strings.Location_LiveLocationRequired_Description, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Location_LiveLocationRequired_ShareLocation, action: { strongSelf.present(textAlertController(context: strongSelf.context, title: strongSelf.presentationData.strings.Location_LiveLocationRequired_Title, text: strongSelf.presentationData.strings.Location_LiveLocationRequired_Description, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Location_LiveLocationRequired_ShareLocation, action: {
completion() completion()
@ -252,6 +311,7 @@ public final class LocationViewController: ViewController {
} }
}) })
strongSelf.present(controller, in: .window(.root)) strongSelf.present(controller, in: .window(.root))
})
} }
} }
}, updateSendActionHighlight: { [weak self] highlighted in }, updateSendActionHighlight: { [weak self] highlighted in
@ -277,6 +337,43 @@ public final class LocationViewController: ViewController {
|> deliverOnMainQueue).start(next: { coordinate in |> deliverOnMainQueue).start(next: { coordinate in
params.sendLiveLocation(TelegramMediaMap(coordinate: coordinate, liveBroadcastingTimeout: 30 * 60, proximityNotificationRadius: distance)) params.sendLiveLocation(TelegramMediaMap(coordinate: coordinate, liveBroadcastingTimeout: 30 * 60, proximityNotificationRadius: distance))
}) })
let _ = (strongSelf.context.account.postbox.loadedPeerWithId(strongSelf.subject.id.peerId)
|> deliverOnMainQueue).start(next: { [weak self] peer in
guard let strongSelf = self else {
return
}
var compactDisplayTitle: String?
if let peer = peer as? TelegramUser {
compactDisplayTitle = peer.compactDisplayTitle
}
var text: String
let distanceString = shortStringForDistance(strings: strongSelf.presentationData.strings, distance: distance)
if let compactDisplayTitle = compactDisplayTitle {
text = strongSelf.presentationData.strings.Location_ProximityAlertSetText(compactDisplayTitle, distanceString).0
} else {
text = strongSelf.presentationData.strings.Location_ProximityAlertSetTextGroup(distanceString).0
}
strongSelf.dismissAllTooltips()
strongSelf.present(
UndoOverlayController(
presentationData: strongSelf.presentationData,
content: .setProximityAlert(
title: strongSelf.presentationData.strings.Location_ProximityAlertSetTitle,
text: text,
cancelled: false
),
elevatedLayout: false,
action: { action in
return true
}
),
in: .current
)
})
} else { } else {
let _ = (context.account.postbox.loadedPeerWithId(subject.id.peerId) let _ = (context.account.postbox.loadedPeerWithId(subject.id.peerId)
|> deliverOnMainQueue).start(next: { peer in |> deliverOnMainQueue).start(next: { peer in
@ -293,6 +390,8 @@ public final class LocationViewController: ViewController {
|> deliverOnMainQueue).start(next: { coordinate in |> deliverOnMainQueue).start(next: { coordinate in
params.sendLiveLocation(TelegramMediaMap(coordinate: coordinate, liveBroadcastingTimeout: period)) params.sendLiveLocation(TelegramMediaMap(coordinate: coordinate, liveBroadcastingTimeout: period))
}) })
strongSelf.controllerNode.showAll()
} }
controller.setItemGroups([ controller.setItemGroups([
@ -355,6 +454,15 @@ public final class LocationViewController: ViewController {
} }
private func dismissAllTooltips() {
self.forEachController({ controller in
if let controller = controller as? UndoOverlayController {
controller.dismissWithCommitAction()
}
return true
})
}
override public func loadDisplayNode() { override public func loadDisplayNode() {
super.loadDisplayNode() super.loadDisplayNode()
guard let interaction = self.interaction else { guard let interaction = self.interaction else {

View File

@ -48,7 +48,7 @@ private enum LocationViewEntryId: Hashable {
private enum LocationViewEntry: Comparable, Identifiable { private enum LocationViewEntry: Comparable, Identifiable {
case info(PresentationTheme, TelegramMediaMap, String?, Double?, Double?) case info(PresentationTheme, TelegramMediaMap, String?, Double?, Double?)
case toggleLiveLocation(PresentationTheme, String, String, CLLocationCoordinate2D?, Double?, Double?) case toggleLiveLocation(PresentationTheme, String, String, Double?, Double?)
case liveLocation(PresentationTheme, PresentationDateTimeFormat, PresentationPersonNameOrder, Message, Double?, Int) case liveLocation(PresentationTheme, PresentationDateTimeFormat, PresentationPersonNameOrder, Message, Double?, Int)
var stableId: LocationViewEntryId { var stableId: LocationViewEntryId {
@ -70,8 +70,8 @@ private enum LocationViewEntry: Comparable, Identifiable {
} else { } else {
return false return false
} }
case let .toggleLiveLocation(lhsTheme, lhsTitle, lhsSubtitle, lhsCoordinate, lhsBeginTimestamp, lhsTimeout): case let .toggleLiveLocation(lhsTheme, lhsTitle, lhsSubtitle, lhsBeginTimestamp, lhsTimeout):
if case let .toggleLiveLocation(rhsTheme, rhsTitle, rhsSubtitle, rhsCoordinate, rhsBeginTimestamp, rhsTimeout) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsSubtitle == rhsSubtitle, lhsCoordinate == rhsCoordinate, lhsBeginTimestamp == rhsBeginTimestamp, lhsTimeout == rhsTimeout { if case let .toggleLiveLocation(rhsTheme, rhsTitle, rhsSubtitle, rhsBeginTimestamp, rhsTimeout) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsSubtitle == rhsSubtitle, lhsBeginTimestamp == rhsBeginTimestamp, lhsTimeout == rhsTimeout {
return true return true
} else { } else {
return false return false
@ -132,7 +132,7 @@ private enum LocationViewEntry: Comparable, Identifiable {
}, getDirections: { }, getDirections: {
interaction?.requestDirections() interaction?.requestDirections()
}) })
case let .toggleLiveLocation(_, title, subtitle, coordinate, beginTimstamp, timeout): case let .toggleLiveLocation(_, title, subtitle, beginTimstamp, timeout):
let beginTimeAndTimeout: (Double, Double)? let beginTimeAndTimeout: (Double, Double)?
if let beginTimstamp = beginTimstamp, let timeout = timeout { if let beginTimstamp = beginTimstamp, let timeout = timeout {
beginTimeAndTimeout = (beginTimstamp, timeout) beginTimeAndTimeout = (beginTimstamp, timeout)
@ -149,7 +149,11 @@ private enum LocationViewEntry: Comparable, Identifiable {
interaction?.updateSendActionHighlight(highlight) interaction?.updateSendActionHighlight(highlight)
}) })
case let .liveLocation(_, dateTimeFormat, nameDisplayOrder, message, distance, _): case let .liveLocation(_, dateTimeFormat, nameDisplayOrder, message, distance, _):
return LocationLiveListItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: context, message: message, distance: distance, action: {}, longTapAction: {}) return LocationLiveListItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: context, message: message, distance: distance, action: {
if let location = getLocation(from: message) {
interaction?.goToCoordinate(location.coordinate)
}
}, longTapAction: {})
} }
} }
} }
@ -277,10 +281,10 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
return messages return messages
} }
setupProximityNotificationImpl = { [weak self] reset in setupProximityNotificationImpl = { reset in
let _ = (liveLocations let _ = (liveLocations
|> take(1) |> take(1)
|> deliverOnMainQueue).start(next: { [weak self] messages in |> deliverOnMainQueue).start(next: { messages in
var ownMessageId: MessageId? var ownMessageId: MessageId?
for message in messages { for message in messages {
if message.localTags.contains(.OutgoingLiveLocation) { if message.localTags.contains(.OutgoingLiveLocation) {
@ -369,7 +373,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
if let channel = subject.author as? TelegramChannel, case .broadcast = channel.info, activeOwnLiveLocation == nil { if let channel = subject.author as? TelegramChannel, case .broadcast = channel.info, activeOwnLiveLocation == nil {
} else { } else {
entries.append(.toggleLiveLocation(presentationData.theme, title, subtitle, userLocation?.coordinate, beginTime, timeout)) entries.append(.toggleLiveLocation(presentationData.theme, title, subtitle, beginTime, timeout))
} }
var sortedLiveLocations: [Message] = [] var sortedLiveLocations: [Message] = []
@ -409,9 +413,9 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
let distance = userLocation.flatMap { subjectLocation.distance(from: $0) } let distance = userLocation.flatMap { subjectLocation.distance(from: $0) }
if message.localTags.contains(.OutgoingLiveLocation), let selfPeer = selfPeer { if message.localTags.contains(.OutgoingLiveLocation), let selfPeer = selfPeer {
userAnnotation = LocationPinAnnotation(context: context, theme: presentationData.theme, message: message, selfPeer: selfPeer, heading: location.heading) userAnnotation = LocationPinAnnotation(context: context, theme: presentationData.theme, message: message, selfPeer: selfPeer, isSelf: true, heading: location.heading)
} else { } else {
annotations.append(LocationPinAnnotation(context: context, theme: presentationData.theme, message: message, selfPeer: selfPeer, heading: location.heading)) annotations.append(LocationPinAnnotation(context: context, theme: presentationData.theme, message: message, selfPeer: selfPeer, isSelf: message.author?.id == context.account.peerId, heading: location.heading))
entries.append(.liveLocation(presentationData.theme, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, message, distance, index)) entries.append(.liveLocation(presentationData.theme, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, message, distance, index))
} }
index += 1 index += 1
@ -420,6 +424,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
if let currentProximityNotification = proximityNotification, currentProximityNotification && state.cancellingProximityRadius { if let currentProximityNotification = proximityNotification, currentProximityNotification && state.cancellingProximityRadius {
proximityNotification = false proximityNotification = false
proximityNotificationRadius = nil
} else if let radius = state.updatingProximityRadius { } else if let radius = state.updatingProximityRadius {
proximityNotification = true proximityNotification = true
proximityNotificationRadius = radius proximityNotificationRadius = radius
@ -481,9 +486,11 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
if !strongSelf.reportedAnnotationsReady { if !strongSelf.reportedAnnotationsReady {
strongSelf.reportedAnnotationsReady = true strongSelf.reportedAnnotationsReady = true
if annotations.count > 0 {
strongSelf.onAnnotationsReady?() strongSelf.onAnnotationsReady?()
} }
} }
}
if let _ = proximityNotification { if let _ = proximityNotification {
strongSelf.headerNode.mapNode.activeProximityRadius = proximityNotificationRadius.flatMap { Double($0) } strongSelf.headerNode.mapNode.activeProximityRadius = proximityNotificationRadius.flatMap { Double($0) }
@ -492,7 +499,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
} }
let rightBarButtonAction: LocationViewRightBarButton let rightBarButtonAction: LocationViewRightBarButton
if location.liveBroadcastingTimeout != nil { if location.liveBroadcastingTimeout != nil {
if liveLocations.count > 1 { if annotations.count > 0 {
rightBarButtonAction = .showAll rightBarButtonAction = .showAll
} else { } else {
rightBarButtonAction = .none rightBarButtonAction = .none
@ -551,6 +558,21 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
} }
} }
self.headerNode.mapNode.annotationSelected = { [weak self] annotation in
guard let strongSelf = self else {
return
}
if let annotation = annotation {
strongSelf.interaction.goToCoordinate(annotation.coordinate)
}
}
self.headerNode.mapNode.userLocationAnnotationSelected = { [weak self] in
if let strongSelf = self, let location = strongSelf.headerNode.mapNode.currentUserLocation {
strongSelf.interaction.goToCoordinate(location.coordinate)
}
}
self.locationManager.manager.startUpdatingHeading() self.locationManager.manager.startUpdatingHeading()
self.locationManager.manager.delegate = self self.locationManager.manager.delegate = self
} }

View File

@ -38,7 +38,8 @@ private func presentLiveLocationController(context: AccountContext, peerId: Peer
}, openUrl: { _ in }, openUrl: { _ in
}, openPeer: { peer, navigation in }, openPeer: { peer, navigation in
}, callPeer: { _, _ in }, callPeer: { _, _ in
}, enqueueMessage: { _ in }, enqueueMessage: { message in
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: [message]).start()
}, sendSticker: nil, }, sendSticker: nil,
setupTemporaryHiddenMedia: { _, _, _ in setupTemporaryHiddenMedia: { _, _, _ in
}, chatAvatarHiddenMedia: { _, _ in }, chatAvatarHiddenMedia: { _, _ in

View File

@ -444,7 +444,9 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
attributedString = nil attributedString = nil
case let .geoProximityReached(fromId, toId, distance): case let .geoProximityReached(fromId, toId, distance):
let distanceString = stringForDistance(strings: strings, distance: Double(distance)) let distanceString = stringForDistance(strings: strings, distance: Double(distance))
if toId == accountPeerId { if fromId == accountPeerId {
attributedString = addAttributesToStringWithRanges(strings.Notification_ProximityYouReached(distanceString, message.peers[toId]?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? ""), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(1, toId)]))
} else if toId == accountPeerId {
attributedString = addAttributesToStringWithRanges(strings.Notification_ProximityReachedYou(message.peers[fromId]?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "", distanceString), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, fromId)])) attributedString = addAttributesToStringWithRanges(strings.Notification_ProximityReachedYou(message.peers[fromId]?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "", distanceString), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, fromId)]))
} else { } else {
attributedString = addAttributesToStringWithRanges(strings.Notification_ProximityReached(message.peers[fromId]?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "", distanceString, message.peers[toId]?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? ""), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, fromId), (2, toId)])) attributedString = addAttributesToStringWithRanges(strings.Notification_ProximityReached(message.peers[fromId]?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "", distanceString, message.peers[toId]?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? ""), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, fromId), (2, toId)]))

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -829,7 +829,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
wasCheck = true wasCheck = true
} }
if isAudio && !isVoice { if isAudio && !isVoice && !isSending {
state = .play state = .play
} else { } else {
if message.groupingKey != nil, adjustedProgress.isEqual(to: 1.0), (message.flags.contains(.Unsent) || wasCheck) { if message.groupingKey != nil, adjustedProgress.isEqual(to: 1.0), (message.flags.contains(.Unsent) || wasCheck) {

View File

@ -21,6 +21,7 @@ public enum UndoOverlayContent {
case chatAddedToFolder(chatTitle: String, folderTitle: String) case chatAddedToFolder(chatTitle: String, folderTitle: String)
case chatRemovedFromFolder(chatTitle: String, folderTitle: String) case chatRemovedFromFolder(chatTitle: String, folderTitle: String)
case messagesUnpinned(title: String, text: String, undo: Bool, isHidden: Bool) case messagesUnpinned(title: String, text: String, undo: Bool, isHidden: Bool)
case setProximityAlert(title: String, text: String, cancelled: Bool)
} }
public enum UndoOverlayAction { public enum UndoOverlayAction {

View File

@ -221,7 +221,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
} }
displayUndo = undo displayUndo = undo
self.originalRemainingSeconds = undo ? 5 : 5 self.originalRemainingSeconds = 5
case let .emoji(path, text): case let .emoji(path, text):
self.iconNode = nil self.iconNode = nil
self.iconCheckNode = nil self.iconCheckNode = nil
@ -388,6 +388,23 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
} }
}) })
} }
case let .setProximityAlert(title, text, cancelled):
self.iconNode = nil
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: cancelled ? "anim_proximity_cancelled" : "anim_proximity_set", colors: [:], scale: 0.45)
self.animatedStickerNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
let link = MarkdownAttributeSet(font: Font.regular(14.0), textColor: undoTextColor)
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: link, linkAttribute: { _ in return nil }), textAlignment: .natural)
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
if !text.isEmpty {
self.textNode.attributedText = attributedText
}
displayUndo = false
self.originalRemainingSeconds = 3
} }
self.remainingSeconds = self.originalRemainingSeconds self.remainingSeconds = self.originalRemainingSeconds
@ -416,7 +433,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
switch content { switch content {
case .removedChat: case .removedChat:
self.panelWrapperNode.addSubnode(self.timerTextNode) self.panelWrapperNode.addSubnode(self.timerTextNode)
case .archivedChat, .hidArchive, .revealedArchive, .succeed, .emoji, .swipeToReply, .actionSucceeded, .stickersModified, .chatAddedToFolder, .chatRemovedFromFolder, .messagesUnpinned: case .archivedChat, .hidArchive, .revealedArchive, .succeed, .emoji, .swipeToReply, .actionSucceeded, .stickersModified, .chatAddedToFolder, .chatRemovedFromFolder, .messagesUnpinned, .setProximityAlert:
break break
case .dice: case .dice:
self.panelWrapperNode.clipsToBounds = true self.panelWrapperNode.clipsToBounds = true