From e07e91fd18013651dce8ae859bafb69946a96dd4 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Thu, 28 Oct 2021 17:59:12 +0400 Subject: [PATCH] Shared media improvements --- .../Sources/CalendarMessageScreen.swift | 40 ++++++++---- .../Sources/SparseItemGrid.swift | 26 ++++++-- .../Messages/SparseMessageList.swift | 48 +++++++++----- .../Panes/PeerInfoVisualMediaPaneNode.swift | 63 +++++++++++++------ .../Sources/PeerInfo/PeerInfoScreen.swift | 4 +- 5 files changed, 129 insertions(+), 52 deletions(-) diff --git a/submodules/CalendarMessageScreen/Sources/CalendarMessageScreen.swift b/submodules/CalendarMessageScreen/Sources/CalendarMessageScreen.swift index 30148e9ae2..c47806f5f7 100644 --- a/submodules/CalendarMessageScreen/Sources/CalendarMessageScreen.swift +++ b/submodules/CalendarMessageScreen/Sources/CalendarMessageScreen.swift @@ -578,6 +578,15 @@ private final class DayComponent: Component { } let titleImage = dayEnvironment.imageCache.text(fontSize: titleFontSize, isSemibold: titleFontIsSemibold, color: titleColor, string: component.title) + if animateMediaIn { + let previousTitleView = UIImageView(image: self.titleView.image) + previousTitleView.frame = self.titleView.frame + self.titleView.superview?.insertSubview(previousTitleView, aboveSubview: self.titleView) + previousTitleView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak previousTitleView] _ in + previousTitleView?.removeFromSuperview() + }) + self.titleView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.16) + } self.titleView.image = titleImage let titleSize = titleImage.size @@ -595,6 +604,7 @@ private final class DayComponent: Component { if animateMediaIn { mediaPreviewView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + self.highlightView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) } } @@ -946,7 +956,7 @@ public final class CalendarMessageScreen: ViewController { private let context: AccountContext private let peerId: PeerId private let initialTimestamp: Int32 - private let navigateToDay: (Int32) -> Void + private let navigateToOffset: (Int) -> Void private let previewDay: (MessageIndex, ASDisplayNode, CGRect, ContextGesture) -> Void private var presentationData: PresentationData @@ -975,13 +985,13 @@ public final class CalendarMessageScreen: ViewController { private var ignoreContentOffset: Bool = false - init(controller: CalendarMessageScreen, context: AccountContext, peerId: PeerId, calendarSource: SparseMessageCalendar, initialTimestamp: Int32, navigateToDay: @escaping (Int32) -> Void, previewDay: @escaping (MessageIndex, ASDisplayNode, CGRect, ContextGesture) -> Void) { + init(controller: CalendarMessageScreen, context: AccountContext, peerId: PeerId, calendarSource: SparseMessageCalendar, initialTimestamp: Int32, navigateToOffset: @escaping (Int) -> Void, previewDay: @escaping (MessageIndex, ASDisplayNode, CGRect, ContextGesture) -> Void) { self.controller = controller self.context = context self.peerId = peerId self.initialTimestamp = initialTimestamp self.calendarSource = calendarSource - self.navigateToDay = navigateToDay + self.navigateToOffset = navigateToOffset self.previewDay = previewDay self.presentationData = context.sharedContext.currentPresentationData.with { $0 } @@ -1569,7 +1579,7 @@ public final class CalendarMessageScreen: ViewController { strongSelf.selectionState = selectionState strongSelf.updateSelectionState() - } else { + } else if let calendarState = strongSelf.calendarState { outer: for month in strongSelf.months { let firstDayTimestamp = Int32(month.firstDay.timeIntervalSince1970) @@ -1577,7 +1587,15 @@ public final class CalendarMessageScreen: ViewController { let dayTimestamp = firstDayTimestamp + 24 * 60 * 60 * Int32(day) if dayTimestamp == timestamp { if month.mediaByDay[day] != nil { - strongSelf.navigateToDay(timestamp) + var offset = 0 + for key in calendarState.messagesByDay.keys.sorted(by: { $0 > $1 }) { + if key == dayTimestamp { + break + } else if let item = calendarState.messagesByDay[key] { + offset += item.count + } + } + strongSelf.navigateToOffset(offset) } break outer @@ -1645,8 +1663,8 @@ public final class CalendarMessageScreen: ViewController { return } var messageMap: [Message] = [] - for (_, message) in calendarState.messagesByDay { - messageMap.append(message) + for (_, entry) in calendarState.messagesByDay { + messageMap.append(entry.message) } var updatedMedia: [Int: [Int: DayMedia]] = [:] @@ -1694,12 +1712,12 @@ public final class CalendarMessageScreen: ViewController { private let peerId: PeerId private let calendarSource: SparseMessageCalendar private let initialTimestamp: Int32 - private let navigateToDay: (CalendarMessageScreen, Int32) -> Void + private let navigateToDay: (CalendarMessageScreen, Int) -> Void private let previewDay: (MessageIndex, ASDisplayNode, CGRect, ContextGesture) -> Void private var presentationData: PresentationData - public init(context: AccountContext, peerId: PeerId, calendarSource: SparseMessageCalendar, initialTimestamp: Int32, navigateToDay: @escaping (CalendarMessageScreen, Int32) -> Void, previewDay: @escaping (MessageIndex, ASDisplayNode, CGRect, ContextGesture) -> Void) { + public init(context: AccountContext, peerId: PeerId, calendarSource: SparseMessageCalendar, initialTimestamp: Int32, navigateToDay: @escaping (CalendarMessageScreen, Int) -> Void, previewDay: @escaping (MessageIndex, ASDisplayNode, CGRect, ContextGesture) -> Void) { self.context = context self.peerId = peerId self.calendarSource = calendarSource @@ -1741,11 +1759,11 @@ public final class CalendarMessageScreen: ViewController { } override public func loadDisplayNode() { - self.displayNode = Node(controller: self, context: self.context, peerId: self.peerId, calendarSource: self.calendarSource, initialTimestamp: self.initialTimestamp, navigateToDay: { [weak self] timestamp in + self.displayNode = Node(controller: self, context: self.context, peerId: self.peerId, calendarSource: self.calendarSource, initialTimestamp: self.initialTimestamp, navigateToOffset: { [weak self] index in guard let strongSelf = self else { return } - strongSelf.navigateToDay(strongSelf, timestamp) + strongSelf.navigateToDay(strongSelf, index) }, previewDay: self.previewDay) self.displayNodeDidLoad() diff --git a/submodules/SparseItemGrid/Sources/SparseItemGrid.swift b/submodules/SparseItemGrid/Sources/SparseItemGrid.swift index 9933f52eca..f3ca0df511 100644 --- a/submodules/SparseItemGrid/Sources/SparseItemGrid.swift +++ b/submodules/SparseItemGrid/Sources/SparseItemGrid.swift @@ -186,6 +186,10 @@ public final class SparseItemGrid: ASDisplayNode { preconditionFailure() } + open var holeAnchor: HoleAnchor { + preconditionFailure() + } + public init() { } } @@ -971,14 +975,24 @@ public final class SparseItemGrid: ASDisplayNode { let visibleRange = layout.visibleItemRange(for: visibleBounds, count: items.count) for index in visibleRange.minIndex ... visibleRange.maxIndex { if items.item(at: index) == nil { - if let holeAnchor = items.closestHole(to: index) { - let location: HoleLocation - if index < holeAnchor.index { - location = .toLower + //let closestItem = items.closestItem(at: index) + let closestHole = items.closestHole(to: index) + + var closestAnchor: HoleAnchor? + /*if let closestItem = closestItem, let closestHole = closestHole { + if abs(closestItem.index - index) < abs(closestHole.index - index) { + closestAnchor = closestItem.holeAnchor } else { - location = .toUpper + closestAnchor = closestHole } - self.maybeLoadHoleAnchor(holeAnchor, location) + } else if let closestItem = closestItem { + closestAnchor = closestItem.holeAnchor + } else if let closestHole = closestHole {*/ + closestAnchor = closestHole + //} + + if let closestAnchor = closestAnchor { + self.maybeLoadHoleAnchor(closestAnchor, .toLower) } break } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/SparseMessageList.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/SparseMessageList.swift index fafd534caf..ae0191afa3 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/SparseMessageList.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/SparseMessageList.swift @@ -240,6 +240,7 @@ public final class SparseMessageList { } var loadRange: ClosedRange? + var loadCount: Int? centralItemSearch: for i in 0 ..< sparseItems.items.count { switch sparseItems.items[i] { @@ -323,6 +324,7 @@ public final class SparseMessageList { } loadRange = holeRange + loadCount = holeCount break centralItemSearch } @@ -331,7 +333,7 @@ public final class SparseMessageList { } } - guard let range = loadRange else { + guard let range = loadRange, let expectedCount = loadCount else { completion() return } @@ -343,7 +345,7 @@ public final class SparseMessageList { } self.loadingHole = loadingHole - let mappedDirection: MessageHistoryViewRelativeHoleDirection = .range(start: MessageId(peerId: anchor.peerId, namespace: anchor.namespace, id: range.lowerBound - 1), end: MessageId(peerId: anchor.peerId, namespace: anchor.namespace, id: range.upperBound + 1)) + let mappedDirection: MessageHistoryViewRelativeHoleDirection = .range(start: MessageId(peerId: anchor.peerId, namespace: anchor.namespace, id: range.upperBound), end: MessageId(peerId: anchor.peerId, namespace: anchor.namespace, id: range.lowerBound - 1)) let account = self.account self.loadHoleDisposable.set((fetchMessageHistoryHole( @@ -370,6 +372,10 @@ public final class SparseMessageList { return } + if messages.count != expectedCount { + Logger.shared.log("SparseMessageList", "unexpected message count") + } + var lowerIndex: Int? var upperIndex: Int? for i in 0 ..< strongSelf.sparseItems!.items.count { @@ -401,6 +407,15 @@ public final class SparseMessageList { } } + let anchors = strongSelf.sparseItems!.items.compactMap { item -> MessageId? in + if case let .anchor(id, _, _) = item { + return id + } else { + return nil + } + } + assert(anchors.sorted(by: >) == anchors) + strongSelf.updateState() if strongSelf.loadingHole == loadingHole { @@ -594,9 +609,9 @@ public final class SparseMessageList { let topItemCount = items.count var totalCount = items.count - if let minMessageId = minMessageId, let sparseItems = self.sparseItems { + if let sparseItems = self.sparseItems { var sparseIndex = 0 - let _ = minMessageId + for i in 0 ..< sparseItems.items.count { switch sparseItems.items[i] { case let .anchor(id, timestamp, message): @@ -699,7 +714,7 @@ public final class SparseMessageCalendar { struct InternalState { var nextRequestOffset: Int32? var minTimestamp: Int32? - var messagesByDay: [Int32: Message] + var messagesByDay: [Int32: SparseMessageCalendar.Entry] } private let queue: Queue @@ -747,8 +762,8 @@ public final class SparseMessageCalendar { func removeMessagesInRange(minTimestamp: Int32, maxTimestamp: Int32, type: InteractiveHistoryClearingType, completion: @escaping () -> Void) -> Disposable { var removeKeys: [Int32] = [] - for (id, message) in self.state.messagesByDay { - if message.timestamp >= minTimestamp && message.timestamp <= maxTimestamp { + for (id, entry) in self.state.messagesByDay { + if entry.message.timestamp >= minTimestamp && entry.message.timestamp <= maxTimestamp { removeKeys.append(id) } } @@ -771,7 +786,7 @@ public final class SparseMessageCalendar { self.isLoadingMore = true struct LoadResult { - var messagesByDay: [Int32: Message] + var messagesByDay: [Int32: SparseMessageCalendar.Entry] var nextOffset: Int32? var minMessageId: MessageId? var minTimestamp: Int32? @@ -831,12 +846,12 @@ public final class SparseMessageCalendar { let _ = transaction.addMessages(parsedMessages, location: .Random) var minMessageId: Int32? - var messagesByDay: [Int32: Message] = [:] + var messagesByDay: [Int32: SparseMessageCalendar.Entry] = [:] for period in periods { switch period { - case let .searchResultsCalendarPeriod(date, minMsgId, _, _): + case let .searchResultsCalendarPeriod(date, minMsgId, _, count): if let message = transaction.getMessage(MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: minMsgId)) { - messagesByDay[date] = message + messagesByDay[date] = SparseMessageCalendar.Entry(message: message, count: Int(count)) } if let minMessageIdValue = minMessageId { if minMsgId < minMessageIdValue { @@ -863,8 +878,8 @@ public final class SparseMessageCalendar { } strongSelf.state.nextRequestOffset = result.nextOffset - for (timestamp, message) in result.messagesByDay { - strongSelf.state.messagesByDay[timestamp] = message + for (timestamp, entry) in result.messagesByDay { + strongSelf.state.messagesByDay[timestamp] = entry } strongSelf.statePromise.set(.single(strongSelf.state)) @@ -873,8 +888,13 @@ public final class SparseMessageCalendar { } } + public struct Entry { + public var message: Message + public var count: Int + } + public struct State { - public var messagesByDay: [Int32: Message] + public var messagesByDay: [Int32: Entry] public var minTimestamp: Int32? public var hasMore: Bool } diff --git a/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift b/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift index e1c75c77b9..5c68bf81c1 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift @@ -663,6 +663,10 @@ private final class VisualMediaItem: SparseItemGrid.Item { override var tag: Int32 { return self.localMonthTimestamp } + + override var holeAnchor: SparseItemGrid.HoleAnchor { + return VisualMediaHoleAnchor(index: self.index, messageId: self.message.id, localMonthTimestamp: self.localMonthTimestamp) + } init(index: Int, message: Message, localMonthTimestamp: Int32) { self.indexValue = index @@ -1173,12 +1177,16 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding, ListShimme if let result = directMediaImageCache.getImage(message: message, media: selectedMedia, width: imageWidthSpec, possibleWidths: SparseItemGridBindingImpl.widthSpecs.1, synchronous: synchronous == .full) { if let image = result.image { layer.contents = image.cgImage - layer.hasContents = true switch synchronous { case .none: - layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, completion: { [weak self, weak layer, weak displayItem] _ in + layer?.hasContents = true + if let displayItem = displayItem { + self?.updateShimmerLayersImpl?(displayItem) + } + }) default: - break + layer.hasContents = true } } if let loadSignal = result.loadSignal { @@ -1192,15 +1200,13 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding, ListShimme let deltaTime = CFAbsoluteTimeGetCurrent() - startTimestamp let synchronousValue: Bool switch synchronous { - case .none: + case .none, .full: synchronousValue = false case .semi: synchronousValue = deltaTime < 0.1 - case .full: - synchronousValue = true } - if layer.hasContents && !synchronousValue { + if layer.contents != nil && !synchronousValue { let copyLayer = ItemLayer() copyLayer.contents = layer.contents copyLayer.contentsRect = layer.contentsRect @@ -1211,18 +1217,27 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding, ListShimme }) layer.contents = image?.cgImage - layer.hasContents = true - } else { - layer.contents = image?.cgImage - layer.hasContents = true - - if !synchronousValue { - layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) - } + layer.hasContents = true if let displayItem = displayItem { self?.updateShimmerLayersImpl?(displayItem) } + } else { + layer.contents = image?.cgImage + + if !synchronousValue { + layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, completion: { [weak layer] _ in + layer?.hasContents = true + if let displayItem = displayItem { + self?.updateShimmerLayersImpl?(displayItem) + } + }) + } else { + layer.hasContents = true + if let displayItem = displayItem { + self?.updateShimmerLayersImpl?(displayItem) + } + } } }) } @@ -1936,13 +1951,16 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro let timezoneOffset = Int32(TimeZone.current.secondsFromGMT()) var mappedItems: [SparseItemGrid.Item] = [] - var mappeHoles: [SparseItemGrid.HoleAnchor] = [] + var mappedHoles: [SparseItemGrid.HoleAnchor] = [] for item in list.items { switch item.content { - case let .message(message, _): + case let .message(message, isLocal): mappedItems.append(VisualMediaItem(index: item.index, message: message, localMonthTimestamp: Month(localTimestamp: message.timestamp + timezoneOffset).packedValue)) + if !isLocal { + mappedHoles.append(VisualMediaHoleAnchor(index: item.index, messageId: message.id, localMonthTimestamp: Month(localTimestamp: message.timestamp + timezoneOffset).packedValue)) + } case let .placeholder(id, timestamp): - mappeHoles.append(VisualMediaHoleAnchor(index: item.index, messageId: id, localMonthTimestamp: Month(localTimestamp: timestamp + timezoneOffset).packedValue)) + mappedHoles.append(VisualMediaHoleAnchor(index: item.index, messageId: id, localMonthTimestamp: Month(localTimestamp: timestamp + timezoneOffset).packedValue)) } } @@ -1953,7 +1971,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro let items = SparseItemGrid.Items( items: mappedItems, - holeAnchors: mappeHoles, + holeAnchors: mappedHoles, count: list.totalCount, itemBinding: strongSelf.itemGridBinding ) @@ -2233,6 +2251,13 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro } } } + + func scrollToItem(index: Int) { + guard let _ = self.items else { + return + } + self.itemGrid.scrollToItem(at: index) + } override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { guard let result = super.hitTest(point, with: event) else { diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index c73f0fc131..46920d84b6 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -6243,7 +6243,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate var dismissCalendarScreen: (() -> Void)? - let calendarScreen = CalendarMessageScreen(context: self.context, peerId: self.peerId, calendarSource: calendarSource, initialTimestamp: initialTimestamp, navigateToDay: { [weak self] c, timestamp in + let calendarScreen = CalendarMessageScreen(context: self.context, peerId: self.peerId, calendarSource: calendarSource, initialTimestamp: initialTimestamp, navigateToDay: { [weak self] c, index in guard let strongSelf = self else { c.dismiss() return @@ -6253,7 +6253,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate return } - pane.scrollToTimestamp(timestamp: timestamp) + pane.scrollToItem(index: index) c.dismiss() }, previewDay: { [weak self] index, sourceNode, sourceRect, gesture in