Location view fixes

This commit is contained in:
Ilya Laktyushin 2020-10-28 23:51:05 +04:00
parent c27ebb4787
commit 2f13d11224
10 changed files with 3969 additions and 3909 deletions

View File

@ -5840,6 +5840,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 %@";

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

@ -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,6 +189,8 @@ 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
@ -199,11 +204,12 @@ 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
self.wrappingScrollNode.view.delaysContentTouches = false self.wrappingScrollNode.view.delaysContentTouches = false
@ -256,9 +262,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
@ -368,8 +375,26 @@ class LocationDistancePickerScreenNode: ViewControllerTracingNode, UIScrollViewD
if !self.usesMetricSystem { if !self.usesMetricSystem {
value = Int32(Double(value) * 1.60934) value = Int32(Double(value) * 1.60934)
} }
let distance = stringForDistance(strings: self.presentationData.strings, distance: CLLocationDistance(value))
self.doneButton.title = self.presentationData.strings.Location_ProximityNotification_Notify(distance).0 var formattedValue = String(format: "%0.1f", CGFloat(value) / 1000.0)
if value == 50 {
formattedValue = formattedValue.replacingOccurrences(of: ".1", with: "0.05")
}
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.regular(14.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 {
@ -540,6 +565,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 +621,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

@ -483,7 +483,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? {

View File

@ -212,46 +212,58 @@ 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)
guard let strongSelf = self else { |> deliverOnMainQueue).start(next: { [weak self] peer in
return
}
strongSelf.controllerNode.setProximityIndicator(radius: distance)
}, completion: { [weak self] distance, completion in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
if let messageId = messageId { var compactDisplayTitle: String?
strongSelf.controllerNode.updateState { state in if let peer = peer as? TelegramUser {
var state = state compactDisplayTitle = peer.compactDisplayTitle
state.updatingProximityRadius = distance }
return state
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 if let messageId = messageId {
guard let strongSelf = self else {
return
}
strongSelf.controllerNode.updateState { state in strongSelf.controllerNode.updateState { state in
var state = state var state = state
state.updatingProximityRadius = nil state.updatingProximityRadius = distance
return state return state
} }
})
} else { 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
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: { guard let strongSelf = self else {
completion() return
strongSelf.interaction?.sendLiveLocation(distance) }
}), TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {})], actionLayout: .vertical), in: .window(.root)) strongSelf.controllerNode.updateState { state in
} var state = state
completion() state.updatingProximityRadius = nil
}, willDismiss: { [weak self] in return state
if let strongSelf = self { }
strongSelf.controllerNode.setProximityIndicator(radius: nil) })
} } 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 }, updateSendActionHighlight: { [weak self] highlighted in

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] = []

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)]))