mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-02 00:17:02 +00:00
Optimized media grid synchronous loading
This commit is contained in:
parent
b6d35a9bb4
commit
d794ece01e
@ -249,8 +249,9 @@ public final class ChatHistoryGridNode: GridNode, ChatHistoryNode {
|
||||
|
||||
super.init()
|
||||
|
||||
self.chatPresentationDataPromise.set(context.sharedContext.presentationData |> map { presentationData in
|
||||
return ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper), fontSize: presentationData.fontSize, strings: self.presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations)
|
||||
self.chatPresentationDataPromise.set(context.sharedContext.presentationData
|
||||
|> map { presentationData in
|
||||
return ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper), fontSize: presentationData.fontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations)
|
||||
})
|
||||
|
||||
self.floatingSections = true
|
||||
@ -493,7 +494,7 @@ public final class ChatHistoryGridNode: GridNode, ChatHistoryNode {
|
||||
|
||||
self.transaction(GridNodeTransaction(deleteItems: mappedTransition.deleteItems, insertItems: mappedTransition.insertItems, updateItems: mappedTransition.updateItems, scrollToItem: mappedTransition.scrollToItem, updateLayout: updateLayout, itemTransition: .immediate, stationaryItems: transition.stationaryItems, updateFirstIndexInSectionOffset: mappedTransition.topOffsetWithinMonth), completion: completion)
|
||||
} else {
|
||||
self.transaction(GridNodeTransaction(deleteItems: transition.deleteItems, insertItems: transition.insertItems, updateItems: transition.updateItems, scrollToItem: transition.scrollToItem, updateLayout: nil, itemTransition: .immediate, stationaryItems: transition.stationaryItems, updateFirstIndexInSectionOffset: transition.topOffsetWithinMonth), completion: completion)
|
||||
self.transaction(GridNodeTransaction(deleteItems: transition.deleteItems, insertItems: transition.insertItems, updateItems: transition.updateItems, scrollToItem: transition.scrollToItem, updateLayout: nil, itemTransition: .immediate, stationaryItems: transition.stationaryItems, updateFirstIndexInSectionOffset: transition.topOffsetWithinMonth, synchronousLoads: true), completion: completion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ final class GridMessageItem: GridItem {
|
||||
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
|
||||
let node = GridMessageItemNode()
|
||||
if let media = mediaForMessage(self.message) {
|
||||
node.setup(context: self.context, item: self, media: media, messageId: self.message.id, controllerInteraction: self.controllerInteraction)
|
||||
node.setup(context: self.context, item: self, media: media, messageId: self.message.id, controllerInteraction: self.controllerInteraction, synchronousLoad: synchronousLoad)
|
||||
}
|
||||
return node
|
||||
}
|
||||
@ -181,7 +181,7 @@ final class GridMessageItem: GridItem {
|
||||
return
|
||||
}
|
||||
if let media = mediaForMessage(self.message) {
|
||||
node.setup(context: self.context, item: self, media: media, messageId: self.message.id, controllerInteraction: self.controllerInteraction)
|
||||
node.setup(context: self.context, item: self, media: media, messageId: self.message.id, controllerInteraction: self.controllerInteraction, synchronousLoad: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -229,13 +229,13 @@ final class GridMessageItemNode: GridItemNode {
|
||||
self.imageNode.view.addGestureRecognizer(recognizer)
|
||||
}
|
||||
|
||||
func setup(context: AccountContext, item: GridMessageItem, media: Media, messageId: MessageId, controllerInteraction: ChatControllerInteraction) {
|
||||
func setup(context: AccountContext, item: GridMessageItem, media: Media, messageId: MessageId, controllerInteraction: ChatControllerInteraction, synchronousLoad: Bool) {
|
||||
if self.currentState == nil || self.currentState!.0 !== context || !self.currentState!.1.isEqual(to: media) {
|
||||
var mediaDimensions: CGSize?
|
||||
if let image = media as? TelegramMediaImage, let largestSize = largestImageRepresentation(image.representations)?.dimensions {
|
||||
mediaDimensions = largestSize
|
||||
|
||||
self.imageNode.setSignal(mediaGridMessagePhoto(account: context.account, photoReference: .message(message: MessageReference(item.message), media: image)), dispatchOnDisplayLink: true)
|
||||
self.imageNode.setSignal(mediaGridMessagePhoto(account: context.account, photoReference: .message(message: MessageReference(item.message), media: image), synchronousLoad: synchronousLoad), attemptSynchronously: synchronousLoad, dispatchOnDisplayLink: true)
|
||||
|
||||
self.fetchStatusDisposable.set(nil)
|
||||
self.statusNode.transitionToState(.none, completion: { [weak self] in
|
||||
@ -245,7 +245,7 @@ final class GridMessageItemNode: GridItemNode {
|
||||
self.resourceStatus = nil
|
||||
} else if let file = media as? TelegramMediaFile, file.isVideo {
|
||||
mediaDimensions = file.dimensions
|
||||
self.imageNode.setSignal(mediaGridMessageVideo(postbox: context.account.postbox, videoReference: .message(message: MessageReference(item.message), media: file)))
|
||||
self.imageNode.setSignal(mediaGridMessageVideo(postbox: context.account.postbox, videoReference: .message(message: MessageReference(item.message), media: file), synchronousLoad: synchronousLoad), attemptSynchronously: synchronousLoad)
|
||||
|
||||
if let duration = file.duration {
|
||||
self.videoAccessoryNode.setup(stringForDuration(duration))
|
||||
|
@ -105,11 +105,13 @@ private enum LogoutOptionsEntry: ItemListNodeEntry, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private func logoutOptionsEntries(presentationData: PresentationData, canAddAccounts: Bool) -> [LogoutOptionsEntry] {
|
||||
private func logoutOptionsEntries(presentationData: PresentationData, canAddAccounts: Bool, hasPasscode: Bool) -> [LogoutOptionsEntry] {
|
||||
var entries: [LogoutOptionsEntry] = []
|
||||
entries.append(.alternativeHeader(presentationData.theme, presentationData.strings.LogoutOptions_AlternativeOptionsSection))
|
||||
entries.append(.addAccount(presentationData.theme, presentationData.strings.LogoutOptions_AddAccountTitle, presentationData.strings.LogoutOptions_AddAccountText))
|
||||
entries.append(.setPasscode(presentationData.theme, presentationData.strings.LogoutOptions_SetPasscodeTitle, presentationData.strings.LogoutOptions_SetPasscodeText))
|
||||
if !hasPasscode {
|
||||
entries.append(.setPasscode(presentationData.theme, presentationData.strings.LogoutOptions_SetPasscodeTitle, presentationData.strings.LogoutOptions_SetPasscodeText))
|
||||
}
|
||||
entries.append(.clearCache(presentationData.theme, presentationData.strings.LogoutOptions_ClearCacheTitle, presentationData.strings.LogoutOptions_ClearCacheText))
|
||||
entries.append(.changePhoneNumber(presentationData.theme, presentationData.strings.LogoutOptions_ChangePhoneNumberTitle, presentationData.strings.LogoutOptions_ChangePhoneNumberText))
|
||||
entries.append(.contactSupport(presentationData.theme, presentationData.strings.LogoutOptions_ContactSupportTitle, presentationData.strings.LogoutOptions_ContactSupportText))
|
||||
@ -198,14 +200,22 @@ func logoutOptionsController(context: AccountContext, navigationController: Navi
|
||||
presentControllerImpl?(alertController, nil)
|
||||
})
|
||||
|
||||
let signal = context.sharedContext.presentationData
|
||||
|> map { presentationData -> (ItemListControllerState, (ItemListNodeState<LogoutOptionsEntry>, LogoutOptionsEntry.ItemGenerationArguments)) in
|
||||
let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, context.sharedContext.accountManager.accessChallengeData())
|
||||
|> map { presentationData, accessChallengeData -> (ItemListControllerState, (ItemListNodeState<LogoutOptionsEntry>, LogoutOptionsEntry.ItemGenerationArguments)) in
|
||||
let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {
|
||||
dismissImpl?()
|
||||
})
|
||||
|
||||
var hasPasscode = false
|
||||
switch accessChallengeData.data {
|
||||
case .numericalPassword, .plaintextPassword:
|
||||
hasPasscode = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.LogoutOptions_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
||||
let listState = ItemListNodeState(entries: logoutOptionsEntries(presentationData: presentationData, canAddAccounts: canAddAccounts), style: .blocks)
|
||||
let listState = ItemListNodeState(entries: logoutOptionsEntries(presentationData: presentationData, canAddAccounts: canAddAccounts, hasPasscode: hasPasscode), style: .blocks)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
|
@ -282,13 +282,13 @@ private func chatMessageImageFileThumbnailDatas(account: Account, fileReference:
|
||||
return signal
|
||||
}
|
||||
|
||||
private func chatMessageVideoDatas(postbox: Postbox, fileReference: FileMediaReference, thumbnailSize: Bool = false, onlyFullSize: Bool = false) -> Signal<(Data?, (Data, String)?, Bool), NoError> {
|
||||
private func chatMessageVideoDatas(postbox: Postbox, fileReference: FileMediaReference, thumbnailSize: Bool = false, onlyFullSize: Bool = false, synchronousLoad: Bool = false) -> Signal<(Data?, (Data, String)?, Bool), NoError> {
|
||||
let fullSizeResource = fileReference.media.resource
|
||||
|
||||
let thumbnailResource = smallestImageRepresentation(fileReference.media.previewRepresentations)?.resource
|
||||
|
||||
let maybeFullSize = postbox.mediaBox.cachedResourceRepresentation(fullSizeResource, representation: thumbnailSize ? CachedScaledVideoFirstFrameRepresentation(size: CGSize(width: 160.0, height: 160.0)) : CachedVideoFirstFrameRepresentation(), complete: false, fetch: false)
|
||||
let fetchedFullSize = postbox.mediaBox.cachedResourceRepresentation(fullSizeResource, representation: thumbnailSize ? CachedScaledVideoFirstFrameRepresentation(size: CGSize(width: 160.0, height: 160.0)) : CachedVideoFirstFrameRepresentation(), complete: false, fetch: true)
|
||||
let maybeFullSize = postbox.mediaBox.cachedResourceRepresentation(fullSizeResource, representation: thumbnailSize ? CachedScaledVideoFirstFrameRepresentation(size: CGSize(width: 160.0, height: 160.0)) : CachedVideoFirstFrameRepresentation(), complete: false, fetch: false, attemptSynchronously: synchronousLoad)
|
||||
let fetchedFullSize = postbox.mediaBox.cachedResourceRepresentation(fullSizeResource, representation: thumbnailSize ? CachedScaledVideoFirstFrameRepresentation(size: CGSize(width: 160.0, height: 160.0)) : CachedVideoFirstFrameRepresentation(), complete: false, fetch: true, attemptSynchronously: synchronousLoad)
|
||||
|
||||
let signal = maybeFullSize
|
||||
|> take(1)
|
||||
@ -306,7 +306,7 @@ private func chatMessageVideoDatas(postbox: Postbox, fileReference: FileMediaRef
|
||||
} else if let thumbnailResource = thumbnailResource {
|
||||
thumbnail = Signal { subscriber in
|
||||
let fetchedDisposable = fetchedMediaResource(postbox: postbox, reference: fileReference.resourceReference(thumbnailResource), statsCategory: .video).start()
|
||||
let thumbnailDisposable = postbox.mediaBox.resourceData(thumbnailResource).start(next: { next in
|
||||
let thumbnailDisposable = postbox.mediaBox.resourceData(thumbnailResource, attemptSynchronously: synchronousLoad).start(next: { next in
|
||||
subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []))
|
||||
}, error: subscriber.putError, completed: subscriber.putCompletion)
|
||||
|
||||
@ -1464,22 +1464,22 @@ func gifPaneVideoThumbnail(account: Account, videoReference: FileMediaReference)
|
||||
}
|
||||
}
|
||||
|
||||
func mediaGridMessageVideo(postbox: Postbox, videoReference: FileMediaReference, onlyFullSize: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
return internalMediaGridMessageVideo(postbox: postbox, videoReference: videoReference, onlyFullSize: onlyFullSize)
|
||||
func mediaGridMessageVideo(postbox: Postbox, videoReference: FileMediaReference, onlyFullSize: Bool = false, synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
return internalMediaGridMessageVideo(postbox: postbox, videoReference: videoReference, onlyFullSize: onlyFullSize, synchronousLoad: synchronousLoad)
|
||||
|> map {
|
||||
return $0.1
|
||||
}
|
||||
}
|
||||
|
||||
func internalMediaGridMessageVideo(postbox: Postbox, videoReference: FileMediaReference, imageReference: ImageMediaReference? = nil, onlyFullSize: Bool = false) -> Signal<(() -> CGSize?, (TransformImageArguments) -> DrawingContext?), NoError> {
|
||||
func internalMediaGridMessageVideo(postbox: Postbox, videoReference: FileMediaReference, imageReference: ImageMediaReference? = nil, onlyFullSize: Bool = false, synchronousLoad: Bool = false) -> Signal<(() -> CGSize?, (TransformImageArguments) -> DrawingContext?), NoError> {
|
||||
let signal: Signal<(Data?, (Data, String)?, Bool), NoError>
|
||||
if let imageReference = imageReference {
|
||||
signal = chatMessagePhotoDatas(postbox: postbox, photoReference: imageReference, tryAdditionalRepresentations: true)
|
||||
signal = chatMessagePhotoDatas(postbox: postbox, photoReference: imageReference, tryAdditionalRepresentations: true, synchronousLoad: synchronousLoad)
|
||||
|> map { (thumbnailData, fullSizeData, fullSizeComplete) -> (Data?, (Data, String)?, Bool) in
|
||||
return (thumbnailData, fullSizeData.flatMap({ ($0, "") }), fullSizeComplete)
|
||||
}
|
||||
} else {
|
||||
signal = chatMessageVideoDatas(postbox: postbox, fileReference: videoReference, onlyFullSize: onlyFullSize)
|
||||
signal = chatMessageVideoDatas(postbox: postbox, fileReference: videoReference, onlyFullSize: onlyFullSize, synchronousLoad: synchronousLoad)
|
||||
}
|
||||
|
||||
return signal
|
||||
|
@ -499,6 +499,8 @@ private final class SettingsControllerImpl: ItemListController<SettingsEntry>, S
|
||||
var switchToAccount: ((AccountRecordId) -> Void)?
|
||||
var addAccount: (() -> Void)?
|
||||
|
||||
weak var switchController: TabBarAccountSwitchController?
|
||||
|
||||
init(currentContext: AccountContext, contextValue: Promise<AccountContext>, state: Signal<(ItemListControllerState, (ItemListNodeState<SettingsEntry>, SettingsEntry.ItemGenerationArguments)), NoError>, tabBarItem: Signal<ItemListControllerTabBarItem, NoError>?, accountsAndPeers: Signal<((Account, Peer)?, [(Account, Peer, Int32)]), NoError>) {
|
||||
self.sharedContext = currentContext.sharedContext
|
||||
self.contextValue = contextValue
|
||||
@ -536,11 +538,27 @@ private final class SettingsControllerImpl: ItemListController<SettingsEntry>, S
|
||||
guard let (maybePrimary, other) = self.accountsAndPeersValue, let primary = maybePrimary else {
|
||||
return
|
||||
}
|
||||
self.sharedContext.mainWindow?.present(TabBarAccountSwitchController(sharedContext: self.sharedContext, accounts: (primary, other), canAddAccounts: other.count + 1 < maximumNumberOfAccounts, switchToAccount: { [weak self] id in
|
||||
let controller = TabBarAccountSwitchController(sharedContext: self.sharedContext, accounts: (primary, other), canAddAccounts: other.count + 1 < maximumNumberOfAccounts, switchToAccount: { [weak self] id in
|
||||
self?.switchToAccount?(id)
|
||||
}, addAccount: { [weak self] in
|
||||
self?.addAccount?()
|
||||
}, sourceNodes: sourceNodes), on: .root)
|
||||
}, sourceNodes: sourceNodes)
|
||||
self.switchController = controller
|
||||
self.sharedContext.mainWindow?.present(controller, on: .root)
|
||||
}
|
||||
|
||||
func updateTabBarPreviewingControllerPresentation(_ update: TabBarContainedControllerPresentationUpdate) {
|
||||
guard let switchController = switchController else {
|
||||
return
|
||||
}
|
||||
/*switch update {
|
||||
case .dismiss:
|
||||
switchController.dismiss()
|
||||
case .present:
|
||||
switchController.finishPresentation()
|
||||
case let .update(progress):
|
||||
switchController.update(progress)
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user