mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
174 lines
7.3 KiB
Swift
174 lines
7.3 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import TelegramCore
|
|
import SwiftSignalKit
|
|
import Display
|
|
import MergeLists
|
|
import ItemListUI
|
|
import AccountContext
|
|
|
|
struct CallListNodeView {
|
|
let originalView: EngineCallList
|
|
let filteredEntries: [CallListNodeEntry]
|
|
let presentationData: ItemListPresentationData
|
|
}
|
|
|
|
enum CallListNodeViewTransitionReason {
|
|
case initial
|
|
case interactiveChanges
|
|
case reload
|
|
case reloadAnimated
|
|
}
|
|
|
|
struct CallListNodeViewTransitionInsertEntry {
|
|
let index: Int
|
|
let previousIndex: Int?
|
|
let entry: CallListNodeEntry
|
|
let directionHint: ListViewItemOperationDirectionHint?
|
|
}
|
|
|
|
struct CallListNodeViewTransitionUpdateEntry {
|
|
let index: Int
|
|
let previousIndex: Int
|
|
let entry: CallListNodeEntry
|
|
let directionHint: ListViewItemOperationDirectionHint?
|
|
}
|
|
|
|
struct CallListNodeViewTransition {
|
|
let callListView: CallListNodeView
|
|
let deleteItems: [ListViewDeleteItem]
|
|
let insertEntries: [CallListNodeViewTransitionInsertEntry]
|
|
let updateEntries: [CallListNodeViewTransitionUpdateEntry]
|
|
let options: ListViewDeleteAndInsertOptions
|
|
let scrollToItem: ListViewScrollToItem?
|
|
let stationaryItemRange: (Int, Int)?
|
|
}
|
|
|
|
enum CallListNodeViewScrollPosition {
|
|
case top(animated: Bool)
|
|
case index(index: EngineMessage.Index, position: ListViewScrollPosition, directionHint: ListViewScrollToItemDirectionHint, animated: Bool)
|
|
}
|
|
|
|
func preparedCallListNodeViewTransition(from fromView: CallListNodeView?, to toView: CallListNodeView, reason: CallListNodeViewTransitionReason, disableAnimations: Bool, context: AccountContext, scrollPosition: CallListNodeViewScrollPosition?) -> Signal<CallListNodeViewTransition, NoError> {
|
|
return Signal { subscriber in
|
|
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromView?.filteredEntries ?? [], rightList: toView.filteredEntries, allUpdated: fromView?.presentationData != toView.presentationData)
|
|
|
|
var adjustedDeleteIndices: [ListViewDeleteItem] = []
|
|
let previousCount: Int
|
|
if let fromView = fromView {
|
|
previousCount = fromView.filteredEntries.count
|
|
} else {
|
|
previousCount = 0;
|
|
}
|
|
for index in deleteIndices {
|
|
adjustedDeleteIndices.append(ListViewDeleteItem(index: previousCount - 1 - index, directionHint: nil))
|
|
}
|
|
var adjustedIndicesAndItems: [CallListNodeViewTransitionInsertEntry] = []
|
|
var adjustedUpdateItems: [CallListNodeViewTransitionUpdateEntry] = []
|
|
let updatedCount = toView.filteredEntries.count
|
|
|
|
var options: ListViewDeleteAndInsertOptions = []
|
|
var maxAnimatedInsertionIndex = -1
|
|
let stationaryItemRange: (Int, Int)? = nil
|
|
var scrollToItem: ListViewScrollToItem? = nil
|
|
|
|
var wasEmpty = false
|
|
if let fromView = fromView, fromView.originalView.items.isEmpty {
|
|
wasEmpty = true
|
|
}
|
|
|
|
switch reason {
|
|
case .initial:
|
|
let _ = options.insert(.LowLatency)
|
|
let _ = options.insert(.Synchronous)
|
|
let _ = options.insert(.PreferSynchronousResourceLoading)
|
|
case .interactiveChanges:
|
|
if wasEmpty {
|
|
let _ = options.insert(.Synchronous)
|
|
let _ = options.insert(.PreferSynchronousResourceLoading)
|
|
} else {
|
|
let _ = options.insert(.AnimateAlpha)
|
|
if !disableAnimations {
|
|
let _ = options.insert(.AnimateInsertion)
|
|
}
|
|
|
|
for (index, _, _) in indicesAndItems.sorted(by: { $0.0 > $1.0 }) {
|
|
let adjustedIndex = updatedCount - 1 - index
|
|
if adjustedIndex == maxAnimatedInsertionIndex + 1 {
|
|
maxAnimatedInsertionIndex += 1
|
|
}
|
|
}
|
|
}
|
|
case .reload:
|
|
break
|
|
case .reloadAnimated:
|
|
let _ = options.insert(.LowLatency)
|
|
let _ = options.insert(.Synchronous)
|
|
let _ = options.insert(.AnimateCrossfade)
|
|
let _ = options.insert(.PreferSynchronousResourceLoading)
|
|
}
|
|
|
|
for (index, entry, previousIndex) in indicesAndItems {
|
|
let adjustedIndex = updatedCount - 1 - index
|
|
|
|
let adjustedPrevousIndex: Int?
|
|
if let previousIndex = previousIndex {
|
|
adjustedPrevousIndex = previousCount - 1 - previousIndex
|
|
} else {
|
|
adjustedPrevousIndex = nil
|
|
}
|
|
|
|
var directionHint: ListViewItemOperationDirectionHint?
|
|
if maxAnimatedInsertionIndex >= 0 && adjustedIndex <= maxAnimatedInsertionIndex {
|
|
directionHint = .Down
|
|
}
|
|
|
|
adjustedIndicesAndItems.append(CallListNodeViewTransitionInsertEntry(index: adjustedIndex, previousIndex: adjustedPrevousIndex, entry: entry, directionHint: directionHint))
|
|
}
|
|
|
|
for (index, entry, previousIndex) in updateIndices {
|
|
let adjustedIndex = updatedCount - 1 - index
|
|
let adjustedPreviousIndex = previousCount - 1 - previousIndex
|
|
|
|
let directionHint: ListViewItemOperationDirectionHint? = nil
|
|
adjustedUpdateItems.append(CallListNodeViewTransitionUpdateEntry(index: adjustedIndex, previousIndex: adjustedPreviousIndex, entry: entry, directionHint: directionHint))
|
|
}
|
|
|
|
if let scrollPosition = scrollPosition {
|
|
switch scrollPosition {
|
|
case let .top(animated):
|
|
scrollToItem = ListViewScrollToItem(index: 0, position: .top(0.0), animated: animated, curve: .Default(duration: nil), directionHint: .Up)
|
|
case let .index(scrollIndex, position, directionHint, animated):
|
|
var index = toView.filteredEntries.count - 1
|
|
for entry in toView.filteredEntries {
|
|
if case let .message(messageIndex) = entry.sortIndex {
|
|
if messageIndex >= scrollIndex {
|
|
scrollToItem = ListViewScrollToItem(index: index, position: position, animated: animated, curve: .Default(duration: nil), directionHint: directionHint)
|
|
break
|
|
}
|
|
}
|
|
index -= 1
|
|
}
|
|
|
|
if scrollToItem == nil {
|
|
var index = 0
|
|
for entry in toView.filteredEntries.reversed() {
|
|
if case let .message(messageIndex) = entry.sortIndex {
|
|
if messageIndex < scrollIndex {
|
|
scrollToItem = ListViewScrollToItem(index: index, position: position, animated: animated, curve: .Default(duration: nil), directionHint: directionHint)
|
|
break
|
|
}
|
|
}
|
|
index += 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
subscriber.putNext(CallListNodeViewTransition(callListView: toView, deleteItems: adjustedDeleteIndices, insertEntries: adjustedIndicesAndItems, updateEntries: adjustedUpdateItems, options: options, scrollToItem: scrollToItem, stationaryItemRange: stationaryItemRange))
|
|
subscriber.putCompletion()
|
|
|
|
return EmptyDisposable
|
|
}
|
|
}
|