mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 14:20:20 +00:00
no message
This commit is contained in:
@@ -82,6 +82,7 @@
|
||||
D0E7A1BF1D8C24B900C37A6F /* ChatHistoryViewForLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E7A1BE1D8C24B900C37A6F /* ChatHistoryViewForLocation.swift */; };
|
||||
D0E7A1C11D8C258D00C37A6F /* ChatHistoryEntriesForView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E7A1C01D8C258D00C37A6F /* ChatHistoryEntriesForView.swift */; };
|
||||
D0E7A1C31D8C25D600C37A6F /* PreparedChatHistoryViewTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E7A1C21D8C25D600C37A6F /* PreparedChatHistoryViewTransition.swift */; };
|
||||
D0ED5D4B1DC806D7007CBB15 /* ApplicationSpecificData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED5D4A1DC806D7007CBB15 /* ApplicationSpecificData.swift */; };
|
||||
D0EE971A1D88BCA0006C18E1 /* ChatInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EE97191D88BCA0006C18E1 /* ChatInfo.swift */; };
|
||||
D0F69D231D6B87D30046BCD6 /* FFMpegMediaFrameSourceContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F69CD31D6B87D30046BCD6 /* FFMpegMediaFrameSourceContext.swift */; };
|
||||
D0F69D241D6B87D30046BCD6 /* MediaPlayerAudioRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F69CD41D6B87D30046BCD6 /* MediaPlayerAudioRenderer.swift */; };
|
||||
@@ -304,6 +305,7 @@
|
||||
D0E7A1BE1D8C24B900C37A6F /* ChatHistoryViewForLocation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatHistoryViewForLocation.swift; sourceTree = "<group>"; };
|
||||
D0E7A1C01D8C258D00C37A6F /* ChatHistoryEntriesForView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatHistoryEntriesForView.swift; sourceTree = "<group>"; };
|
||||
D0E7A1C21D8C25D600C37A6F /* PreparedChatHistoryViewTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreparedChatHistoryViewTransition.swift; sourceTree = "<group>"; };
|
||||
D0ED5D4A1DC806D7007CBB15 /* ApplicationSpecificData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplicationSpecificData.swift; sourceTree = "<group>"; };
|
||||
D0EE97191D88BCA0006C18E1 /* ChatInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatInfo.swift; sourceTree = "<group>"; };
|
||||
D0F69CD31D6B87D30046BCD6 /* FFMpegMediaFrameSourceContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FFMpegMediaFrameSourceContext.swift; sourceTree = "<group>"; };
|
||||
D0F69CD41D6B87D30046BCD6 /* MediaPlayerAudioRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaPlayerAudioRenderer.swift; sourceTree = "<group>"; };
|
||||
@@ -1061,6 +1063,7 @@
|
||||
D0F69E931D6B8C9B0046BCD6 /* ProgressiveImage.swift */,
|
||||
D0F69E941D6B8C9B0046BCD6 /* WebP.swift */,
|
||||
D0B844571DAC44E8005F29E1 /* PeerPresenceStatusManager.swift */,
|
||||
D0ED5D4A1DC806D7007CBB15 /* ApplicationSpecificData.swift */,
|
||||
);
|
||||
name = Utils;
|
||||
sourceTree = "<group>";
|
||||
@@ -1344,6 +1347,7 @@
|
||||
D0F69D771D6B87DF0046BCD6 /* FFMpegMediaPassthroughVideoFrameDecoder.swift in Sources */,
|
||||
D0F69DFE1D6B8A880046BCD6 /* AvatarNode.swift in Sources */,
|
||||
D0F69E9B1D6B8D200046BCD6 /* UIImage+WebP.m in Sources */,
|
||||
D0ED5D4B1DC806D7007CBB15 /* ApplicationSpecificData.swift in Sources */,
|
||||
D0F69E581D6B8BDA0046BCD6 /* GalleryItemNode.swift in Sources */,
|
||||
D0F69E971D6B8C9B0046BCD6 /* WebP.swift in Sources */,
|
||||
D0F69E2F1D6B8B030046BCD6 /* ChatMessageBubbleContentCalclulateImageCorners.swift in Sources */,
|
||||
|
||||
6
TelegramUI/ApplicationSpecificData.swift
Normal file
6
TelegramUI/ApplicationSpecificData.swift
Normal file
@@ -0,0 +1,6 @@
|
||||
import Foundation
|
||||
import SwiftSignalKit
|
||||
|
||||
final class ApplicationSpecificData {
|
||||
let sharedChatMediaInputNode = Atomic<ChatMediaInputNode?>(value: nil)
|
||||
}
|
||||
@@ -163,6 +163,7 @@ public class ChatController: ViewController {
|
||||
}
|
||||
}, sendSticker: { [weak self] file in
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({})
|
||||
enqueueMessage(account: strongSelf.account, peerId: strongSelf.peerId, text: "", replyMessageId: nil, media: file).start()
|
||||
}
|
||||
})
|
||||
@@ -258,6 +259,7 @@ public class ChatController: ViewController {
|
||||
let _ = options.insert(.Synchronous)
|
||||
let _ = options.insert(.LowLatency)
|
||||
options.remove(.AnimateInsertion)
|
||||
options.insert(.RequestItemInsertionAnimations)
|
||||
|
||||
let deleteItems = transition.deleteItems.map({ item in
|
||||
return ListViewDeleteItem(index: item.index, directionHint: nil)
|
||||
@@ -306,6 +308,7 @@ public class ChatController: ViewController {
|
||||
let scaledSize = size.aspectFitted(CGSize(width: 1280.0, height: 1280.0))
|
||||
let resource = PhotoLibraryMediaResource(localIdentifier: asset.localIdentifier)
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: randomId), representations: [TelegramMediaImageRepresentation(dimensions: scaledSize, resource: resource)])
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({})
|
||||
enqueueMessage(account: strongSelf.account, peerId: strongSelf.peerId, text: "", replyMessageId: nil, media: media).start()
|
||||
}
|
||||
}
|
||||
@@ -380,7 +383,7 @@ public class ChatController: ViewController {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
self.chatDisplayNode.historyNode.preloadPages = true
|
||||
self.chatDisplayNode.historyNode.canReadHistory.set(.single(true))
|
||||
self.chatDisplayNode.historyNode.canReadHistory.set(true)
|
||||
|
||||
self.chatDisplayNode.loadInputPanels()
|
||||
}
|
||||
|
||||
@@ -506,10 +506,11 @@ class ChatControllerNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
func loadInputPanels() {
|
||||
/*if self.inputMediaNode == nil {
|
||||
if self.inputMediaNode == nil {
|
||||
let inputNode = ChatMediaInputNode(account: self.account, controllerInteraction: self.controllerInteraction)
|
||||
inputNode.interfaceInteraction = interfaceInteraction
|
||||
self.inputMediaNode = inputNode
|
||||
}*/
|
||||
inputNode.updateLayout(width: self.bounds.size.width, transition: .immediate, interfaceState: self.chatPresentationInterfaceState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,25 @@ private func mappedChatHistoryViewListTransition(account: Account, peerId: PeerI
|
||||
case .Bottom:
|
||||
mappedPosition = .bottom
|
||||
}
|
||||
mappedScrollToItem = GridNodeScrollToItem(index: scrollToItem.index, position: mappedPosition)
|
||||
let scrollTransition: ContainedViewLayoutTransition
|
||||
if scrollToItem.animated {
|
||||
switch scrollToItem.curve {
|
||||
case .Default:
|
||||
scrollTransition = .animated(duration: 0.3, curve: .easeInOut)
|
||||
case let .Spring(duration):
|
||||
scrollTransition = .animated(duration: duration, curve: .spring)
|
||||
}
|
||||
} else {
|
||||
scrollTransition = .immediate
|
||||
}
|
||||
let directionHint: GridNodePreviousItemsTransitionDirectionHint
|
||||
switch scrollToItem.directionHint {
|
||||
case .Up:
|
||||
directionHint = .up
|
||||
case .Down:
|
||||
directionHint = .down
|
||||
}
|
||||
mappedScrollToItem = GridNodeScrollToItem(index: scrollToItem.index, position: mappedPosition, transition: scrollTransition, directionHint: directionHint, adjustForSection: true)
|
||||
}
|
||||
|
||||
return ChatHistoryGridViewTransition(historyView: transition.historyView, deleteItems: transition.deleteItems.map { $0.index }, insertItems: mappedInsertEntries(account: account, peerId: peerId, controllerInteraction: controllerInteraction, entries: transition.insertEntries), updateItems: mappedUpdateEntries(account: account, peerId: peerId, controllerInteraction: controllerInteraction, entries: transition.updateEntries), scrollToItem: mappedScrollToItem, stationaryItemRange: transition.stationaryItemRange)
|
||||
|
||||
@@ -124,6 +124,14 @@ private func mappedChatHistoryViewListTransition(account: Account, peerId: PeerI
|
||||
return ChatHistoryListViewTransition(historyView: transition.historyView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(account: account, peerId: peerId, controllerInteraction: controllerInteraction, mode: mode, entries: transition.insertEntries), updateItems: mappedUpdateEntries(account: account, peerId: peerId, controllerInteraction: controllerInteraction, mode: mode, entries: transition.updateEntries), options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange)
|
||||
}
|
||||
|
||||
private final class ChatHistoryTransactionOpaqueState {
|
||||
let historyView: ChatHistoryView
|
||||
|
||||
init(historyView: ChatHistoryView) {
|
||||
self.historyView = historyView
|
||||
}
|
||||
}
|
||||
|
||||
public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
private let account: Account
|
||||
private let peerId: PeerId
|
||||
@@ -145,10 +153,10 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
public let historyReady = Promise<Bool>()
|
||||
private var didSetHistoryReady = false
|
||||
|
||||
private let maxVisibleIncomingMessageId = Promise<MessageId>()
|
||||
let canReadHistory = Promise<Bool>()
|
||||
private let maxVisibleIncomingMessageId = ValuePromise<MessageId>()
|
||||
let canReadHistory = ValuePromise<Bool>()
|
||||
|
||||
private let _chatHistoryLocation = Promise<ChatHistoryLocation>()
|
||||
private let _chatHistoryLocation = ValuePromise<ChatHistoryLocation>()
|
||||
private var chatHistoryLocation: Signal<ChatHistoryLocation, NoError> {
|
||||
return self._chatHistoryLocation.get()
|
||||
}
|
||||
@@ -164,6 +172,8 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
|
||||
super.init()
|
||||
|
||||
//self.debugInfo = true
|
||||
|
||||
self.preloadPages = false
|
||||
switch self.mode {
|
||||
case .bubbles:
|
||||
@@ -263,34 +273,28 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
self.readHistoryDisposable.set(readHistory.start())
|
||||
|
||||
if let messageId = messageId {
|
||||
self._chatHistoryLocation.set(.single(ChatHistoryLocation.InitialSearch(messageId: messageId, count: 60)))
|
||||
self._chatHistoryLocation.set(ChatHistoryLocation.InitialSearch(messageId: messageId, count: 60))
|
||||
} else {
|
||||
self._chatHistoryLocation.set(.single(ChatHistoryLocation.Initial(count: 60)))
|
||||
self._chatHistoryLocation.set(ChatHistoryLocation.Initial(count: 60))
|
||||
}
|
||||
|
||||
self.displayedItemRangeChanged = { [weak self] displayedRange in
|
||||
self.displayedItemRangeChanged = { [weak self] displayedRange, opaqueTransactionState in
|
||||
if let strongSelf = self {
|
||||
/*if let transactionTag = strongSelf.listViewTransactionTag {
|
||||
strongSelf.messageViewQueue.dispatch {
|
||||
if transactionTag == strongSelf.historyViewTransactionTag {
|
||||
if let range = range, historyView = strongSelf.historyView, firstEntry = historyView.filteredEntries.first, lastEntry = historyView.filteredEntries.last {
|
||||
if range.firstIndex < 5 && historyView.originalView.laterId != nil {
|
||||
strongSelf._chatHistoryLocation.set(.single(ChatHistoryLocation.Navigation(index: lastEntry.index, anchorIndex: historyView.originalView.anchorIndex)))
|
||||
} else if range.lastIndex >= historyView.filteredEntries.count - 5 && historyView.originalView.earlierId != nil {
|
||||
strongSelf._chatHistoryLocation.set(.single(ChatHistoryLocation.Navigation(index: firstEntry.index, anchorIndex: historyView.originalView.anchorIndex)))
|
||||
} else {
|
||||
//strongSelf.account.postbox.updateMessageHistoryViewVisibleRange(messageView.id, earliestVisibleIndex: viewEntries[viewEntries.count - 1 - range.lastIndex].index, latestVisibleIndex: viewEntries[viewEntries.count - 1 - range.firstIndex].index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
if let visible = displayedRange.visibleRange, let historyView = strongSelf.historyView {
|
||||
if let historyView = (opaqueTransactionState as? ChatHistoryTransactionOpaqueState)?.historyView {
|
||||
if let visible = displayedRange.visibleRange {
|
||||
if let messageId = maxIncomingMessageIdForEntries(historyView.filteredEntries, indexRange: (historyView.filteredEntries.count - 1 - visible.lastIndex, historyView.filteredEntries.count - 1 - visible.firstIndex)) {
|
||||
strongSelf.updateMaxVisibleReadIncomingMessageId(messageId)
|
||||
}
|
||||
}
|
||||
|
||||
if let loaded = displayedRange.loadedRange, let firstEntry = historyView.filteredEntries.first, let lastEntry = historyView.filteredEntries.last {
|
||||
if loaded.firstIndex < 5 && historyView.originalView.laterId != nil {
|
||||
strongSelf._chatHistoryLocation.set(ChatHistoryLocation.Navigation(index: lastEntry.index, anchorIndex: historyView.originalView.anchorIndex))
|
||||
} else if loaded.lastIndex >= historyView.filteredEntries.count - 5 && historyView.originalView.earlierId != nil {
|
||||
strongSelf._chatHistoryLocation.set(ChatHistoryLocation.Navigation(index: firstEntry.index, anchorIndex: historyView.originalView.anchorIndex))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -301,15 +305,15 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
}
|
||||
|
||||
public func scrollToStartOfHistory() {
|
||||
self._chatHistoryLocation.set(.single(ChatHistoryLocation.Scroll(index: MessageIndex.lowerBound(peerId: self.peerId), anchorIndex: MessageIndex.lowerBound(peerId: self.peerId), sourceIndex: MessageIndex.upperBound(peerId: self.peerId), scrollPosition: .Bottom, animated: true)))
|
||||
self._chatHistoryLocation.set(ChatHistoryLocation.Scroll(index: MessageIndex.lowerBound(peerId: self.peerId), anchorIndex: MessageIndex.lowerBound(peerId: self.peerId), sourceIndex: MessageIndex.upperBound(peerId: self.peerId), scrollPosition: .Bottom, animated: true))
|
||||
}
|
||||
|
||||
public func scrollToEndOfHistory() {
|
||||
self._chatHistoryLocation.set(.single(ChatHistoryLocation.Scroll(index: MessageIndex.upperBound(peerId: self.peerId), anchorIndex: MessageIndex.upperBound(peerId: self.peerId), sourceIndex: MessageIndex.lowerBound(peerId: self.peerId), scrollPosition: .Top, animated: true)))
|
||||
self._chatHistoryLocation.set(ChatHistoryLocation.Scroll(index: MessageIndex.upperBound(peerId: self.peerId), anchorIndex: MessageIndex.upperBound(peerId: self.peerId), sourceIndex: MessageIndex.lowerBound(peerId: self.peerId), scrollPosition: .Top, animated: true))
|
||||
}
|
||||
|
||||
public func scrollToMessage(from fromIndex: MessageIndex, to toIndex: MessageIndex) {
|
||||
self._chatHistoryLocation.set(.single(ChatHistoryLocation.Scroll(index: toIndex, anchorIndex: toIndex, sourceIndex: fromIndex, scrollPosition: .Center(.Bottom), animated: true)))
|
||||
self._chatHistoryLocation.set(ChatHistoryLocation.Scroll(index: toIndex, anchorIndex: toIndex, sourceIndex: fromIndex, scrollPosition: .Center(.Bottom), animated: true))
|
||||
}
|
||||
|
||||
public func messageInCurrentHistoryView(_ id: MessageId) -> Message? {
|
||||
@@ -323,7 +327,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
}
|
||||
|
||||
private func updateMaxVisibleReadIncomingMessageId(_ id: MessageId) {
|
||||
self.maxVisibleIncomingMessageId.set(.single(id))
|
||||
self.maxVisibleIncomingMessageId.set(id)
|
||||
}
|
||||
|
||||
private func enqueueHistoryViewTransition(_ transition: ChatHistoryListViewTransition) -> Signal<Void, NoError> {
|
||||
@@ -384,15 +388,15 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
self.layoutActionOnViewTransition = nil
|
||||
let (mappedTransition, updateSizeAndInsets) = layoutActionOnViewTransition(transition)
|
||||
|
||||
self.deleteAndInsertItems(deleteIndices: mappedTransition.deleteItems, insertIndicesAndItems: transition.insertItems, updateIndicesAndItems: transition.updateItems, options: mappedTransition.options, scrollToItem: mappedTransition.scrollToItem, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: mappedTransition.stationaryItemRange, completion: completion)
|
||||
self.transaction(deleteIndices: mappedTransition.deleteItems, insertIndicesAndItems: transition.insertItems, updateIndicesAndItems: transition.updateItems, options: mappedTransition.options, scrollToItem: mappedTransition.scrollToItem, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: mappedTransition.stationaryItemRange, updateOpaqueState: ChatHistoryTransactionOpaqueState(historyView: transition.historyView), completion: completion)
|
||||
} else {
|
||||
self.deleteAndInsertItems(deleteIndices: transition.deleteItems, insertIndicesAndItems: transition.insertItems, updateIndicesAndItems: transition.updateItems, options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, completion: completion)
|
||||
self.transaction(deleteIndices: transition.deleteItems, insertIndicesAndItems: transition.insertItems, updateIndicesAndItems: transition.updateItems, options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, updateOpaqueState: ChatHistoryTransactionOpaqueState(historyView: transition.historyView), completion: completion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func updateLayout(transition: ContainedViewLayoutTransition, updateSizeAndInsets: ListViewUpdateSizeAndInsets) {
|
||||
self.deleteAndInsertItems(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, completion: { _ in })
|
||||
self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
|
||||
if !self.dequeuedInitialTransitionOnLayout {
|
||||
self.dequeuedInitialTransitionOnLayout = true
|
||||
|
||||
@@ -85,7 +85,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
fileprivate func setImage(account: Account, image: TelegramMediaImage) {
|
||||
if self.accountAndMedia == nil || !self.accountAndMedia!.1.isEqual(image) {
|
||||
if let largestSize = largestRepresentationForPhoto(image) {
|
||||
let displaySize = largestSize.dimensions.dividedByScreenScale()
|
||||
let displaySize = largestSize.dimensions.fitted(CGSize(width: 1280.0, height: 1280.0)).dividedByScreenScale().integralFloor
|
||||
self.imageNode.alphaTransitionOnFirstUpdate = false
|
||||
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets()))()
|
||||
self.imageNode.setSignal(account: account, signal: chatMessagePhoto(account: account, photo: image), dispatchOnDisplayLink: false)
|
||||
|
||||
@@ -173,6 +173,14 @@ extension ChatListEntry: Identifiable {
|
||||
}
|
||||
}
|
||||
|
||||
private final class ChatListOpaqueTransactionState {
|
||||
let chatListViewAndEntries: (ChatListView, [ChatListControllerEntry])
|
||||
|
||||
init(chatListViewAndEntries: (ChatListView, [ChatListControllerEntry])) {
|
||||
self.chatListViewAndEntries = chatListViewAndEntries
|
||||
}
|
||||
}
|
||||
|
||||
public class ChatListController: ViewController {
|
||||
let account: Account
|
||||
|
||||
@@ -209,7 +217,7 @@ public class ChatListController: ViewController {
|
||||
self.scrollToTop = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if let (view, _) = strongSelf.chatListViewAndEntries, view.laterIndex == nil {
|
||||
strongSelf.chatListDisplayNode.listView.deleteAndInsertItems(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: ListViewScrollToItem(index: 0, position: .Top, animated: true, curve: .Default, directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, completion: { _ in })
|
||||
strongSelf.chatListDisplayNode.listView.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: ListViewScrollToItem(index: 0, position: .Top, animated: true, curve: .Default, directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
} else {
|
||||
strongSelf.setMessageViewPosition(.Around(index: MessageIndex.absoluteUpperBound(), anchorIndex: MessageIndex.absoluteUpperBound(), scrollPosition: .Top), hint: "later", force: true)
|
||||
}
|
||||
@@ -231,9 +239,9 @@ public class ChatListController: ViewController {
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = ChatListControllerNode(account: self.account)
|
||||
|
||||
self.chatListDisplayNode.listView.displayedItemRangeChanged = { [weak self] range in
|
||||
self.chatListDisplayNode.listView.displayedItemRangeChanged = { [weak self] range, transactionOpaqueState in
|
||||
if let strongSelf = self, !strongSelf.settingView {
|
||||
if let range = range.loadedRange, let (view, _) = strongSelf.chatListViewAndEntries {
|
||||
if let range = range.loadedRange, let (view, _) = (transactionOpaqueState as? ChatListOpaqueTransactionState)?.chatListViewAndEntries {
|
||||
if range.firstIndex < 5 && view.laterIndex != nil {
|
||||
strongSelf.setMessageViewPosition(.Around(index: view.entries[view.entries.count - 1].index, anchorIndex: MessageIndex.absoluteUpperBound(), scrollPosition: nil), hint: "later", force: false)
|
||||
} else if range.firstIndex >= 5 && range.lastIndex >= view.entries.count - 5 && view.earlierIndex != nil {
|
||||
@@ -477,7 +485,7 @@ public class ChatListController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.chatListDisplayNode.listView.deleteAndInsertItems(deleteIndices: adjustedDeleteIndices, insertIndicesAndItems: adjustedIndicesAndItems, updateIndicesAndItems: adjustedUpdateItems, options: options, scrollToItem: scrollToItem, completion: { [weak self] _ in
|
||||
strongSelf.chatListDisplayNode.listView.transaction(deleteIndices: adjustedDeleteIndices, insertIndicesAndItems: adjustedIndicesAndItems, updateIndicesAndItems: adjustedUpdateItems, options: options, scrollToItem: scrollToItem, updateOpaqueState: ChatListOpaqueTransactionState(chatListViewAndEntries: (view, viewEntries)), completion: { [weak self] _ in
|
||||
if let strongSelf = self {
|
||||
strongSelf.ready.set(single(true, NoError.self))
|
||||
strongSelf.settingView = false
|
||||
|
||||
@@ -63,7 +63,7 @@ class ChatListControllerNode: ASDisplayNode {
|
||||
|
||||
let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: layout.size, insets: insets, duration: duration, curve: listViewCurve)
|
||||
|
||||
self.listView.deleteAndInsertItems(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, completion: { _ in })
|
||||
self.listView.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
|
||||
if let searchDisplayController = self.searchDisplayController {
|
||||
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
||||
|
||||
@@ -68,7 +68,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.listNode.deleteAndInsertItems(deleteIndices: (0 ..< previousItems.count).map({ ListViewDeleteItem(index: $0, directionHint: nil) }), insertIndicesAndItems: (0 ..< listItems.count).map({ ListViewInsertItem(index: $0, previousIndex: nil, item: listItems[$0], directionHint: .Down) }), updateIndicesAndItems: [], options: [])
|
||||
strongSelf.listNode.transaction(deleteIndices: (0 ..< previousItems.count).map({ ListViewDeleteItem(index: $0, directionHint: nil) }), insertIndicesAndItems: (0 ..< listItems.count).map({ ListViewInsertItem(index: $0, previousIndex: nil, item: listItems[$0], directionHint: .Down) }), updateIndicesAndItems: [], options: [], updateOpaqueState: nil)
|
||||
}
|
||||
}))
|
||||
}
|
||||
@@ -120,6 +120,6 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
}
|
||||
|
||||
self.listNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
self.listNode.deleteAndInsertItems(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: UIEdgeInsets(top: navigationBarHeight, left: 0.0, bottom: layout.insets(options: [.input]).bottom, right: 0.0), duration: duration, curve: listViewCurve), stationaryItemRange: nil, completion: { _ in })
|
||||
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: UIEdgeInsets(top: navigationBarHeight, left: 0.0, bottom: layout.insets(options: [.input]).bottom, right: 0.0), duration: duration, curve: listViewCurve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ final class ChatListSearchRecentPeersNode: ASDisplayNode {
|
||||
for peer in peers {
|
||||
items.append(HorizontalPeerItem(account: account, peer: peer, action: peerSelected))
|
||||
}
|
||||
strongSelf.listView.deleteAndInsertItems(deleteIndices: [], insertIndicesAndItems: (0 ..< items.count).map({ ListViewInsertItem(index: $0, previousIndex: nil, item: items[$0], directionHint: .Down) }), updateIndicesAndItems: [], options: [])
|
||||
strongSelf.listView.transaction(deleteIndices: [], insertIndicesAndItems: (0 ..< items.count).map({ ListViewInsertItem(index: $0, previousIndex: nil, item: items[$0], directionHint: .Down) }), updateIndicesAndItems: [], options: [], updateOpaqueState: nil)
|
||||
}
|
||||
}))
|
||||
}
|
||||
@@ -52,6 +52,6 @@ final class ChatListSearchRecentPeersNode: ASDisplayNode {
|
||||
|
||||
self.listView.bounds = CGRect(x: 0.0, y: 0.0, width: 92.0, height: bounds.size.width)
|
||||
self.listView.position = CGPoint(x: bounds.size.width / 2.0, y: 92.0 / 2.0 + 29.0)
|
||||
self.listView.deleteAndInsertItems(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: CGSize(width: 92.0, height: bounds.size.width), insets: UIEdgeInsets(), duration: 0.0, curve: .Default), stationaryItemRange: nil, completion: { _ in })
|
||||
self.listView.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: CGSize(width: 92.0, height: bounds.size.width), insets: UIEdgeInsets(), duration: 0.0, curve: .Default), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ private final class ChatMediaActionSheetRollItemNode: ActionSheetItemNode, PHPho
|
||||
}
|
||||
|
||||
if !items.isEmpty {
|
||||
self.listView.deleteAndInsertItems(deleteIndices: [], insertIndicesAndItems: (0 ..< items.count).map({ ListViewInsertItem(index: $0, previousIndex: nil, item: items[$0], directionHint: .Down) }), updateIndicesAndItems: [], options: [])
|
||||
self.listView.transaction(deleteIndices: [], insertIndicesAndItems: (0 ..< items.count).map({ ListViewInsertItem(index: $0, previousIndex: nil, item: items[$0], directionHint: .Down) }), updateIndicesAndItems: [], options: [], updateOpaqueState: nil)
|
||||
}
|
||||
|
||||
//PHPhotoLibrary.shared().register(self)
|
||||
|
||||
@@ -17,6 +17,7 @@ private struct ChatMediaInputGridTransition {
|
||||
let updates: [GridNodeUpdateItem]
|
||||
let updateFirstIndexInSectionOffset: Int?
|
||||
let stationaryItems: GridNodeStationaryItems
|
||||
let scrollToItem: GridNodeScrollToItem?
|
||||
}
|
||||
|
||||
private func preparedChatMediaInputPanelEntryTransition(account: Account, from fromEntries: [ChatMediaInputPanelEntry], to toEntries: [ChatMediaInputPanelEntry], inputNodeInteraction: ChatMediaInputNodeInteraction) -> ChatMediaInputPanelTransition {
|
||||
@@ -31,6 +32,7 @@ private func preparedChatMediaInputPanelEntryTransition(account: Account, from f
|
||||
|
||||
private func preparedChatMediaInputGridEntryTransition(account: Account, from fromEntries: [ChatMediaInputGridEntry], to toEntries: [ChatMediaInputGridEntry], update: StickerPacksCollectionUpdate, interfaceInteraction: ChatControllerInteraction, inputNodeInteraction: ChatMediaInputNodeInteraction) -> ChatMediaInputGridTransition {
|
||||
var stationaryItems: GridNodeStationaryItems = .none
|
||||
var scrollToItem: GridNodeScrollToItem?
|
||||
switch update {
|
||||
case .generic:
|
||||
break
|
||||
@@ -48,6 +50,17 @@ private func preparedChatMediaInputGridEntryTransition(account: Account, from fr
|
||||
index += 1
|
||||
}
|
||||
stationaryItems = .indices(indices)
|
||||
case let .navigate(index):
|
||||
for i in 0 ..< toEntries.count {
|
||||
if toEntries[i].index >= index {
|
||||
var directionHint: GridNodePreviousItemsTransitionDirectionHint = .up
|
||||
if !fromEntries.isEmpty && fromEntries[0].index < toEntries[i].index {
|
||||
directionHint = .down
|
||||
}
|
||||
scrollToItem = GridNodeScrollToItem(index: i, position: .top, transition: .animated(duration: 0.45, curve: .spring), directionHint: directionHint, adjustForSection: true)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||
@@ -61,7 +74,7 @@ private func preparedChatMediaInputGridEntryTransition(account: Account, from fr
|
||||
firstIndexInSectionOffset = Int(toEntries[0].index.itemIndex.index)
|
||||
}
|
||||
|
||||
return ChatMediaInputGridTransition(deletions: deletions, insertions: insertions, updates: updates, updateFirstIndexInSectionOffset: firstIndexInSectionOffset, stationaryItems: stationaryItems)
|
||||
return ChatMediaInputGridTransition(deletions: deletions, insertions: insertions, updates: updates, updateFirstIndexInSectionOffset: firstIndexInSectionOffset, stationaryItems: stationaryItems, scrollToItem: scrollToItem)
|
||||
}
|
||||
|
||||
private func chatMediaInputPanelEntries(view: ItemCollectionsView) -> [ChatMediaInputPanelEntry] {
|
||||
@@ -97,6 +110,7 @@ private func chatMediaInputGridEntries(view: ItemCollectionsView) -> [ChatMediaI
|
||||
private enum StickerPacksCollectionPosition: Equatable {
|
||||
case initial
|
||||
case scroll(aroundIndex: ItemCollectionViewEntryIndex)
|
||||
case navigate(index: ItemCollectionViewEntryIndex)
|
||||
|
||||
static func ==(lhs: StickerPacksCollectionPosition, rhs: StickerPacksCollectionPosition) -> Bool {
|
||||
switch lhs {
|
||||
@@ -112,6 +126,8 @@ private enum StickerPacksCollectionPosition: Equatable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case .navigate:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,12 +135,22 @@ private enum StickerPacksCollectionPosition: Equatable {
|
||||
private enum StickerPacksCollectionUpdate {
|
||||
case generic
|
||||
case scroll
|
||||
case navigate(ItemCollectionViewEntryIndex)
|
||||
}
|
||||
|
||||
final class ChatMediaInputNodeInteraction {
|
||||
let navigateToCollectionId: (ItemCollectionId) -> Void
|
||||
|
||||
var highlightedItemCollectionId: ItemCollectionId?
|
||||
|
||||
init(navigateToCollectionId: @escaping (ItemCollectionId) -> Void) {
|
||||
self.navigateToCollectionId = navigateToCollectionId
|
||||
}
|
||||
}
|
||||
|
||||
private let defaultPortraitPanelHeight: CGFloat = UIScreenScale.isEqual(to: 3.0) ? 271.0 : 258.0
|
||||
private let defaultLandscapePanelHeight: CGFloat = UIScreenScale.isEqual(to: 3.0) ? 194.0 : 194.0
|
||||
|
||||
final class ChatMediaInputNode: ChatInputNode {
|
||||
private let account: Account
|
||||
private let controllerInteraction: ChatControllerInteraction
|
||||
@@ -161,7 +187,21 @@ final class ChatMediaInputNode: ChatInputNode {
|
||||
|
||||
super.init()
|
||||
|
||||
self.inputNodeInteraction = ChatMediaInputNodeInteraction()
|
||||
self.inputNodeInteraction = ChatMediaInputNodeInteraction(navigateToCollectionId: { [weak self] collectionId in
|
||||
if let strongSelf = self, let currentView = strongSelf.currentView, (collectionId != strongSelf.inputNodeInteraction.highlightedItemCollectionId || true) {
|
||||
var index: Int32 = 0
|
||||
for (id, _, _) in currentView.collectionInfos {
|
||||
if id.namespace == collectionId.namespace {
|
||||
if id == collectionId {
|
||||
let itemIndex = ItemCollectionViewEntryIndex.lowerBound(collectionIndex: index, collectionId: id)
|
||||
strongSelf.itemCollectionsViewPosition.set(.single(.navigate(index: itemIndex)))
|
||||
break
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
self.clipsToBounds = true
|
||||
self.backgroundColor = UIColor(0xE8EBF0)
|
||||
@@ -193,6 +233,19 @@ final class ChatMediaInputNode: ChatInputNode {
|
||||
}
|
||||
return (view, update)
|
||||
}
|
||||
case let .navigate(index):
|
||||
var firstTime = true
|
||||
return account.postbox.itemCollectionsView(namespaces: [Namespaces.ItemCollection.CloudStickerPacks], aroundIndex: index, count: 140)
|
||||
|> map { view -> (ItemCollectionsView, StickerPacksCollectionUpdate) in
|
||||
let update: StickerPacksCollectionUpdate
|
||||
if firstTime {
|
||||
firstTime = false
|
||||
update = .navigate(index)
|
||||
} else {
|
||||
update = .generic
|
||||
}
|
||||
return (view, update)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,20 +271,38 @@ final class ChatMediaInputNode: ChatInputNode {
|
||||
|
||||
self.gridNode.visibleItemsUpdated = { [weak self] visibleItems in
|
||||
if let strongSelf = self {
|
||||
if let topVisible = visibleItems.topVisible {
|
||||
if let item = topVisible.1 as? ChatMediaInputStickerGridItem {
|
||||
let collectionId = item.index.collectionId
|
||||
var topVisibleCollectionId: ItemCollectionId?
|
||||
|
||||
if let topVisibleSection = visibleItems.topSectionVisible as? ChatMediaInputStickerGridSection {
|
||||
topVisibleCollectionId = topVisibleSection.collectionId
|
||||
} else if let topVisible = visibleItems.topVisible, let item = topVisible.1 as? ChatMediaInputStickerGridItem {
|
||||
topVisibleCollectionId = item.index.collectionId
|
||||
}
|
||||
if let collectionId = topVisibleCollectionId {
|
||||
if strongSelf.inputNodeInteraction.highlightedItemCollectionId != collectionId {
|
||||
strongSelf.inputNodeInteraction.highlightedItemCollectionId = collectionId
|
||||
var selectedItemNode: ChatMediaInputStickerPackItemNode?
|
||||
var ensuredNodeVisible = false
|
||||
var firstVisibleCollectionId: ItemCollectionId?
|
||||
strongSelf.listView.forEachItemNode { itemNode in
|
||||
if let itemNode = itemNode as? ChatMediaInputStickerPackItemNode {
|
||||
if firstVisibleCollectionId == nil {
|
||||
firstVisibleCollectionId = itemNode.currentCollectionId
|
||||
}
|
||||
itemNode.updateIsHighlighted()
|
||||
if itemNode.currentCollectionId == collectionId {
|
||||
strongSelf.listView.ensureItemNodeVisible(itemNode)
|
||||
ensuredNodeVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if let currentView = strongSelf.currentView, let firstVisibleCollectionId = firstVisibleCollectionId, !ensuredNodeVisible {
|
||||
let targetIndex = currentView.collectionInfos.index(where: { id, _, _ in return id == collectionId })
|
||||
let firstVisibleIndex = currentView.collectionInfos.index(where: { id, _, _ in return id == firstVisibleCollectionId })
|
||||
if let targetIndex = targetIndex, let firstVisibleIndex = firstVisibleIndex {
|
||||
let toRight = targetIndex > firstVisibleIndex
|
||||
strongSelf.listView.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [], scrollToItem: ListViewScrollToItem(index: targetIndex, position: toRight ? .Bottom : .Top, animated: true, curve: .Default, directionHint: toRight ? .Down : .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,8 +333,13 @@ final class ChatMediaInputNode: ChatInputNode {
|
||||
self.disposable.dispose()
|
||||
}
|
||||
|
||||
private func heightForWidth(width: CGFloat) -> CGFloat {
|
||||
return defaultPortraitPanelHeight
|
||||
}
|
||||
|
||||
override func updateLayout(width: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat {
|
||||
let separatorHeight = UIScreenPixel
|
||||
let panelHeight = self.heightForWidth(width: width)
|
||||
|
||||
transition.updateFrame(node: self.collectionListPanel, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: 41.0)))
|
||||
transition.updateFrame(node: self.collectionListSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: 41.0), size: CGSize(width: width, height: separatorHeight)))
|
||||
@@ -293,15 +369,15 @@ final class ChatMediaInputNode: ChatInputNode {
|
||||
listViewCurve = .Default
|
||||
}
|
||||
|
||||
let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: CGSize(width: 41.0, height: width), insets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0), duration: duration, curve: listViewCurve)
|
||||
let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: CGSize(width: 41.0, height: width), insets: UIEdgeInsets(top: 4.0, left: 0.0, bottom: 4.0, right: 0.0), duration: duration, curve: listViewCurve)
|
||||
|
||||
self.listView.deleteAndInsertItems(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, completion: { _ in })
|
||||
self.listView.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
|
||||
self.gridNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 41.0), size: CGSize(width: width, height: 258.0 - 41.0))
|
||||
self.gridNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 41.0), size: CGSize(width: width, height: panelHeight - 41.0))
|
||||
|
||||
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: CGSize(width: width, height: 258.0 - 41.0), insets: UIEdgeInsets(), preloadSize: 300.0, itemSize: CGSize(width: 75.0, height: 75.0)), transition: .immediate), stationaryItems: .all, updateFirstIndexInSectionOffset: nil), completion: { _ in })
|
||||
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: CGSize(width: width, height: panelHeight - 41.0), insets: UIEdgeInsets(), preloadSize: 300.0, itemSize: CGSize(width: 75.0, height: 75.0)), transition: .immediate), stationaryItems: .all, updateFirstIndexInSectionOffset: nil), completion: { _ in })
|
||||
|
||||
return 258.0
|
||||
return panelHeight
|
||||
}
|
||||
|
||||
private func enqueuePanelTransition(_ transition: ChatMediaInputPanelTransition, firstTime: Bool) {
|
||||
@@ -312,11 +388,11 @@ final class ChatMediaInputNode: ChatInputNode {
|
||||
} else {
|
||||
options.insert(.AnimateInsertion)
|
||||
}
|
||||
self.listView.deleteAndInsertItems(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, completion: { [weak self] _ in
|
||||
self.listView.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateOpaqueState: nil, completion: { [weak self] _ in
|
||||
})
|
||||
}
|
||||
|
||||
private func enqueueGridTransition(_ transition: ChatMediaInputGridTransition, firstTime: Bool) {
|
||||
self.gridNode.transaction(GridNodeTransaction(deleteItems: transition.deletions, insertItems: transition.insertions, updateItems: transition.updates, scrollToItem: nil, updateLayout: nil, stationaryItems: transition.stationaryItems, updateFirstIndexInSectionOffset: transition.updateFirstIndexInSectionOffset), completion: { _ in })
|
||||
self.gridNode.transaction(GridNodeTransaction(deleteItems: transition.deletions, insertItems: transition.insertions, updateItems: transition.updates, scrollToItem: transition.scrollToItem, updateLayout: nil, stationaryItems: transition.stationaryItems, updateFirstIndexInSectionOffset: transition.updateFirstIndexInSectionOffset), completion: { _ in })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ enum ChatMediaInputPanelEntry: Comparable, Identifiable {
|
||||
switch self {
|
||||
case let .stickerPack(index, info, topItem):
|
||||
return ChatMediaInputStickerPackItem(account: account, inputNodeInteraction: inputNodeInteraction, collectionId: info.id, stickerPackItem: topItem, index: index, selected: {
|
||||
inputNodeInteraction.navigateToCollectionId(info.id)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,12 +135,12 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode {
|
||||
override func layout() {
|
||||
super.layout()
|
||||
|
||||
let imageFrame = self.bounds.insetBy(dx: 6.0, dy: 6.0)
|
||||
self.imageNode.frame = imageFrame
|
||||
let boundingSize = self.bounds.insetBy(dx: 6.0, dy: 6.0).size
|
||||
|
||||
if let (_, _, mediaDimensions) = self.currentState {
|
||||
let imageSize = mediaDimensions.aspectFitted(imageFrame.size)
|
||||
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageFrame.size, intrinsicInsets: UIEdgeInsets()))()
|
||||
let imageSize = mediaDimensions.aspectFitted(boundingSize)
|
||||
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: boundingSize, intrinsicInsets: UIEdgeInsets()))()
|
||||
self.imageNode.frame = CGRect(origin: CGPoint(x: 6.0, y: 6.0), size: imageSize)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ final class ChatMediaInputStickerPackItem: ListViewItem {
|
||||
}
|
||||
|
||||
private let boundingSize = CGSize(width: 41.0, height: 41.0)
|
||||
private let imageSize = CGSize(width: 30.0, height: 30.0)
|
||||
private let boundingImageSize = CGSize(width: 30.0, height: 30.0)
|
||||
private let highlightSize = CGSize(width: 35.0, height: 35.0)
|
||||
private let verticalOffset: CGFloat = 3.0
|
||||
|
||||
@@ -76,7 +76,6 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
|
||||
self.highlightNode.frame = CGRect(origin: CGPoint(x: floor((boundingSize.width - highlightSize.width) / 2.0) + verticalOffset, y: floor((boundingSize.height - highlightSize.height) / 2.0)), size: highlightSize)
|
||||
|
||||
self.imageNode.frame = CGRect(origin: CGPoint(x: floor((boundingSize.width - imageSize.width) / 2.0) + verticalOffset, y: floor((boundingSize.height - imageSize.height) / 2.0)), size: imageSize)
|
||||
self.imageNode.transform = CATransform3DMakeRotation(CGFloat(M_PI / 2.0), 0.0, 0.0, 1.0)
|
||||
self.imageNode.alphaTransitionOnFirstUpdate = true
|
||||
|
||||
@@ -97,10 +96,12 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
self.currentItem = item
|
||||
|
||||
if let item = item, let dimensions = item.file.dimensions {
|
||||
let imageApply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: dimensions.aspectFitted(imageSize), boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))
|
||||
let imageSize = dimensions.aspectFitted(boundingImageSize)
|
||||
let imageApply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: boundingImageSize, intrinsicInsets: UIEdgeInsets()))
|
||||
imageApply()
|
||||
self.imageNode.setSignal(account: account, signal: chatMessageSticker(account: account, file: item.file, small: true))
|
||||
self.stickerFetchedDisposable.set(fileInteractiveFetched(account: account, file: item.file).start())
|
||||
self.imageNode.frame = CGRect(origin: CGPoint(x: floor((boundingSize.width - imageSize.width) / 2.0) + verticalOffset, y: floor((boundingSize.height - imageSize.height) / 2.0)), size: imageSize)
|
||||
}
|
||||
|
||||
self.updateIsHighlighted()
|
||||
|
||||
@@ -134,6 +134,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
|
||||
let textFieldInsets = UIEdgeInsets(top: 6.0, left: 42.0, bottom: 6.0, right: 42.0)
|
||||
let textInputViewInternalInsets = UIEdgeInsets(top: 6.5, left: 13.0, bottom: 7.5, right: 13.0)
|
||||
let accessoryButtonSpacing: CGFloat = 0.0
|
||||
let accessoryButtonInset: CGFloat = 4.0 + UIScreenPixel
|
||||
|
||||
override init() {
|
||||
self.textInputBackgroundView = UIImageView(image: textInputViewBackground)
|
||||
@@ -204,6 +206,36 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
textInputNode.view.addGestureRecognizer(recognizer)
|
||||
}
|
||||
|
||||
private func calculateTextFieldMetrics(width: CGFloat) -> (accessoryButtonsWidth: CGFloat, textFieldHeight: CGFloat) {
|
||||
let accessoryButtonInset = self.accessoryButtonInset
|
||||
let accessoryButtonSpacing = self.accessoryButtonSpacing
|
||||
|
||||
var accessoryButtonsWidth: CGFloat = 0.0
|
||||
var firstButton = true
|
||||
for (_, button) in self.accessoryItemButtons {
|
||||
if firstButton {
|
||||
firstButton = false
|
||||
accessoryButtonsWidth += accessoryButtonInset
|
||||
} else {
|
||||
accessoryButtonsWidth += accessoryButtonSpacing
|
||||
}
|
||||
accessoryButtonsWidth += button.buttonWidth
|
||||
}
|
||||
|
||||
let textFieldHeight: CGFloat
|
||||
if let textInputNode = self.textInputNode {
|
||||
textFieldHeight = min(115.0, max(21.0, ceil(textInputNode.measure(CGSize(width: width - self.textFieldInsets.left - self.textFieldInsets.right - self.textInputViewInternalInsets.left - self.textInputViewInternalInsets.right - accessoryButtonsWidth, height: CGFloat.greatestFiniteMagnitude)).height)))
|
||||
} else {
|
||||
textFieldHeight = 21.0
|
||||
}
|
||||
|
||||
return (accessoryButtonsWidth, textFieldHeight)
|
||||
}
|
||||
|
||||
private func panelHeight(textFieldHeight: CGFloat) -> CGFloat {
|
||||
return textFieldHeight + self.textFieldInsets.top + self.textFieldInsets.bottom + self.textInputViewInternalInsets.top + self.textInputViewInternalInsets.bottom
|
||||
}
|
||||
|
||||
override func updateLayout(width: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat {
|
||||
if self.presentationInterfaceState != interfaceState {
|
||||
let previousState = self.presentationInterfaceState
|
||||
@@ -228,8 +260,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
|
||||
let minimalHeight: CGFloat = 47.0
|
||||
let minimalInputHeight: CGFloat = 35.0
|
||||
let accessoryButtonSpacing: CGFloat = 0.0
|
||||
let accessoryButtonInset: CGFloat = 4.0 + UIScreenPixel
|
||||
|
||||
var animatedTransition = true
|
||||
if case .immediate = transition {
|
||||
@@ -280,26 +310,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
self.accessoryItemButtons = updatedButtons
|
||||
}
|
||||
|
||||
var accessoryButtonsWidth: CGFloat = 0.0
|
||||
var firstButton = true
|
||||
for (_, button) in self.accessoryItemButtons {
|
||||
if firstButton {
|
||||
firstButton = false
|
||||
accessoryButtonsWidth += accessoryButtonInset
|
||||
} else {
|
||||
accessoryButtonsWidth += accessoryButtonSpacing
|
||||
}
|
||||
accessoryButtonsWidth += button.buttonWidth
|
||||
}
|
||||
|
||||
let textFieldHeight: CGFloat
|
||||
if let textInputNode = self.textInputNode {
|
||||
textFieldHeight = min(115.0, max(21.0, ceil(textInputNode.measure(CGSize(width: width - self.textFieldInsets.left - self.textFieldInsets.right - self.textInputViewInternalInsets.left - self.textInputViewInternalInsets.right - accessoryButtonsWidth, height: CGFloat.greatestFiniteMagnitude)).height)))
|
||||
} else {
|
||||
textFieldHeight = 21.0
|
||||
}
|
||||
|
||||
let panelHeight = textFieldHeight + self.textFieldInsets.top + self.textFieldInsets.bottom + self.textInputViewInternalInsets.top + self.textInputViewInternalInsets.bottom
|
||||
let (accessoryButtonsWidth, textFieldHeight) = self.calculateTextFieldMetrics(width: width)
|
||||
let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight)
|
||||
|
||||
transition.updateFrame(layer: self.attachmentButton.layer, frame: CGRect(origin: CGPoint(x: 2.0 - UIScreenPixel, y: panelHeight - minimalHeight), size: CGSize(width: 40.0, height: minimalHeight)))
|
||||
transition.updateFrame(layer: self.micButton.layer, frame: CGRect(origin: CGPoint(x: width - 43.0 - UIScreenPixel, y: panelHeight - minimalHeight - UIScreenPixel), size: CGSize(width: 44.0, height: minimalHeight)))
|
||||
@@ -369,6 +381,12 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
}
|
||||
|
||||
self.interfaceInteraction?.updateTextInputState(self.inputTextState)
|
||||
|
||||
let (accessoryButtonsWidth, textFieldHeight) = self.calculateTextFieldMetrics(width: self.bounds.size.width)
|
||||
let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight)
|
||||
if !self.bounds.size.height.isEqual(to: panelHeight) {
|
||||
self.updateHeight()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ public class ContactsController: ViewController {
|
||||
|
||||
self.scrollToTop = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.contactsNode.listView.deleteAndInsertItems(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .Top, animated: true, curve: .Default, directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, completion: { _ in })
|
||||
strongSelf.contactsNode.listView.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .Top, animated: true, curve: .Default, directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -306,7 +306,7 @@ public class ContactsController: ViewController {
|
||||
} else if animated {
|
||||
options.insert(.AnimateInsertion)
|
||||
}
|
||||
self.contactsNode.listView.deleteAndInsertItems(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, completion: { [weak self] _ in
|
||||
self.contactsNode.listView.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateOpaqueState: nil, completion: { [weak self] _ in
|
||||
if let strongSelf = self {
|
||||
if !strongSelf.didSetReady {
|
||||
strongSelf.didSetReady = true
|
||||
|
||||
@@ -61,7 +61,7 @@ final class ContactsControllerNode: ASDisplayNode {
|
||||
|
||||
let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: layout.size, insets: insets, duration: duration, curve: listViewCurve)
|
||||
|
||||
self.listView.deleteAndInsertItems(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, completion: { _ in })
|
||||
self.listView.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
|
||||
if let searchDisplayController = self.searchDisplayController {
|
||||
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
||||
|
||||
@@ -64,7 +64,7 @@ final class ContactsSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.listNode.deleteAndInsertItems(deleteIndices: (0 ..< previousItems.count).map({ ListViewDeleteItem(index: $0, directionHint: nil) }), insertIndicesAndItems: (0 ..< listItems.count).map({ ListViewInsertItem(index: $0, previousIndex: nil, item: listItems[$0], directionHint: .Down) }), updateIndicesAndItems: [], options: [])
|
||||
strongSelf.listNode.transaction(deleteIndices: (0 ..< previousItems.count).map({ ListViewDeleteItem(index: $0, directionHint: nil) }), insertIndicesAndItems: (0 ..< listItems.count).map({ ListViewInsertItem(index: $0, previousIndex: nil, item: listItems[$0], directionHint: .Down) }), updateIndicesAndItems: [], options: [], updateOpaqueState: nil)
|
||||
}
|
||||
}))
|
||||
}
|
||||
@@ -87,6 +87,6 @@ final class ContactsSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
super.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
||||
|
||||
self.listNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
self.listNode.deleteAndInsertItems(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: UIEdgeInsets(top: navigationBarHeight, left: 0.0, bottom: 0.0, right: 0.0), duration: 0.0, curve: .Default), stationaryItemRange: nil, completion: { _ in })
|
||||
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: UIEdgeInsets(top: navigationBarHeight, left: 0.0, bottom: 0.0, right: 0.0), duration: 0.0, curve: .Default), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public class ListController: ViewController {
|
||||
self.displayNode.backgroundColor = UIColor(0xefeff4)
|
||||
|
||||
if !self.items.isEmpty {
|
||||
self.listDisplayNode.listView.deleteAndInsertItems(deleteIndices: [], insertIndicesAndItems: (0 ..< self.items.count).map({ ListViewInsertItem(index: $0, previousIndex: nil, item: self.items[$0], directionHint: .Down) }), updateIndicesAndItems: [], options: [.LowLatency, .Synchronous])
|
||||
self.listDisplayNode.listView.transaction(deleteIndices: [], insertIndicesAndItems: (0 ..< self.items.count).map({ ListViewInsertItem(index: $0, previousIndex: nil, item: self.items[$0], directionHint: .Down) }), updateIndicesAndItems: [], options: [.LowLatency, .Synchronous], updateOpaqueState: nil)
|
||||
}
|
||||
|
||||
self.displayNodeDidLoad()
|
||||
|
||||
@@ -44,6 +44,6 @@ public class ListControllerNode: ASDisplayNode {
|
||||
self.listView.bounds = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height)
|
||||
self.listView.position = CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0)
|
||||
|
||||
self.listView.deleteAndInsertItems(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: insets, duration: duration, curve: listViewCurve), stationaryItemRange: nil, completion: { _ in })
|
||||
self.listView.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: insets, duration: duration, curve: listViewCurve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ public final class PeerInfoController: ListController {
|
||||
} else if animated {
|
||||
options.insert(.AnimateInsertion)
|
||||
}
|
||||
self.listDisplayNode.listView.deleteAndInsertItems(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, completion: { [weak self] _ in
|
||||
self.listDisplayNode.listView.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateOpaqueState: nil, completion: { [weak self] _ in
|
||||
if let strongSelf = self {
|
||||
if !strongSelf.didSetReady {
|
||||
strongSelf.didSetReady = true
|
||||
|
||||
@@ -18,7 +18,6 @@ private func chatMessagePhotoDatas(account: Account, photo: TelegramMediaImage,
|
||||
let signal = maybeFullSize |> take(1) |> mapToSignal { maybeData -> Signal<(Data?, Data?, Bool), NoError> in
|
||||
if maybeData.complete {
|
||||
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: [])
|
||||
|
||||
return .single((nil, loadedData, true))
|
||||
} else {
|
||||
let fetchedThumbnail = account.postbox.mediaBox.fetchedResource(smallestRepresentation.resource)
|
||||
@@ -371,9 +370,22 @@ func chatMessagePhoto(account: Account, photo: TelegramMediaImage) -> Signal<(Tr
|
||||
|
||||
return signal |> map { (thumbnailData, fullSizeData, fullSizeComplete) in
|
||||
return { arguments in
|
||||
assertNotOnMainThread()
|
||||
var debugTiming = false
|
||||
var startTime = 0.0
|
||||
if arguments.imageSize.equalTo(CGSize(width: 640.0, height: 853.0)) {
|
||||
print("begin draw \(CFAbsoluteTimeGetCurrent() * 1000.0)")
|
||||
debugTiming = true
|
||||
startTime = CFAbsoluteTimeGetCurrent()
|
||||
}
|
||||
|
||||
let context = DrawingContext(size: arguments.drawingSize, clear: true)
|
||||
|
||||
if debugTiming {
|
||||
let currentTime = CFAbsoluteTimeGetCurrent()
|
||||
print("create context: \((currentTime - startTime) * 1000.0) ms")
|
||||
startTime = currentTime
|
||||
}
|
||||
|
||||
let drawingRect = arguments.drawingRect
|
||||
let fittedSize = arguments.imageSize.aspectFilled(arguments.boundingSize).fitted(arguments.imageSize)
|
||||
let fittedRect = CGRect(origin: CGPoint(x: drawingRect.origin.x + (drawingRect.size.width - fittedSize.width) / 2.0, y: drawingRect.origin.y + (drawingRect.size.height - fittedSize.height) / 2.0), size: fittedSize)
|
||||
@@ -381,11 +393,16 @@ func chatMessagePhoto(account: Account, photo: TelegramMediaImage) -> Signal<(Tr
|
||||
var fullSizeImage: CGImage?
|
||||
if let fullSizeData = fullSizeData {
|
||||
if fullSizeComplete {
|
||||
let options = NSMutableDictionary()
|
||||
/*let options = NSMutableDictionary()
|
||||
options.setValue(max(fittedSize.width * context.scale, fittedSize.height * context.scale) as NSNumber, forKey: kCGImageSourceThumbnailMaxPixelSize as String)
|
||||
options.setValue(true as NSNumber, forKey: kCGImageSourceCreateThumbnailFromImageAlways as String)
|
||||
if let imageSource = CGImageSourceCreateWithData(fullSizeData as CFData, nil), let image = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary) {
|
||||
fullSizeImage = image
|
||||
}*/
|
||||
let options = NSMutableDictionary()
|
||||
options[kCGImageSourceShouldCache as NSString] = false as NSNumber
|
||||
if let imageSource = CGImageSourceCreateWithData(fullSizeData as CFData, nil), let image = CGImageSourceCreateImageAtIndex(imageSource, 0, options as CFDictionary) {
|
||||
fullSizeImage = image
|
||||
}
|
||||
} else {
|
||||
let imageSource = CGImageSourceCreateIncremental(nil)
|
||||
@@ -399,6 +416,12 @@ func chatMessagePhoto(account: Account, photo: TelegramMediaImage) -> Signal<(Tr
|
||||
}
|
||||
}
|
||||
|
||||
if debugTiming {
|
||||
let currentTime = CFAbsoluteTimeGetCurrent()
|
||||
print("decode full: \((currentTime - startTime) * 1000.0) ms")
|
||||
startTime = currentTime
|
||||
}
|
||||
|
||||
var thumbnailImage: CGImage?
|
||||
if let thumbnailData = thumbnailData, let imageSource = CGImageSourceCreateWithData(thumbnailData as CFData, nil), let image = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) {
|
||||
thumbnailImage = image
|
||||
@@ -418,6 +441,12 @@ func chatMessagePhoto(account: Account, photo: TelegramMediaImage) -> Signal<(Tr
|
||||
blurredThumbnailImage = thumbnailContext.generateImage()
|
||||
}
|
||||
|
||||
if debugTiming {
|
||||
let currentTime = CFAbsoluteTimeGetCurrent()
|
||||
print("decode thumbnail: \((currentTime - startTime) * 1000.0) ms")
|
||||
startTime = currentTime
|
||||
}
|
||||
|
||||
context.withFlippedContext { c in
|
||||
c.setBlendMode(.copy)
|
||||
if arguments.boundingSize != arguments.imageSize {
|
||||
@@ -437,8 +466,20 @@ func chatMessagePhoto(account: Account, photo: TelegramMediaImage) -> Signal<(Tr
|
||||
}
|
||||
}
|
||||
|
||||
if debugTiming {
|
||||
let currentTime = CFAbsoluteTimeGetCurrent()
|
||||
print("draw: \((currentTime - startTime) * 1000.0) ms")
|
||||
startTime = currentTime
|
||||
}
|
||||
|
||||
addCorners(context, arguments: arguments)
|
||||
|
||||
if debugTiming {
|
||||
let currentTime = CFAbsoluteTimeGetCurrent()
|
||||
print("add corners: \((currentTime - startTime) * 1000.0) ms")
|
||||
startTime = currentTime
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class SettingsController: ListController {
|
||||
let item = SettingsAccountInfoItem(account: account, peer: peer, connectionStatus: connectionStatus)
|
||||
strongSelf.items[0] = item
|
||||
if strongSelf.isNodeLoaded {
|
||||
strongSelf.listDisplayNode.listView.deleteAndInsertItems(deleteIndices: [ListViewDeleteItem(index: 0, directionHint: nil)], insertIndicesAndItems: [ListViewInsertItem(index: 0, previousIndex: 0, item: item, directionHint: .Down)], updateIndicesAndItems: [], options: [.AnimateInsertion])
|
||||
strongSelf.listDisplayNode.listView.transaction(deleteIndices: [ListViewDeleteItem(index: 0, directionHint: nil)], insertIndicesAndItems: [ListViewInsertItem(index: 0, previousIndex: 0, item: item, directionHint: .Down)], updateIndicesAndItems: [], options: [.AnimateInsertion], updateOpaqueState: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,8 +62,6 @@ func chatMessageSticker(account: Account, file: TelegramMediaFile, small: Bool)
|
||||
|
||||
return signal |> map { (thumbnailData, fullSizeData, fullSizeComplete) in
|
||||
return { arguments in
|
||||
assertNotOnMainThread()
|
||||
|
||||
let context = DrawingContext(size: arguments.drawingSize, clear: true)
|
||||
|
||||
var fullSizeImage: (UIImage, UIImage)?
|
||||
|
||||
@@ -36,7 +36,7 @@ public class TransformImageNode: ASDisplayNode {
|
||||
public var alphaTransitionOnFirstUpdate = false
|
||||
private var disposable = MetaDisposable()
|
||||
|
||||
private var argumentsPromise = Promise<TransformImageArguments>()
|
||||
private var argumentsPromise = ValuePromise<TransformImageArguments>(ignoreRepeated: true)
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
@@ -45,7 +45,7 @@ public class TransformImageNode: ASDisplayNode {
|
||||
func setSignal(account: Account, signal: Signal<(TransformImageArguments) -> DrawingContext, NoError>, dispatchOnDisplayLink: Bool = true) {
|
||||
let argumentsPromise = self.argumentsPromise
|
||||
|
||||
let result = combineLatest(signal, argumentsPromise.get()) |> deliverOn(account.graphicsThreadPool) |> mapToThrottled { transform, arguments -> Signal<UIImage?, NoError> in
|
||||
let result = combineLatest(signal, argumentsPromise.get()) |> deliverOn(Queue.concurrentDefaultQueue() /*account.graphicsThreadPool*/) |> mapToThrottled { transform, arguments -> Signal<UIImage?, NoError> in
|
||||
return deferred {
|
||||
return Signal<UIImage?, NoError>.single(transform(arguments).generateImage())
|
||||
}
|
||||
@@ -80,7 +80,7 @@ public class TransformImageNode: ASDisplayNode {
|
||||
|
||||
public func asyncLayout() -> (TransformImageArguments) -> (() -> Void) {
|
||||
return { arguments in
|
||||
self.argumentsPromise.set(.single(arguments))
|
||||
self.argumentsPromise.set(arguments)
|
||||
|
||||
return {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user