From d794ece01eee6aafb87a9a731dab75fef3ef48ad Mon Sep 17 00:00:00 2001 From: Peter <> Date: Fri, 15 Feb 2019 23:40:06 +0400 Subject: [PATCH] Optimized media grid synchronous loading --- TelegramUI/ChatHistoryGridNode.swift | 7 ++++--- TelegramUI/GridMessageItem.swift | 10 +++++----- TelegramUI/LogoutOptionsController.swift | 20 +++++++++++++++----- TelegramUI/PhotoResources.swift | 18 +++++++++--------- TelegramUI/SettingsController.swift | 22 ++++++++++++++++++++-- 5 files changed, 53 insertions(+), 24 deletions(-) diff --git a/TelegramUI/ChatHistoryGridNode.swift b/TelegramUI/ChatHistoryGridNode.swift index f584dc1c3e..0b6e133af5 100644 --- a/TelegramUI/ChatHistoryGridNode.swift +++ b/TelegramUI/ChatHistoryGridNode.swift @@ -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) } } } diff --git a/TelegramUI/GridMessageItem.swift b/TelegramUI/GridMessageItem.swift index 58b4f619db..d2a1c661f5 100644 --- a/TelegramUI/GridMessageItem.swift +++ b/TelegramUI/GridMessageItem.swift @@ -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)) diff --git a/TelegramUI/LogoutOptionsController.swift b/TelegramUI/LogoutOptionsController.swift index 9ef29c18f0..b66bf2b383 100644 --- a/TelegramUI/LogoutOptionsController.swift +++ b/TelegramUI/LogoutOptionsController.swift @@ -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.ItemGenerationArguments)) in + let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, context.sharedContext.accountManager.accessChallengeData()) + |> map { presentationData, accessChallengeData -> (ItemListControllerState, (ItemListNodeState, 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)) } diff --git a/TelegramUI/PhotoResources.swift b/TelegramUI/PhotoResources.swift index 71d51918ac..5d7279c479 100644 --- a/TelegramUI/PhotoResources.swift +++ b/TelegramUI/PhotoResources.swift @@ -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 diff --git a/TelegramUI/SettingsController.swift b/TelegramUI/SettingsController.swift index 1c339199f7..71afc8b210 100644 --- a/TelegramUI/SettingsController.swift +++ b/TelegramUI/SettingsController.swift @@ -499,6 +499,8 @@ private final class SettingsControllerImpl: ItemListController, S var switchToAccount: ((AccountRecordId) -> Void)? var addAccount: (() -> Void)? + weak var switchController: TabBarAccountSwitchController? + init(currentContext: AccountContext, contextValue: Promise, state: Signal<(ItemListControllerState, (ItemListNodeState, SettingsEntry.ItemGenerationArguments)), NoError>, tabBarItem: Signal?, accountsAndPeers: Signal<((Account, Peer)?, [(Account, Peer, Int32)]), NoError>) { self.sharedContext = currentContext.sharedContext self.contextValue = contextValue @@ -536,11 +538,27 @@ private final class SettingsControllerImpl: ItemListController, 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) + }*/ } }