diff --git a/submodules/LocationUI/Sources/LocationInfoListItem.swift b/submodules/LocationUI/Sources/LocationInfoListItem.swift index 915a36b7f0..723b55c99a 100644 --- a/submodules/LocationUI/Sources/LocationInfoListItem.swift +++ b/submodules/LocationUI/Sources/LocationInfoListItem.swift @@ -20,12 +20,13 @@ final class LocationInfoListItem: ListViewItem { let drivingTime: ExpectedTravelTime let transitTime: ExpectedTravelTime let walkingTime: ExpectedTravelTime + let hasEta: Bool let action: () -> Void let drivingAction: () -> Void let transitAction: () -> Void let walkingAction: () -> Void - public init(presentationData: ItemListPresentationData, engine: TelegramEngine, location: TelegramMediaMap, address: String?, distance: String?, drivingTime: ExpectedTravelTime, transitTime: ExpectedTravelTime, walkingTime: ExpectedTravelTime, action: @escaping () -> Void, drivingAction: @escaping () -> Void, transitAction: @escaping () -> Void, walkingAction: @escaping () -> Void) { + public init(presentationData: ItemListPresentationData, engine: TelegramEngine, location: TelegramMediaMap, address: String?, distance: String?, drivingTime: ExpectedTravelTime, transitTime: ExpectedTravelTime, walkingTime: ExpectedTravelTime, hasEta: Bool, action: @escaping () -> Void, drivingAction: @escaping () -> Void, transitAction: @escaping () -> Void, walkingAction: @escaping () -> Void) { self.presentationData = presentationData self.engine = engine self.location = location @@ -34,6 +35,7 @@ final class LocationInfoListItem: ListViewItem { self.drivingTime = drivingTime self.transitTime = transitTime self.walkingTime = walkingTime + self.hasEta = hasEta self.action = action self.drivingAction = drivingAction self.transitAction = transitAction @@ -179,7 +181,8 @@ final class LocationInfoListItemNode: ListViewItemNode { let titleSpacing: CGFloat = 1.0 let bottomInset: CGFloat = 4.0 - let contentSize = CGSize(width: params.width, height: max(100.0, verticalInset * 2.0 + titleLayout.size.height + titleSpacing + subtitleLayout.size.height + bottomInset)) + let textContentSize = verticalInset * 2.0 + titleLayout.size.height + titleSpacing + subtitleLayout.size.height + bottomInset + let contentSize = CGSize(width: params.width, height: item.hasEta ? max(100.0, textContentSize) : textContentSize) let nodeLayout = ListViewItemNodeLayout(contentSize: contentSize, insets: UIEdgeInsets()) return (nodeLayout, { [weak self] in @@ -280,95 +283,99 @@ final class LocationInfoListItemNode: ListViewItemNode { var directionsWidth: CGFloat = 93.0 - if item.drivingTime == .unknown && item.transitTime == .unknown && item.walkingTime == .unknown { - strongSelf.drivingButtonNode?.icon = nil - strongSelf.drivingButtonNode?.title = item.presentationData.strings.Map_GetDirections - if let drivingButtonNode = strongSelf.drivingButtonNode { - let buttonSize = drivingButtonNode.sizeThatFits(contentSize) - directionsWidth = buttonSize.width - } - - if let previousDrivingTime = currentItem?.drivingTime, case .calculating = previousDrivingTime { - strongSelf.drivingButtonNode?.alpha = 1.0 - strongSelf.drivingButtonNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) - } - } else { - if case let .ready(drivingTime) = item.drivingTime { - strongSelf.drivingButtonNode?.title = stringForEstimatedDuration(strings: item.presentationData.strings, time: drivingTime, format: { $0 }) + if item.hasEta { + if item.drivingTime == .unknown && item.transitTime == .unknown && item.walkingTime == .unknown { + strongSelf.drivingButtonNode?.icon = nil + strongSelf.drivingButtonNode?.title = item.presentationData.strings.Map_GetDirections + if let drivingButtonNode = strongSelf.drivingButtonNode { + let buttonSize = drivingButtonNode.sizeThatFits(contentSize) + directionsWidth = buttonSize.width + } if let previousDrivingTime = currentItem?.drivingTime, case .calculating = previousDrivingTime { strongSelf.drivingButtonNode?.alpha = 1.0 strongSelf.drivingButtonNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) } - } - - if case let .ready(transitTime) = item.transitTime { - strongSelf.transitButtonNode?.title = stringForEstimatedDuration(strings: item.presentationData.strings, time: transitTime, format: { $0 }) - - if let previousTransitTime = currentItem?.transitTime, case .calculating = previousTransitTime { - strongSelf.transitButtonNode?.alpha = 1.0 - strongSelf.transitButtonNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) - } - } - - if case let .ready(walkingTime) = item.walkingTime { - strongSelf.walkingButtonNode?.title = stringForEstimatedDuration(strings: item.presentationData.strings, time: walkingTime, format: { $0 }) - - if let previousWalkingTime = currentItem?.walkingTime, case .calculating = previousWalkingTime { - strongSelf.walkingButtonNode?.alpha = 1.0 - strongSelf.walkingButtonNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) - } - } - } - - let directionsSpacing: CGFloat = 8.0 - - if case .calculating = item.drivingTime, case .calculating = item.transitTime, case .calculating = item.walkingTime { - let shimmerNode: ShimmerEffectNode - if let current = strongSelf.placeholderNode { - shimmerNode = current } else { - shimmerNode = ShimmerEffectNode() - strongSelf.placeholderNode = shimmerNode - strongSelf.addSubnode(shimmerNode) - } - shimmerNode.frame = CGRect(origin: CGPoint(x: leftInset, y: subtitleFrame.maxY + 12.0), size: CGSize(width: contentSize.width - leftInset, height: 32.0)) - if let (rect, size) = strongSelf.absoluteLocation { - shimmerNode.updateAbsoluteRect(rect, within: size) + if case let .ready(drivingTime) = item.drivingTime { + strongSelf.drivingButtonNode?.title = stringForEstimatedDuration(strings: item.presentationData.strings, time: drivingTime, format: { $0 }) + + if let previousDrivingTime = currentItem?.drivingTime, case .calculating = previousDrivingTime { + strongSelf.drivingButtonNode?.alpha = 1.0 + strongSelf.drivingButtonNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + } + } + + if case let .ready(transitTime) = item.transitTime { + strongSelf.transitButtonNode?.title = stringForEstimatedDuration(strings: item.presentationData.strings, time: transitTime, format: { $0 }) + + if let previousTransitTime = currentItem?.transitTime, case .calculating = previousTransitTime { + strongSelf.transitButtonNode?.alpha = 1.0 + strongSelf.transitButtonNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + } + } + + if case let .ready(walkingTime) = item.walkingTime { + strongSelf.walkingButtonNode?.title = stringForEstimatedDuration(strings: item.presentationData.strings, time: walkingTime, format: { $0 }) + + if let previousWalkingTime = currentItem?.walkingTime, case .calculating = previousWalkingTime { + strongSelf.walkingButtonNode?.alpha = 1.0 + strongSelf.walkingButtonNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + } + } } - var shapes: [ShimmerEffectNode.Shape] = [] - shapes.append(.roundedRectLine(startPoint: CGPoint(x: 0.0, y: 0.0), width: directionsWidth, diameter: 32.0)) - shapes.append(.roundedRectLine(startPoint: CGPoint(x: directionsWidth + directionsSpacing, y: 0.0), width: directionsWidth, diameter: 32.0)) - shapes.append(.roundedRectLine(startPoint: CGPoint(x: directionsWidth + directionsSpacing + directionsWidth + directionsSpacing, y: 0.0), width: directionsWidth, diameter: 32.0)) + let directionsSpacing: CGFloat = 8.0 + + if case .calculating = item.drivingTime, case .calculating = item.transitTime, case .calculating = item.walkingTime { + let shimmerNode: ShimmerEffectNode + if let current = strongSelf.placeholderNode { + shimmerNode = current + } else { + shimmerNode = ShimmerEffectNode() + strongSelf.placeholderNode = shimmerNode + strongSelf.addSubnode(shimmerNode) + } + shimmerNode.frame = CGRect(origin: CGPoint(x: leftInset, y: subtitleFrame.maxY + 12.0), size: CGSize(width: contentSize.width - leftInset, height: 32.0)) + if let (rect, size) = strongSelf.absoluteLocation { + shimmerNode.updateAbsoluteRect(rect, within: size) + } + + var shapes: [ShimmerEffectNode.Shape] = [] + shapes.append(.roundedRectLine(startPoint: CGPoint(x: 0.0, y: 0.0), width: directionsWidth, diameter: 32.0)) + shapes.append(.roundedRectLine(startPoint: CGPoint(x: directionsWidth + directionsSpacing, y: 0.0), width: directionsWidth, diameter: 32.0)) + shapes.append(.roundedRectLine(startPoint: CGPoint(x: directionsWidth + directionsSpacing + directionsWidth + directionsSpacing, y: 0.0), width: directionsWidth, diameter: 32.0)) + + shimmerNode.update(backgroundColor: item.presentationData.theme.list.plainBackgroundColor, foregroundColor: item.presentationData.theme.list.mediaPlaceholderColor, shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: shapes, size: shimmerNode.frame.size) + } else if let shimmerNode = strongSelf.placeholderNode { + strongSelf.placeholderNode = nil + shimmerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak shimmerNode] _ in + shimmerNode?.removeFromSupernode() + }) + } + + let drivingHeight = strongSelf.drivingButtonNode?.updateLayout(width: directionsWidth, transition: .immediate) ?? 0.0 + let transitHeight = strongSelf.transitButtonNode?.updateLayout(width: directionsWidth, transition: .immediate) ?? 0.0 + let walkingHeight = strongSelf.walkingButtonNode?.updateLayout(width: directionsWidth, transition: .immediate) ?? 0.0 + + var buttonOrigin = leftInset + strongSelf.drivingButtonNode?.frame = CGRect(origin: CGPoint(x: buttonOrigin, y: subtitleFrame.maxY + 12.0), size: CGSize(width: directionsWidth, height: drivingHeight)) + + if case .ready = item.drivingTime { + buttonOrigin += directionsWidth + directionsSpacing + } + + strongSelf.transitButtonNode?.frame = CGRect(origin: CGPoint(x: buttonOrigin, y: subtitleFrame.maxY + 12.0), size: CGSize(width: directionsWidth, height: transitHeight)) + + if case .ready = item.transitTime { + buttonOrigin += directionsWidth + directionsSpacing + } + + strongSelf.walkingButtonNode?.frame = CGRect(origin: CGPoint(x: buttonOrigin, y: subtitleFrame.maxY + 12.0), size: CGSize(width: directionsWidth, height: walkingHeight)) + } else { - shimmerNode.update(backgroundColor: item.presentationData.theme.list.plainBackgroundColor, foregroundColor: item.presentationData.theme.list.mediaPlaceholderColor, shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: shapes, size: shimmerNode.frame.size) - } else if let shimmerNode = strongSelf.placeholderNode { - strongSelf.placeholderNode = nil - shimmerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak shimmerNode] _ in - shimmerNode?.removeFromSupernode() - }) } - let drivingHeight = strongSelf.drivingButtonNode?.updateLayout(width: directionsWidth, transition: .immediate) ?? 0.0 - let transitHeight = strongSelf.transitButtonNode?.updateLayout(width: directionsWidth, transition: .immediate) ?? 0.0 - let walkingHeight = strongSelf.walkingButtonNode?.updateLayout(width: directionsWidth, transition: .immediate) ?? 0.0 - - var buttonOrigin = leftInset - strongSelf.drivingButtonNode?.frame = CGRect(origin: CGPoint(x: buttonOrigin, y: subtitleFrame.maxY + 12.0), size: CGSize(width: directionsWidth, height: drivingHeight)) - - if case .ready = item.drivingTime { - buttonOrigin += directionsWidth + directionsSpacing - } - - strongSelf.transitButtonNode?.frame = CGRect(origin: CGPoint(x: buttonOrigin, y: subtitleFrame.maxY + 12.0), size: CGSize(width: directionsWidth, height: transitHeight)) - - if case .ready = item.transitTime { - buttonOrigin += directionsWidth + directionsSpacing - } - - strongSelf.walkingButtonNode?.frame = CGRect(origin: CGPoint(x: buttonOrigin, y: subtitleFrame.maxY + 12.0), size: CGSize(width: directionsWidth, height: walkingHeight)) - strongSelf.buttonNode.frame = CGRect(x: 0.0, y: 0.0, width: contentSize.width, height: 72.0) strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: contentSize.width, height: contentSize.height)) } diff --git a/submodules/LocationUI/Sources/LocationViewController.swift b/submodules/LocationUI/Sources/LocationViewController.swift index 37301ffdd2..71fd3a7f87 100644 --- a/submodules/LocationUI/Sources/LocationViewController.swift +++ b/submodules/LocationUI/Sources/LocationViewController.swift @@ -77,7 +77,7 @@ public final class LocationViewController: ViewController { private var presentationData: PresentationData private var presentationDataDisposable: Disposable? private var showAll: Bool - private let disableDismissGesture: Bool + private let isStoryLocation: Bool private let locationManager = LocationManager() private var permissionDisposable: Disposable? @@ -88,11 +88,11 @@ public final class LocationViewController: ViewController { public var dismissed: () -> Void = {} - public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, subject: EngineMessage, disableDismissGesture: Bool = false, params: LocationViewParams) { + public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, subject: EngineMessage, isStoryLocation: Bool = false, params: LocationViewParams) { self.context = context self.subject = subject self.showAll = params.showAll - self.disableDismissGesture = disableDismissGesture + self.isStoryLocation = isStoryLocation self.presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 } @@ -491,7 +491,7 @@ public final class LocationViewController: ViewController { return } - self.displayNode = LocationViewControllerNode(context: self.context, presentationData: self.presentationData, subject: self.subject, interaction: interaction, locationManager: self.locationManager) + self.displayNode = LocationViewControllerNode(context: self.context, presentationData: self.presentationData, subject: self.subject, interaction: interaction, locationManager: self.locationManager, isStoryLocation: self.isStoryLocation) self.displayNodeDidLoad() self.controllerNode.onAnnotationsReady = { [weak self] in @@ -501,7 +501,7 @@ public final class LocationViewController: ViewController { strongSelf.controllerNode.showAll() } - self.controllerNode.headerNode.mapNode.disableHorizontalTransitionGesture = self.disableDismissGesture + self.controllerNode.headerNode.mapNode.disableHorizontalTransitionGesture = self.isStoryLocation } private func updateRightBarButton() { diff --git a/submodules/LocationUI/Sources/LocationViewControllerNode.swift b/submodules/LocationUI/Sources/LocationViewControllerNode.swift index 9aa5b34c22..578cd30ff3 100644 --- a/submodules/LocationUI/Sources/LocationViewControllerNode.swift +++ b/submodules/LocationUI/Sources/LocationViewControllerNode.swift @@ -47,7 +47,7 @@ private enum LocationViewEntryId: Hashable { } private enum LocationViewEntry: Comparable, Identifiable { - case info(PresentationTheme, TelegramMediaMap, String?, Double?, ExpectedTravelTime, ExpectedTravelTime, ExpectedTravelTime) + case info(PresentationTheme, TelegramMediaMap, String?, Double?, ExpectedTravelTime, ExpectedTravelTime, ExpectedTravelTime, Bool) case toggleLiveLocation(PresentationTheme, String, String, Double?, Double?) case liveLocation(PresentationTheme, PresentationDateTimeFormat, PresentationPersonNameOrder, EngineMessage, Double?, ExpectedTravelTime, ExpectedTravelTime, ExpectedTravelTime, Int) @@ -64,8 +64,8 @@ private enum LocationViewEntry: Comparable, Identifiable { static func ==(lhs: LocationViewEntry, rhs: LocationViewEntry) -> Bool { switch lhs { - case let .info(lhsTheme, lhsLocation, lhsAddress, lhsDistance, lhsDrivingTime, lhsTransitTime, lhsWalkingTime): - if case let .info(rhsTheme, rhsLocation, rhsAddress, rhsDistance, rhsDrivingTime, rhsTransitTime, rhsWalkingTime) = rhs, lhsTheme === rhsTheme, lhsLocation.venue?.id == rhsLocation.venue?.id, lhsAddress == rhsAddress, lhsDistance == rhsDistance, lhsDrivingTime == rhsDrivingTime, lhsTransitTime == rhsTransitTime, lhsWalkingTime == rhsWalkingTime { + case let .info(lhsTheme, lhsLocation, lhsAddress, lhsDistance, lhsDrivingTime, lhsTransitTime, lhsWalkingTime, lhsHasEta): + if case let .info(rhsTheme, rhsLocation, rhsAddress, rhsDistance, rhsDrivingTime, rhsTransitTime, rhsWalkingTime, rhsHasEta) = rhs, lhsTheme === rhsTheme, lhsLocation.venue?.id == rhsLocation.venue?.id, lhsAddress == rhsAddress, lhsDistance == rhsDistance, lhsDrivingTime == rhsDrivingTime, lhsTransitTime == rhsTransitTime, lhsWalkingTime == rhsWalkingTime, lhsHasEta == rhsHasEta { return true } else { return false @@ -113,7 +113,7 @@ private enum LocationViewEntry: Comparable, Identifiable { func item(context: AccountContext, presentationData: PresentationData, interaction: LocationViewInteraction?) -> ListViewItem { switch self { - case let .info(_, location, address, distance, drivingTime, transitTime, walkingTime): + case let .info(_, location, address, distance, drivingTime, transitTime, walkingTime, hasEta): let addressString: String? if let address = address { addressString = address @@ -126,7 +126,7 @@ private enum LocationViewEntry: Comparable, Identifiable { } else { distanceString = nil } - return LocationInfoListItem(presentationData: ItemListPresentationData(presentationData), engine: context.engine, location: location, address: addressString, distance: distanceString, drivingTime: drivingTime, transitTime: transitTime, walkingTime: walkingTime, action: { + return LocationInfoListItem(presentationData: ItemListPresentationData(presentationData), engine: context.engine, location: location, address: addressString, distance: distanceString, drivingTime: drivingTime, transitTime: transitTime, walkingTime: walkingTime, hasEta: hasEta, action: { interaction?.goToCoordinate(location.coordinate) }, drivingAction: { interaction?.requestDirections(location, nil, .driving) @@ -219,6 +219,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan private var subject: EngineMessage private let interaction: LocationViewInteraction private let locationManager: LocationManager + private let isStoryLocation: Bool private let listNode: ListView let headerNode: LocationMapHeaderNode @@ -246,13 +247,14 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan } private let travelTimesPromise = Promise<[EngineMessage.Id: (Double, ExpectedTravelTime, ExpectedTravelTime, ExpectedTravelTime)]>([:]) - init(context: AccountContext, presentationData: PresentationData, subject: EngineMessage, interaction: LocationViewInteraction, locationManager: LocationManager) { + init(context: AccountContext, presentationData: PresentationData, subject: EngineMessage, interaction: LocationViewInteraction, locationManager: LocationManager, isStoryLocation: Bool) { self.context = context self.presentationData = presentationData self.presentationDataPromise = Promise(presentationData) self.subject = subject self.interaction = interaction self.locationManager = locationManager + self.isStoryLocation = isStoryLocation self.state = LocationViewState() self.statePromise = Promise(self.state) @@ -370,7 +372,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan let subjectLocation = CLLocation(latitude: location.latitude, longitude: location.longitude) let distance = userLocation.flatMap { subjectLocation.distance(from: $0) } - entries.append(.info(presentationData.theme, location, address, distance, eta.0, eta.1, eta.2)) + entries.append(.info(presentationData.theme, location, address, distance, eta.0, eta.1, eta.2, !isStoryLocation)) annotations.append(LocationPinAnnotation(context: context, theme: presentationData.theme, location: location, queryId: nil, resultId: nil, forcedSelection: true)) } else { @@ -849,7 +851,10 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan } let overlap: CGFloat = 6.0 - var topInset: CGFloat = layout.size.height - layout.intrinsicInsets.bottom - 100.0 - overlap + var topInset: CGFloat = layout.size.height - layout.intrinsicInsets.bottom - overlap + if !self.isStoryLocation { + topInset -= 100.0 + } if let location = getLocation(from: self.subject), location.liveBroadcastingTimeout != nil { topInset += 66.0 } diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift index 2ec11e67af..5f873e2134 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift @@ -3109,7 +3109,7 @@ final class StoryItemSetContainerSendMessage { let subject = EngineMessage(stableId: 0, stableVersion: 0, id: EngineMessage.Id(peerId: PeerId(0), namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: nil, text: "", attributes: [], media: [.geo(TelegramMediaMap(latitude: venue.latitude, longitude: venue.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: venue.venue, liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil))], peers: [:], associatedMessages: [:], associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) actions.append(ContextMenuAction(content: .textWithIcon(title: "View Location", icon: generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: .white)), action: { [weak controller, weak view] in - let locationController = LocationViewController(context: component.context, updatedPresentationData: updatedPresentationData, subject: subject, disableDismissGesture: true, params: LocationViewParams(sendLiveLocation: { _ in }, stopLiveLocation: { _ in }, openUrl: { _ in }, openPeer: { _ in })) + let locationController = LocationViewController(context: component.context, updatedPresentationData: updatedPresentationData, subject: subject, isStoryLocation: true, params: LocationViewParams(sendLiveLocation: { _ in }, stopLiveLocation: { _ in }, openUrl: { _ in }, openPeer: { _ in })) view?.updateModalTransitionFactor(1.0, transition: .animated(duration: 0.5, curve: .spring)) locationController.dismissed = { [weak view] in view?.updateModalTransitionFactor(0.0, transition: .animated(duration: 0.5, curve: .spring))