diff --git a/TelegramUI/ChatListSearchContainerNode.swift b/TelegramUI/ChatListSearchContainerNode.swift index 7469204978..6c37e08139 100644 --- a/TelegramUI/ChatListSearchContainerNode.swift +++ b/TelegramUI/ChatListSearchContainerNode.swift @@ -766,7 +766,34 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode { } } |> distinctUntilChanged - var recentItemsTransition = combineLatest(hasRecentPeers, recentlySearchedPeers(postbox: account.postbox), presentationDataPromise.get(), self.statePromise.get()) + + let previousRecentlySearchedPeerOrder = Atomic<[PeerId]>(value: []) + let fixedRecentlySearchedPeers = recentlySearchedPeers(postbox: account.postbox) + |> map { peers -> [RecentlySearchedPeer] in + var result: [RecentlySearchedPeer] = [] + let _ = previousRecentlySearchedPeerOrder.modify { current in + var updated: [PeerId] = [] + for id in current { + inner: for peer in peers { + if peer.peer.peerId == id { + updated.append(id) + result.append(peer) + break inner + } + } + } + for peer in peers.reversed() { + if !updated.contains(peer.peer.peerId) { + updated.insert(peer.peer.peerId, at: 0) + result.insert(peer, at: 0) + } + } + return updated + } + return result + } + + var recentItemsTransition = combineLatest(hasRecentPeers, fixedRecentlySearchedPeers, presentationDataPromise.get(), self.statePromise.get()) |> mapToSignal { [weak self] hasRecentPeers, peers, presentationData, state -> Signal<(ChatListSearchContainerRecentTransition, Bool), NoError> in var entries: [ChatListRecentEntry] = [] if !filter.contains(.onlyGroups) { diff --git a/TelegramUI/ChatMessageInteractiveMediaNode.swift b/TelegramUI/ChatMessageInteractiveMediaNode.swift index 10620e2ebf..b84535f554 100644 --- a/TelegramUI/ChatMessageInteractiveMediaNode.swift +++ b/TelegramUI/ChatMessageInteractiveMediaNode.swift @@ -22,6 +22,7 @@ enum InteractiveMediaNodeActivateContent { final class ChatMessageInteractiveMediaNode: ASDisplayNode { private let imageNode: TransformImageNode + private var currentImageArguments: TransformImageArguments? private var videoNode: UniversalVideoNode? private var statusNode: RadialStatusNode? private var badgeNode: ChatMessageInteractiveMediaBadge? @@ -396,7 +397,19 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode { strongSelf.sizeCalculation = sizeCalculation strongSelf.automaticPlayback = automaticPlayback strongSelf.automaticDownload = automaticDownload - transition.updateFrame(node: strongSelf.imageNode, frame: imageFrame) + + if let previousArguments = strongSelf.currentImageArguments { + if previousArguments.imageSize == arguments.imageSize { + strongSelf.imageNode.frame = imageFrame + } else { + transition.updateFrame(node: strongSelf.imageNode, frame: imageFrame) + } + } else { + strongSelf.imageNode.frame = imageFrame + } + strongSelf.currentImageArguments = arguments + imageApply() + strongSelf.statusNode?.position = CGPoint(x: imageFrame.midX, y: imageFrame.midY) if let replaceVideoNode = replaceVideoNode { @@ -469,8 +482,6 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode { strongSelf.fetchControls.with({ $0 })?.fetch(false) } - imageApply() - strongSelf.updateFetchStatus() } }) diff --git a/TelegramUI/ContactMultiselectionController.swift b/TelegramUI/ContactMultiselectionController.swift index ad0af73fdb..63dd22d86c 100644 --- a/TelegramUI/ContactMultiselectionController.swift +++ b/TelegramUI/ContactMultiselectionController.swift @@ -304,6 +304,7 @@ class ContactMultiselectionController: ViewController { if let presentationArguments = self.presentationArguments as? ViewControllerPresentationArguments { switch presentationArguments.presentationAnimation { case .modalSheet: + self.view.endEditing(true) self.contactsNode.animateOut(completion: { [weak self] in self?.dismissed?() completion?() diff --git a/TelegramUI/ContactMultiselectionControllerNode.swift b/TelegramUI/ContactMultiselectionControllerNode.swift index 0810dea8ef..88758f3e27 100644 --- a/TelegramUI/ContactMultiselectionControllerNode.swift +++ b/TelegramUI/ContactMultiselectionControllerNode.swift @@ -174,7 +174,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode { } func animateOut(completion: (() -> Void)?) { - self.layer.animatePosition(from: self.layer.position, to: CGPoint(x: 0.0, y: self.layer.bounds.size.height), duration: 0.2, timingFunction: kCAMediaTimingFunctionEaseInEaseOut, removeOnCompletion: false, additive: true, completion: { [weak self] _ in + self.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: self.layer.bounds.size.height), duration: 0.2, timingFunction: kCAMediaTimingFunctionEaseInEaseOut, removeOnCompletion: false, additive: true, completion: { [weak self] _ in if let strongSelf = self { strongSelf.dismiss?() completion?() diff --git a/TelegramUI/InstantPageControllerNode.swift b/TelegramUI/InstantPageControllerNode.swift index 4ebb1d84e4..4bfb16ed3d 100644 --- a/TelegramUI/InstantPageControllerNode.swift +++ b/TelegramUI/InstantPageControllerNode.swift @@ -368,7 +368,14 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { } } - if self.currentExpandedDetails == nil { + if var currentExpandedDetails = self.currentExpandedDetails { + for (index, expanded) in expandedDetails { + if currentExpandedDetails[index] == nil { + currentExpandedDetails[index] = expanded + } + } + self.currentExpandedDetails = currentExpandedDetails + } else { self.currentExpandedDetails = expandedDetails } @@ -540,8 +547,8 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { } } } - - if let currentLayout = self.currentLayout, collapseOffset > 0.0 { + + if let currentLayout = self.currentLayout { let effectiveContentHeight = currentLayout.contentSize.height - collapseOffset if effectiveContentHeight != self.scrollNode.view.contentSize.height { transition.animateView { @@ -928,12 +935,17 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { private func findAnchorItem(_ anchor: String, items: [InstantPageItem]) -> (InstantPageItem, CGFloat, [InstantPageDetailsItem])? { for item in items { if let item = item as? InstantPageAnchorItem, item.anchor == anchor { - return (item, 0.0, []) + return (item, -10.0, []) } else if let item = item as? InstantPageTextItem { if let lineIndex = item.anchors[anchor] { return (item, item.lines[lineIndex].frame.minY - 10.0, []) } } + else if let item = item as? InstantPageTableItem { + if let offset = item.anchors[anchor] { + return (item, offset - 10.0, []) + } + } else if let item = item as? InstantPageDetailsItem { if let (foundItem, offset, detailsItems) = self.findAnchorItem(anchor, items: item.items) { var detailsItems = detailsItems @@ -965,14 +977,13 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { if let webPage = self.webPage, case let .Loaded(content) = webPage.content, let page = content.instantPage, page.url == baseUrl, let anchor = anchor { if !anchor.isEmpty { if let (item, lineOffset, detailsItems) = findAnchorItem(String(anchor), items: items) { - var previousDetailsItem: InstantPageDetailsItem? var previousDetailsNode: InstantPageDetailsNode? var containerOffset: CGFloat = 0.0 for detailsItem in detailsItems { - if let previousNode = previousDetailsNode, let previousDetailsItem = previousDetailsItem { + if let previousNode = previousDetailsNode { previousNode.contentNode.updateDetailsExpanded(detailsItem.index, true, animated: false) - let frame = previousNode.contentNode.effectiveFrameForItem(detailsItem) - containerOffset += frame.minY + previousDetailsItem.titleHeight + let frame = previousNode.effectiveFrameForItem(detailsItem) + containerOffset += frame.minY previousDetailsNode = previousNode.contentNode.nodeForDetailsItem(detailsItem) previousDetailsNode?.setExpanded(true, animated: false) @@ -983,18 +994,23 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { previousDetailsNode = self.nodeForDetailsItem(detailsItem) previousDetailsNode?.setExpanded(true, animated: false) - previousDetailsItem = detailsItem } } let frame: CGRect - if let previousDetailsNode = previousDetailsNode, let previousDetailsItem = previousDetailsItem { - containerOffset += previousDetailsItem.titleHeight - frame = previousDetailsNode.contentNode.effectiveFrameForItem(item) + if let previousDetailsNode = previousDetailsNode { + frame = previousDetailsNode.effectiveFrameForItem(item) } else { frame = self.effectiveFrameForItem(item) } - self.scrollNode.view.setContentOffset(CGPoint(x: 0.0, y: containerOffset + frame.minY + lineOffset - self.scrollNode.view.contentInset.top), animated: true) + + var targetY = min(containerOffset + frame.minY + lineOffset, self.scrollNode.view.contentSize.height - self.scrollNode.frame.height) + if targetY < self.scrollNode.view.contentOffset.y { + targetY -= self.scrollNode.view.contentInset.top + } else { + targetY -= self.containerLayout?.statusBarHeight ?? 20.0 + } + self.scrollNode.view.setContentOffset(CGPoint(x: 0.0, y: targetY), animated: true) } } else { self.scrollNode.view.setContentOffset(CGPoint(x: 0.0, y: -self.scrollNode.view.contentInset.top), animated: true) diff --git a/TelegramUI/InstantPageDetailsNode.swift b/TelegramUI/InstantPageDetailsNode.swift index 9ad1d26ad9..3c8a494c83 100644 --- a/TelegramUI/InstantPageDetailsNode.swift +++ b/TelegramUI/InstantPageDetailsNode.swift @@ -361,7 +361,7 @@ final class InstantPageDetailsContentNode : ASDisplayNode { return CGRect(origin: origin, size: tile.frame.size) } - func effectiveFrameForItem(_ item: InstantPageItem) -> CGRect { + fileprivate func effectiveFrameForItem(_ item: InstantPageItem) -> CGRect { let layoutOrigin = item.frame.origin var origin = layoutOrigin @@ -610,6 +610,10 @@ final class InstantPageDetailsNode: ASDisplayNode, InstantPageNode { var effectiveContentSize: CGSize { return self.contentNode.effectiveContentSize } + + func effectiveFrameForItem(_ item: InstantPageItem) -> CGRect { + return self.contentNode.effectiveFrameForItem(item).offsetBy(dx: 0.0, dy: self.item.titleHeight) + } } private final class InstantPageDetailsArrowNodeParameters: NSObject { diff --git a/TelegramUI/InstantPageFeedbackItem.swift b/TelegramUI/InstantPageFeedbackItem.swift index 8362b7af89..fbbb85e299 100644 --- a/TelegramUI/InstantPageFeedbackItem.swift +++ b/TelegramUI/InstantPageFeedbackItem.swift @@ -32,11 +32,11 @@ final class InstantPageFeedbackItem: InstantPageItem { } func distanceThresholdGroup() -> Int? { - return nil + return 8 } func distanceThresholdWithGroupCount(_ count: Int) -> CGFloat { - return 0.0 + return CGFloat.greatestFiniteMagnitude } func linkSelectionRects(at point: CGPoint) -> [CGRect] { diff --git a/TelegramUI/InstantPageLayout.swift b/TelegramUI/InstantPageLayout.swift index 9d236c3a1b..abdb178ba8 100644 --- a/TelegramUI/InstantPageLayout.swift +++ b/TelegramUI/InstantPageLayout.swift @@ -269,7 +269,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins for subBlock in blocks { let subLayout = layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0 - indexSpacing - maxIndexWidth, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: listItems, fillToSize: nil, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights) - let spacing: CGFloat = previousBlock != nil ? spacingBetweenBlocks(upper: previousBlock, lower: subBlock) : 0.0 + let spacing: CGFloat = previousBlock != nil && subLayout.contentSize.height > 0.0 ? spacingBetweenBlocks(upper: previousBlock, lower: subBlock) : 0.0 let blockItems = subLayout.flattenedItemsWithOrigin(CGPoint(x: horizontalInset + indexSpacing + maxIndexWidth, y: contentSize.height + spacing)) if previousBlock == nil { originY += spacing diff --git a/TelegramUI/InstantPageLayoutSpacings.swift b/TelegramUI/InstantPageLayoutSpacings.swift index 3c7c49995c..b676fbf4c5 100644 --- a/TelegramUI/InstantPageLayoutSpacings.swift +++ b/TelegramUI/InstantPageLayoutSpacings.swift @@ -4,7 +4,7 @@ import TelegramCore func spacingBetweenBlocks(upper: InstantPageBlock?, lower: InstantPageBlock?) -> CGFloat { if let upper = upper, let lower = lower { switch (upper, lower) { - case (_, .cover), (_, .channelBanner), (.details, .details), (.relatedArticles, nil), (.anchor, _), (_, .anchor): + case (_, .cover), (_, .channelBanner), (.details, .details), (.relatedArticles, nil), (_, .anchor): return 0.0 case (.divider, _), (_, .divider): return 25.0 @@ -49,7 +49,7 @@ func spacingBetweenBlocks(upper: InstantPageBlock?, lower: InstantPageBlock?) -> } } else if let lower = lower { switch lower { - case .cover, .channelBanner, .details: + case .cover, .channelBanner, .details, .anchor: return 0.0 default: return 25.0 diff --git a/TelegramUI/InstantPageTableItem.swift b/TelegramUI/InstantPageTableItem.swift index 61e1c9e661..916a3cca0e 100644 --- a/TelegramUI/InstantPageTableItem.swift +++ b/TelegramUI/InstantPageTableItem.swift @@ -108,6 +108,8 @@ final class InstantPageTableItem: InstantPageScrollableItem { fileprivate let cells: [InstantPageTableCellItem] private let borderWidth: CGFloat + let anchors: [String: CGFloat] + fileprivate init(frame: CGRect, totalWidth: CGFloat, horizontalInset: CGFloat, borderWidth: CGFloat, theme: InstantPageTheme, cells: [InstantPageTableCellItem], rtl: Bool) { self.frame = frame self.totalWidth = totalWidth @@ -116,6 +118,20 @@ final class InstantPageTableItem: InstantPageScrollableItem { self.theme = theme self.cells = cells self.isRTL = rtl + + var anchors: [String: CGFloat] = [:] + for cell in cells { + if let textItem = cell.textItem { + for (anchor, lineIndex) in textItem.anchors { + if anchors[anchor] == nil { + let textItemFrame = textItem.frame.offsetBy(dx: cell.frame.minX, dy: cell.frame.minY) + let offset = textItemFrame.minY + textItem.lines[lineIndex].frame.minY + anchors[anchor] = offset + } + } + } + } + self.anchors = anchors } var contentSize: CGSize { diff --git a/TelegramUI/InstantPageTextItem.swift b/TelegramUI/InstantPageTextItem.swift index 38dc33918c..e4553bba44 100644 --- a/TelegramUI/InstantPageTextItem.swift +++ b/TelegramUI/InstantPageTextItem.swift @@ -552,7 +552,8 @@ func layoutTextItemWithString(_ string: NSAttributedString, boundingWidth: CGFlo var lastIndex: CFIndex = 0 var currentLineOrigin = CGPoint() - + + var hasAnchors = false var maxLineWidth: CGFloat = 0.0 var maxImageHeight: CGFloat = 0.0 var extraDescent: CGFloat = 0.0 @@ -677,6 +678,10 @@ func layoutTextItemWithString(_ string: NSAttributedString, boundingWidth: CGFlo } } + if !anchorItems.isEmpty { + hasAnchors = true + } + if hadExtraDescent && extraDescent > 0 { workingLineOrigin.y += fontLineSpacing } @@ -706,7 +711,7 @@ func layoutTextItemWithString(_ string: NSAttributedString, boundingWidth: CGFlo } var height: CGFloat = 0.0 - if !lines.isEmpty { + if !lines.isEmpty && !(string.length == 1 && hasAnchors) { height = lines.last!.frame.maxY + extraDescent } diff --git a/TelegramUI/UserInfoController.swift b/TelegramUI/UserInfoController.swift index 8a895bf593..76e3780dea 100644 --- a/TelegramUI/UserInfoController.swift +++ b/TelegramUI/UserInfoController.swift @@ -634,7 +634,7 @@ private func userInfoEntries(account: Account, presentationData: PresentationDat entries.append(UserInfoEntry.addContact(presentationData.theme, presentationData.strings.UserInfo_AddContact)) } - if let cachedUserData = cachedPeerData as? CachedUserData, !(cachedUserData.hasAccountPeerPhone ?? false) { + if let cachedUserData = cachedPeerData as? CachedUserData, let hasAccountPeerPhone = cachedUserData.hasAccountPeerPhone, !hasAccountPeerPhone { entries.append(UserInfoEntry.shareMyContact(presentationData.theme, presentationData.strings.UserInfo_ShareMyContactInfo)) }