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.UnlinkChannel" = "Unlink Channel";
"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$@?
Any member of this group will be able to see messages in the channel.";
"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.";
"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";
@ -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.ProximityReachedYou" = "%1$@ is now within %2$@ from you";
"Notification.ProximityYouReached" = "You are now within %1$@ from %2$@";
"Location.ProximityNotification.Title" = "Proximity Alert";
"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.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.PublicShares" = "Public Shares";
"Stats.Message.PrivateShares" = "Private Shares";

View File

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

View File

@ -5,6 +5,7 @@ import Display
import TelegramPresentationData
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 {
let backgroundColor: UIColor
@ -119,10 +120,16 @@ public final class ChatMessageLiveLocationTimerNode: ASDisplayNode {
path.lineCapStyle = .round
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 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/TelegramNotices:TelegramNotices",
"//submodules/TooltipUI:TooltipUI",
"//submodules/UndoUI:UndoUI",
],
frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework",

View File

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

View File

@ -239,7 +239,10 @@ final class LocationActionListItemNode: ListViewItemNode {
let titleSpacing: CGFloat = 1.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())
return (nodeLayout, { [weak self] in

View File

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

View File

@ -28,16 +28,18 @@ final class LocationDistancePickerScreen: ViewController {
private let context: AccountContext
private let style: LocationDistancePickerScreenStyle
private let distances: Signal<[Double], NoError>
private let compactDisplayTitle: String?
private let updated: (Int32?) -> Void
private let completion: (Int32, @escaping () -> Void) -> Void
private let willDismiss: () -> Void
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.style = style
self.distances = distances
self.compactDisplayTitle = compactDisplayTitle
self.updated = updated
self.completion = completion
self.willDismiss = willDismiss
@ -67,7 +69,7 @@ final class LocationDistancePickerScreen: ViewController {
}
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
guard let strongSelf = self else {
return
@ -173,6 +175,7 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
private let context: AccountContext
private let controllerStyle: LocationDistancePickerScreenStyle
private var presentationData: PresentationData
private var compactDisplayTitle: String?
private var distances: [Double] = []
private let dimNode: ASDisplayNode
@ -186,10 +189,14 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
private let cancelButton: HighlightableButtonNode
private let doneButton: SolidRoundedButtonNode
private let measureButtonTitleNode: ImmediateTextNode
private var pickerView: TimerPickerView?
private let unitLabelNode: ImmediateTextNode
private let smallUnitLabelNode: ImmediateTextNode
private var pickerTimer: SwiftSignalKit.Timer?
private var containerLayout: (ContainerViewLayout, CGFloat)?
private var distancesDisposable: Disposable?
@ -199,11 +206,12 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
var dismiss: (() -> 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.controllerStyle = style
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.compactDisplayTitle = compactDisplayTitle
self.wrappingScrollNode = ASScrollNode()
self.wrappingScrollNode.view.alwaysBounceVertical = true
self.wrappingScrollNode.view.delaysContentTouches = false
@ -256,9 +264,10 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
self.doneButton.title = self.presentationData.strings.Conversation_Timer_Send
self.unitLabelNode = ImmediateTextNode()
self.smallUnitLabelNode = ImmediateTextNode()
self.measureButtonTitleNode = ImmediateTextNode()
super.init()
self.backgroundColor = nil
@ -314,6 +323,8 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
deinit {
self.distancesDisposable?.dispose()
self.pickerTimer?.invalidate()
}
func setupPickerView() {
@ -338,6 +349,18 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
self.contentContainerNode.addSubnode(self.unitLabelNode)
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()
}
@ -364,19 +387,38 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
let largeValue = unitValues[selectedLargeRow]
let smallValue = smallUnitValues[selectedSmallRow]
var value = largeValue * 1000 + smallValue * 10
if !self.usesMetricSystem {
value = Int32(Double(value) * 1.60934)
let value = largeValue * 1000 + smallValue * 10
var formattedValue = String(format: "%0.1f", CGFloat(value) / 1000.0)
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))
self.doneButton.title = self.presentationData.strings.Location_ProximityNotification_Notify(distance).0
let distance = self.usesMetricSystem ? "\(formattedValue) \(self.presentationData.strings.Location_ProximityNotification_DistanceKM)" : "\(formattedValue) \(self.presentationData.strings.Location_ProximityNotification_DistanceMI)"
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)
if let (layout, navigationBarHeight) = self.containerLayout {
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.isUserInteractionEnabled = false
self.textNode.alpha = 1.0
@ -388,26 +430,41 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
}
}
fileprivate func update() {
var previousReportedValue: Int32?
fileprivate func update() -> Bool {
if let pickerView = self.pickerView {
let largeValue = unitValues[pickerView.selectedRow(inComponent: 0)]
let smallValue = smallUnitValues[pickerView.selectedRow(inComponent: 1)]
let selectedLargeRow = pickerView.selectedRow(inComponent: 0)
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
if !self.usesMetricSystem {
value = Int32(Double(value) * 1.60934)
}
self.updated?(value)
if let previousReportedValue = self.previousReportedValue, value == previousReportedValue {
return false
} else {
self.updated?(value)
self.previousReportedValue = value
return true
}
} else {
return false
}
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView.selectedRow(inComponent: 0) == 0 && pickerView.selectedRow(inComponent: 1) == 0 {
pickerView.selectRow(1, inComponent: 1, animated: true)
} else {
self.updateDoneButtonTitle()
self.update()
}
self.updateDoneButtonTitle()
self.update()
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
@ -540,6 +597,7 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
}
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
var hadValidLayout = self.containerLayout != nil
self.containerLayout = (layout, navigationBarHeight)
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.contentContainerNode, frame: contentContainerFrame)
if !hadValidLayout {
self.updateDoneButtonTitle()
}
}
}

View File

@ -178,7 +178,7 @@ final class LocationLiveListItemNode: ListViewItemNode {
var subtitle = timeString
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)"
}

View File

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

View File

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

View File

@ -7,6 +7,7 @@ import SyncCore
import Postbox
import SwiftSignalKit
import TelegramPresentationData
import TelegramStringFormatting
import AccountContext
import AppBundle
import CoreLocation
@ -14,6 +15,7 @@ import PresentationDataUtils
import OpenInExternalAppUI
import ShareController
import DeviceAccess
import UndoUI
public class LocationViewParams {
let sendLiveLocation: (TelegramMediaMap) -> Void
@ -194,12 +196,31 @@ public final class LocationViewController: ViewController {
guard let strongSelf = self else {
return
}
strongSelf.controllerNode.updateState { state in
var state = state
state.cancellingProximityRadius = false
return state
Queue.mainQueue().after(0.5) {
strongSelf.controllerNode.updateState { state in
var state = state
state.cancellingProximityRadius = false
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 {
DeviceAccess.authorizeAccess(to: .location(.live), locationManager: strongSelf.locationManager, presentationData: strongSelf.presentationData, present: { c, a in
@ -212,46 +233,85 @@ public final class LocationViewController: ViewController {
}
strongSelf.controllerNode.setProximityIndicator(radius: 0)
let controller = LocationDistancePickerScreen(context: context, style: .default, distances: strongSelf.controllerNode.headerNode.mapNode.distancesToAllAnnotations, updated: { [weak self] distance in
guard let strongSelf = self else {
return
}
strongSelf.controllerNode.setProximityIndicator(radius: distance)
}, completion: { [weak self] distance, completion in
let _ = (strongSelf.context.account.postbox.loadedPeerWithId(strongSelf.subject.id.peerId)
|> deliverOnMainQueue).start(next: { [weak self] peer in
guard let strongSelf = self else {
return
}
if let messageId = messageId {
strongSelf.controllerNode.updateState { state in
var state = state
state.updatingProximityRadius = distance
return state
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 {
return
}
strongSelf.controllerNode.setProximityIndicator(radius: distance)
}, completion: { [weak self] distance, completion in
guard let strongSelf = self else {
return
}
let _ = requestEditLiveLocation(postbox: context.account.postbox, network: context.account.network, stateManager: context.account.stateManager, messageId: messageId, stop: false, coordinate: nil, heading: nil, proximityNotificationRadius: distance).start(completed: { [weak self] in
guard let strongSelf = self else {
return
}
if let messageId = messageId {
strongSelf.controllerNode.updateState { state in
var state = state
state.updatingProximityRadius = nil
state.updatingProximityRadius = distance
return state
}
})
} 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: {
completion()
strongSelf.interaction?.sendLiveLocation(distance)
}), TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {})], actionLayout: .vertical), in: .window(.root))
}
completion()
}, willDismiss: { [weak self] in
if let strongSelf = self {
strongSelf.controllerNode.setProximityIndicator(radius: nil)
}
let _ = requestEditLiveLocation(postbox: context.account.postbox, network: context.account.network, stateManager: context.account.stateManager, messageId: messageId, stop: false, coordinate: nil, heading: nil, proximityNotificationRadius: distance).start(completed: { [weak self] in
guard let strongSelf = self else {
return
}
Queue.mainQueue().after(0.5) {
strongSelf.controllerNode.updateState { state in
var state = state
state.updatingProximityRadius = nil
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 {
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()
strongSelf.interaction?.sendLiveLocation(distance)
}), TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {})], actionLayout: .vertical), in: .window(.root))
}
completion()
}, willDismiss: { [weak self] in
if let strongSelf = self {
strongSelf.controllerNode.setProximityIndicator(radius: nil)
}
})
strongSelf.present(controller, in: .window(.root))
})
strongSelf.present(controller, in: .window(.root))
}
}
}, updateSendActionHighlight: { [weak self] highlighted in
@ -277,6 +337,43 @@ public final class LocationViewController: ViewController {
|> deliverOnMainQueue).start(next: { coordinate in
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 {
let _ = (context.account.postbox.loadedPeerWithId(subject.id.peerId)
|> deliverOnMainQueue).start(next: { peer in
@ -293,6 +390,8 @@ public final class LocationViewController: ViewController {
|> deliverOnMainQueue).start(next: { coordinate in
params.sendLiveLocation(TelegramMediaMap(coordinate: coordinate, liveBroadcastingTimeout: period))
})
strongSelf.controllerNode.showAll()
}
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() {
super.loadDisplayNode()
guard let interaction = self.interaction else {

View File

@ -48,7 +48,7 @@ private enum LocationViewEntryId: Hashable {
private enum LocationViewEntry: Comparable, Identifiable {
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)
var stableId: LocationViewEntryId {
@ -70,8 +70,8 @@ private enum LocationViewEntry: Comparable, Identifiable {
} else {
return false
}
case let .toggleLiveLocation(lhsTheme, lhsTitle, lhsSubtitle, lhsCoordinate, 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 {
case let .toggleLiveLocation(lhsTheme, lhsTitle, lhsSubtitle, lhsBeginTimestamp, lhsTimeout):
if case let .toggleLiveLocation(rhsTheme, rhsTitle, rhsSubtitle, rhsBeginTimestamp, rhsTimeout) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsSubtitle == rhsSubtitle, lhsBeginTimestamp == rhsBeginTimestamp, lhsTimeout == rhsTimeout {
return true
} else {
return false
@ -132,7 +132,7 @@ private enum LocationViewEntry: Comparable, Identifiable {
}, getDirections: {
interaction?.requestDirections()
})
case let .toggleLiveLocation(_, title, subtitle, coordinate, beginTimstamp, timeout):
case let .toggleLiveLocation(_, title, subtitle, beginTimstamp, timeout):
let beginTimeAndTimeout: (Double, Double)?
if let beginTimstamp = beginTimstamp, let timeout = timeout {
beginTimeAndTimeout = (beginTimstamp, timeout)
@ -149,7 +149,11 @@ private enum LocationViewEntry: Comparable, Identifiable {
interaction?.updateSendActionHighlight(highlight)
})
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
}
setupProximityNotificationImpl = { [weak self] reset in
setupProximityNotificationImpl = { reset in
let _ = (liveLocations
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] messages in
|> deliverOnMainQueue).start(next: { messages in
var ownMessageId: MessageId?
for message in messages {
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 {
} else {
entries.append(.toggleLiveLocation(presentationData.theme, title, subtitle, userLocation?.coordinate, beginTime, timeout))
entries.append(.toggleLiveLocation(presentationData.theme, title, subtitle, beginTime, timeout))
}
var sortedLiveLocations: [Message] = []
@ -409,9 +413,9 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
let distance = userLocation.flatMap { subjectLocation.distance(from: $0) }
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 {
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))
}
index += 1
@ -420,6 +424,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
if let currentProximityNotification = proximityNotification, currentProximityNotification && state.cancellingProximityRadius {
proximityNotification = false
proximityNotificationRadius = nil
} else if let radius = state.updatingProximityRadius {
proximityNotification = true
proximityNotificationRadius = radius
@ -481,7 +486,9 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
if !strongSelf.reportedAnnotationsReady {
strongSelf.reportedAnnotationsReady = true
strongSelf.onAnnotationsReady?()
if annotations.count > 0 {
strongSelf.onAnnotationsReady?()
}
}
}
@ -492,7 +499,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
}
let rightBarButtonAction: LocationViewRightBarButton
if location.liveBroadcastingTimeout != nil {
if liveLocations.count > 1 {
if annotations.count > 0 {
rightBarButtonAction = .showAll
} else {
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.delegate = self
}

View File

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

View File

@ -444,7 +444,9 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
attributedString = nil
case let .geoProximityReached(fromId, toId, 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)]))
} 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)]))

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
}
if isAudio && !isVoice {
if isAudio && !isVoice && !isSending {
state = .play
} else {
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 chatRemovedFromFolder(chatTitle: String, folderTitle: String)
case messagesUnpinned(title: String, text: String, undo: Bool, isHidden: Bool)
case setProximityAlert(title: String, text: String, cancelled: Bool)
}
public enum UndoOverlayAction {

View File

@ -221,7 +221,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
}
displayUndo = undo
self.originalRemainingSeconds = undo ? 5 : 5
self.originalRemainingSeconds = 5
case let .emoji(path, text):
self.iconNode = 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
@ -416,7 +433,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
switch content {
case .removedChat:
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
case .dice:
self.panelWrapperNode.clipsToBounds = true