mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 22:55:00 +00:00
Shared media improvements
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -240,6 +240,7 @@ public final class SparseMessageList {
|
||||
}
|
||||
|
||||
var loadRange: ClosedRange<Int32>?
|
||||
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
|
||||
}
|
||||
|
||||
@@ -664,6 +664,10 @@ private final class VisualMediaItem: SparseItemGrid.Item {
|
||||
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
|
||||
self.message = message
|
||||
@@ -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
|
||||
)
|
||||
@@ -2234,6 +2252,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 {
|
||||
return nil
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user