Swiftgram/TelegramUI/GalleryController.swift
Peter fc8fa045a6 Fixed Apple Pay
Added ability to download music without streaming
Added progress indicators for various blocking tasks
Fixed image gallery swipe to dismiss after zooming
Added online member count indication in supergroups
Fixed contact statuses in contact search
2018-10-13 03:31:39 +03:00

669 lines
33 KiB
Swift

import Foundation
import Display
import QuickLook
import Postbox
import SwiftSignalKit
import AsyncDisplayKit
import TelegramCore
private func tagsForMessage(_ message: Message) -> MessageTags? {
for media in message.media {
switch media {
case _ as TelegramMediaImage:
return .photoOrVideo
case let file as TelegramMediaFile:
if file.isVideo {
if !file.isAnimated {
return .photoOrVideo
}
} else if file.isVoice {
return .voiceOrInstantVideo
} else if file.isSticker {
return nil
} else {
return .file
}
default:
break
}
}
return nil
}
private func galleryMediaForMedia(media: Media) -> Media? {
if let media = media as? TelegramMediaImage {
return media
} else if let file = media as? TelegramMediaFile {
if file.mimeType.hasPrefix("audio/") {
return nil
} else if !file.isVideo && file.mimeType.hasPrefix("video/") {
return file
} else {
return file
}
}
return nil
}
private func mediaForMessage(message: Message) -> Media? {
for media in message.media {
if let result = galleryMediaForMedia(media: media) {
return result
} else if let webpage = media as? TelegramMediaWebpage {
switch webpage.content {
case let .Loaded(content):
if let embedUrl = content.embedUrl, !embedUrl.isEmpty {
return webpage
} else if let file = content.file {
if let result = galleryMediaForMedia(media: file) {
return result
}
} else if let image = content.image {
if let result = galleryMediaForMedia(media: image) {
return result
}
}
case .Pending:
break
}
}
}
return nil
}
private let internalExtensions = Set<String>([
"jpg",
"png",
"jpeg"
])
private let internalNotSupportedExtensions = Set<String>([
"djvu"
])
private let internalMimeTypes = Set<String>([
])
private let internalMimePrefixes: [String] = [
"image/jpeg",
"image/jpg",
"image/png"
]
private let supportedVideoMimeTypes = Set<String>([
"video/mp4",
"video/mpeg4",
"video/mov"
])
func internalDocumentItemSupportsMimeType(_ type: String, fileName: String?) -> Bool {
if let fileName = fileName {
let ext = (fileName as NSString).pathExtension
if internalExtensions.contains(ext.lowercased()) {
return true
}
if internalNotSupportedExtensions.contains(ext.lowercased()) {
return false
}
}
if internalMimeTypes.contains(type) {
return true
}
if supportedVideoMimeTypes.contains(type) {
return true
}
for prefix in internalMimePrefixes {
if type.hasPrefix(prefix) {
return true
}
}
return false
}
func galleryItemForEntry(account: Account, presentationData: PresentationData, entry: MessageHistoryEntry, streamVideos: Bool, loopVideos: Bool = false, hideControls: Bool = false, playbackCompleted: @escaping () -> Void = {}) -> GalleryItem? {
switch entry {
case let .MessageEntry(message, _, location, _):
if let media = mediaForMessage(message: message) {
if let _ = media as? TelegramMediaImage {
return ChatImageGalleryItem(account: account, presentationData: presentationData, message: message, location: location)
} else if let file = media as? TelegramMediaFile {
if file.isVideo || supportedVideoMimeTypes.contains(file.mimeType) {
let content: UniversalVideoContent
if file.isAnimated {
content = NativeVideoContent(id: .message(message.id, message.stableId + 1, file.fileId), fileReference: .message(message: MessageReference(message), media: file), streamVideo: streamVideos, loopVideo: true, enableSound: false)
} else {
if true || (file.mimeType == "video/mpeg4" || file.mimeType == "video/mov" || file.mimeType == "video/mp4") {
content = NativeVideoContent(id: .message(message.id, message.stableId, file.fileId), fileReference: .message(message: MessageReference(message), media: file), streamVideo: streamVideos, loopVideo: loopVideos)
} else {
content = PlatformVideoContent(id: .message(message.id, message.stableId, file.fileId), fileReference: .message(message: MessageReference(message), media: file), streamVideo: streamVideos, loopVideo: loopVideos)
}
}
return UniversalVideoGalleryItem(account: account, presentationData: presentationData, content: content, originData: GalleryItemOriginData(title: message.author?.displayTitle, timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: message.text, hideControls: hideControls, playbackCompleted: playbackCompleted)
} else {
if file.mimeType.hasPrefix("image/") && file.mimeType != "image/gif" {
if file.size == nil || file.size! < 5 * 1024 * 1024 {
return ChatImageGalleryItem(account: account, presentationData: presentationData, message: message, location: location)
} else {
return ChatDocumentGalleryItem(account: account, presentationData: presentationData, message: message, location: location)
}
} else if internalDocumentItemSupportsMimeType(file.mimeType, fileName: file.fileName) {
return ChatDocumentGalleryItem(account: account, presentationData: presentationData, message: message, location: location)
} else {
return ChatExternalFileGalleryItem(account: account, presentationData: presentationData, message: message, location: location)
}
}
} else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(webpageContent) = webpage.content {
switch websiteType(of: webpageContent) {
case .instagram where webpageContent.file != nil && webpageContent.image != nil && webpageContent.file!.isVideo:
return UniversalVideoGalleryItem(account: account, presentationData: presentationData, content: NativeVideoContent(id: NativeVideoContentId.message(message.id, message.stableId, webpage.webpageId), fileReference: .message(message: MessageReference(message), media: webpageContent.file!), streamVideo: true, enableSound: true), originData: GalleryItemOriginData(title: message.author?.displayTitle, timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: "")
//return UniversalVideoGalleryItem(account: account, theme: theme, strings: strings, content: SystemVideoContent(url: webpageContent.embedUrl!, image: webpageContent.image!, dimensions: webpageContent.embedSize ?? CGSize(width: 640.0, height: 640.0), duration: Int32(webpageContent.duration ?? 0)), originData: GalleryItemOriginData(title: message.author?.displayTitle, timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: "")
/*case .twitter where webpageContent.embedUrl != nil && webpageContent.image != nil:
return UniversalVideoGalleryItem(account: account, theme: theme, strings: strings, content: SystemVideoContent(url: webpageContent.embedUrl!, image: webpageContent.image!, dimensions: webpageContent.embedSize ?? CGSize(width: 640.0, height: 640.0), duration: Int32(webpageContent.duration ?? 0)), originData: GalleryItemOriginData(title: message.author?.displayTitle, timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: "")*/
default:
if let content = WebEmbedVideoContent(webPage: webpage, webpageContent: webpageContent) {
return UniversalVideoGalleryItem(account: account, presentationData: presentationData, content: content, originData: GalleryItemOriginData(title: message.author?.displayTitle, timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: "")
}
}
}
}
default:
break
}
return nil
}
final class GalleryTransitionArguments {
let transitionNode: (ASDisplayNode, () -> UIView?)
let addToTransitionSurface: (UIView) -> Void
init(transitionNode: (ASDisplayNode, () -> UIView?), addToTransitionSurface: @escaping (UIView) -> Void) {
self.transitionNode = transitionNode
self.addToTransitionSurface = addToTransitionSurface
}
}
final class GalleryControllerPresentationArguments {
let animated: Bool
let transitionArguments: (MessageId, Media) -> GalleryTransitionArguments?
init(animated: Bool = true, transitionArguments: @escaping (MessageId, Media) -> GalleryTransitionArguments?) {
self.animated = animated
self.transitionArguments = transitionArguments
}
}
private enum GalleryMessageHistoryView {
case view(MessageHistoryView)
case single(MessageHistoryEntry)
var entries: [MessageHistoryEntry] {
switch self {
case let .view(view):
return view.entries
case let .single(entry):
return [entry]
}
}
}
enum GalleryControllerItemSource {
case peerMessagesAtId(MessageId)
case standaloneMessage(Message)
}
class GalleryController: ViewController {
static let darkNavigationTheme = NavigationBarTheme(buttonColor: .white, disabledButtonColor: UIColor(rgb: 0x525252), primaryTextColor: .white, backgroundColor: UIColor(white: 0.0, alpha: 0.6), separatorColor: UIColor(white: 0.0, alpha: 0.8), badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear)
static let lightNavigationTheme = NavigationBarTheme(buttonColor: UIColor(rgb: 0x007ee5), disabledButtonColor: UIColor(rgb: 0xd0d0d0), primaryTextColor: .black, backgroundColor: UIColor(red: 0.968626451, green: 0.968626451, blue: 0.968626451, alpha: 1.0), separatorColor: UIColor(red: 0.6953125, green: 0.6953125, blue: 0.6953125, alpha: 1.0), badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear)
private var galleryNode: GalleryControllerNode {
return self.displayNode as! GalleryControllerNode
}
private let account: Account
private var presentationData: PresentationData
private let streamVideos: Bool
private let _ready = Promise<Bool>()
override var ready: Promise<Bool> {
return self._ready
}
private var didSetReady = false
private var adjustedForInitialPreviewingLayout = false
var temporaryDoNotWaitForReady = false
private let disposable = MetaDisposable()
private var entries: [MessageHistoryEntry] = []
private var centralEntryStableId: UInt32?
private let centralItemTitle = Promise<String>()
private let centralItemTitleView = Promise<UIView?>()
private let centralItemRightBarButtonItem = Promise<UIBarButtonItem?>()
private let centralItemNavigationStyle = Promise<GalleryItemNodeNavigationStyle>()
private let centralItemFooterContentNode = Promise<GalleryFooterContentNode?>()
private let centralItemAttributesDisposable = DisposableSet();
private let _hiddenMedia = Promise<(MessageId, Media)?>(nil)
private let replaceRootController: (ViewController, ValuePromise<Bool>?) -> Void
private let baseNavigationController: NavigationController?
private var hiddenMediaManagerIndex: Int?
init(account: Account, source: GalleryControllerItemSource, invertItemOrder: Bool = false, streamSingleVideo: Bool = false, synchronousLoad: Bool = false, replaceRootController: @escaping (ViewController, ValuePromise<Bool>?) -> Void, baseNavigationController: NavigationController?) {
self.account = account
self.replaceRootController = replaceRootController
self.baseNavigationController = baseNavigationController
self.streamVideos = streamSingleVideo
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: GalleryController.darkNavigationTheme, strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)))
let backItem = UIBarButtonItem(backButtonAppearanceWithTitle: presentationData.strings.Common_Back, target: self, action: #selector(self.donePressed))
self.navigationItem.leftBarButtonItem = backItem
self.statusBar.statusBarStyle = .White
let message: Signal<Message?, NoError>
switch source {
case let .peerMessagesAtId(messageId):
message = account.postbox.messageAtId(messageId)
case let .standaloneMessage(m):
message = .single(m)
}
let messageView = message
|> filter({ $0 != nil })
|> mapToSignal { message -> Signal<GalleryMessageHistoryView?, NoError> in
switch source {
case .peerMessagesAtId:
if !streamSingleVideo, let tags = tagsForMessage(message!) {
let view = account.postbox.aroundMessageHistoryViewForLocation(.peer(message!.id.peerId), index: .message(MessageIndex(message!)), anchorIndex: .message(MessageIndex(message!)), count: 50, clipHoles: false, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tags, orderStatistics: [.combinedLocation])
return view
|> mapToSignal { (view, _, _) -> Signal<GalleryMessageHistoryView?, NoError> in
let mapped = GalleryMessageHistoryView.view(view)
return .single(mapped)
}
} else {
return .single(GalleryMessageHistoryView.single(MessageHistoryEntry.MessageEntry(message!, false, nil, nil)))
}
case .standaloneMessage:
return .single(GalleryMessageHistoryView.single(MessageHistoryEntry.MessageEntry(message!, false, nil, nil)))
}
}
|> take(1)
let semaphore: DispatchSemaphore?
if synchronousLoad {
semaphore = DispatchSemaphore(value: 0)
} else {
semaphore = nil
}
let syncResult = Atomic<(Bool, (() -> Void)?)>(value: (false, nil))
self.disposable.set(messageView.start(next: { [weak self] view in
let f: () -> Void = {
if let strongSelf = self {
if let view = view {
let entries = view.entries.filter { entry in
if case .MessageEntry = entry {
return true
} else {
return false
}
}
var centralEntryStableId: UInt32?
loop: for i in 0 ..< entries.count {
switch entries[i] {
case let .MessageEntry(message, _, _, _):
switch source {
case let .peerMessagesAtId(messageId):
if message.id == messageId {
centralEntryStableId = message.stableId
break loop
}
case let .standaloneMessage(m):
if message.id == m.id {
centralEntryStableId = message.stableId
break loop
}
}
default:
break
}
}
if invertItemOrder {
strongSelf.entries = entries.reversed()
if let centralEntryStableId = centralEntryStableId {
strongSelf.centralEntryStableId = centralEntryStableId
}
} else {
strongSelf.entries = entries
strongSelf.centralEntryStableId = centralEntryStableId
}
if strongSelf.isViewLoaded {
var items: [GalleryItem] = []
var centralItemIndex: Int?
for entry in strongSelf.entries {
if let item = galleryItemForEntry(account: account, presentationData: strongSelf.presentationData, entry: entry, streamVideos: streamSingleVideo) {
if case let .MessageEntry(message, _, _, _) = entry, message.stableId == strongSelf.centralEntryStableId {
centralItemIndex = items.count
}
items.append(item)
}
}
strongSelf.galleryNode.pager.replaceItems(items, centralItemIndex: centralItemIndex)
if strongSelf.temporaryDoNotWaitForReady {
strongSelf.didSetReady = true
strongSelf._ready.set(.single(true))
} else {
let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in
strongSelf?.didSetReady = true
}
strongSelf._ready.set(ready |> map { true })
}
}
}
}
}
var process = false
let _ = syncResult.modify { processed, _ in
if !processed {
return (processed, f)
}
process = true
return (true, nil)
}
semaphore?.signal()
if process {
Queue.mainQueue().async {
f()
}
}
}))
if let semaphore = semaphore {
let _ = semaphore.wait(timeout: DispatchTime.now() + 1.0)
}
var syncResultApply: (() -> Void)?
let _ = syncResult.modify { processed, f in
syncResultApply = f
return (true, nil)
}
syncResultApply?()
self.centralItemAttributesDisposable.add(self.centralItemTitle.get().start(next: { [weak self] title in
self?.navigationItem.title = title
}))
self.centralItemAttributesDisposable.add(self.centralItemTitleView.get().start(next: { [weak self] titleView in
self?.navigationItem.titleView = titleView
}))
self.centralItemAttributesDisposable.add(self.centralItemRightBarButtonItem.get().start(next: { [weak self] rightBarButtonItem in
self?.navigationItem.rightBarButtonItem = rightBarButtonItem
}))
self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode in
self?.galleryNode.updatePresentationState({
$0.withUpdatedFooterContentNode(footerContentNode)
}, transition: .immediate)
}))
self.centralItemAttributesDisposable.add(self.centralItemNavigationStyle.get().start(next: { [weak self] style in
if let strongSelf = self {
switch style {
case .dark:
strongSelf.statusBar.statusBarStyle = .White
strongSelf.navigationBar?.updatePresentationData(NavigationBarPresentationData(theme: GalleryController.darkNavigationTheme, strings: NavigationBarStrings(presentationStrings: strongSelf.presentationData.strings)))
strongSelf.galleryNode.backgroundNode.backgroundColor = UIColor.black
strongSelf.galleryNode.isBackgroundExtendedOverNavigationBar = true
case .light:
strongSelf.statusBar.statusBarStyle = .Black
strongSelf.navigationBar?.updatePresentationData(NavigationBarPresentationData(theme: GalleryController.darkNavigationTheme, strings: NavigationBarStrings(presentationStrings: strongSelf.presentationData.strings)))
strongSelf.galleryNode.backgroundNode.backgroundColor = UIColor(rgb: 0xbdbdc2)
strongSelf.galleryNode.isBackgroundExtendedOverNavigationBar = false
}
}
}))
if let mediaManager = account.telegramApplicationContext.mediaManager {
self.hiddenMediaManagerIndex = mediaManager.galleryHiddenMediaManager.addSource(self._hiddenMedia.get() |> map { messageIdAndMedia in
if let (messageId, media) = messageIdAndMedia {
return .chat(messageId, media)
} else {
return nil
}
})
}
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.disposable.dispose()
self.centralItemAttributesDisposable.dispose()
if let hiddenMediaManagerIndex = self.hiddenMediaManagerIndex, let mediaManager = self.account.telegramApplicationContext.mediaManager {
mediaManager.galleryHiddenMediaManager.removeSource(hiddenMediaManagerIndex)
}
}
@objc func donePressed() {
self.dismiss(forceAway: false)
}
private func dismiss(forceAway: Bool) {
var animatedOutNode = true
var animatedOutInterface = false
let completion = { [weak self] in
if animatedOutNode && animatedOutInterface {
self?._hiddenMedia.set(.single(nil))
self?.presentingViewController?.dismiss(animated: false, completion: nil)
}
}
if let centralItemNode = self.galleryNode.pager.centralItemNode(), let presentationArguments = self.presentationArguments as? GalleryControllerPresentationArguments {
if case let .MessageEntry(message, _, _, _) = self.entries[centralItemNode.index] {
if let media = mediaForMessage(message: message), let transitionArguments = presentationArguments.transitionArguments(message.id, media), !forceAway {
animatedOutNode = false
centralItemNode.animateOut(to: transitionArguments.transitionNode, addToTransitionSurface: transitionArguments.addToTransitionSurface, completion: {
animatedOutNode = true
completion()
})
}
}
}
self.galleryNode.animateOut(animateContent: animatedOutNode, completion: {
animatedOutInterface = true
completion()
})
}
override func loadDisplayNode() {
let controllerInteraction = GalleryControllerInteraction(presentController: { [weak self] controller, arguments in
if let strongSelf = self {
strongSelf.present(controller, in: .window(.root), with: arguments)
}
}, dismissController: { [weak self] in
self?.dismiss(forceAway: true)
}, replaceRootController: { [weak self] controller, ready in
if let strongSelf = self {
strongSelf.replaceRootController(controller, ready)
}
})
self.displayNode = GalleryControllerNode(controllerInteraction: controllerInteraction)
self.displayNodeDidLoad()
self.galleryNode.statusBar = self.statusBar
self.galleryNode.navigationBar = self.navigationBar
self.galleryNode.transitionDataForCentralItem = { [weak self] in
if let strongSelf = self {
if let centralItemNode = strongSelf.galleryNode.pager.centralItemNode(), let presentationArguments = strongSelf.presentationArguments as? GalleryControllerPresentationArguments {
if case let .MessageEntry(message, _, _, _) = strongSelf.entries[centralItemNode.index] {
if let media = mediaForMessage(message: message), let transitionArguments = presentationArguments.transitionArguments(message.id, media) {
return (transitionArguments.transitionNode, transitionArguments.addToTransitionSurface)
}
}
}
}
return nil
}
self.galleryNode.dismiss = { [weak self] in
self?._hiddenMedia.set(.single(nil))
self?.presentingViewController?.dismiss(animated: false, completion: nil)
}
self.galleryNode.beginCustomDismiss = { [weak self] in
if let strongSelf = self {
strongSelf._hiddenMedia.set(.single(nil))
var animatedOutNode = true
var animatedOutInterface = false
let completion = {
if animatedOutNode && animatedOutInterface {
//self?.presentingViewController?.dismiss(animated: false, completion: nil)
}
}
strongSelf.galleryNode.animateOut(animateContent: animatedOutNode, completion: {
animatedOutInterface = true
//completion()
})
}
}
self.galleryNode.completeCustomDismiss = { [weak self] in
self?._hiddenMedia.set(.single(nil))
self?.presentingViewController?.dismiss(animated: false, completion: nil)
}
let baseNavigationController = self.baseNavigationController
self.galleryNode.baseNavigationController = { [weak baseNavigationController] in
return baseNavigationController
}
var items: [GalleryItem] = []
var centralItemIndex: Int?
for entry in self.entries {
if let item = galleryItemForEntry(account: account, presentationData: self.presentationData, entry: entry, streamVideos: self.streamVideos) {
if case let .MessageEntry(message, _, _, _) = entry, message.stableId == self.centralEntryStableId {
centralItemIndex = items.count
}
items.append(item)
}
}
self.galleryNode.pager.replaceItems(items, centralItemIndex: centralItemIndex)
self.galleryNode.pager.centralItemIndexUpdated = { [weak self] index in
if let strongSelf = self {
var hiddenItem: (MessageId, Media)?
if let index = index {
if case let .MessageEntry(message, _, _, _) = strongSelf.entries[index], let media = mediaForMessage(message: message) {
hiddenItem = (message.id, media)
}
if let node = strongSelf.galleryNode.pager.centralItemNode() {
strongSelf.centralItemTitle.set(node.title())
strongSelf.centralItemTitleView.set(node.titleView())
strongSelf.centralItemRightBarButtonItem.set(node.rightBarButtonItem())
strongSelf.centralItemNavigationStyle.set(node.navigationStyle())
strongSelf.centralItemFooterContentNode.set(node.footerContent())
}
}
if strongSelf.didSetReady {
strongSelf._hiddenMedia.set(.single(hiddenItem))
}
}
}
if !self.entries.isEmpty && !self.didSetReady {
if self.temporaryDoNotWaitForReady {
self.didSetReady = true
self._ready.set(.single(true))
} else {
let ready = self.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak self] _ in
self?.didSetReady = true
}
self._ready.set(ready |> map { true })
}
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
var nodeAnimatesItself = false
if let centralItemNode = self.galleryNode.pager.centralItemNode() {
if case let .MessageEntry(message, _, _, _) = self.entries[centralItemNode.index] {
self.centralItemTitle.set(centralItemNode.title())
self.centralItemTitleView.set(centralItemNode.titleView())
self.centralItemRightBarButtonItem.set(centralItemNode.rightBarButtonItem())
self.centralItemNavigationStyle.set(centralItemNode.navigationStyle())
self.centralItemFooterContentNode.set(centralItemNode.footerContent())
if let media = mediaForMessage(message: message) {
if let presentationArguments = self.presentationArguments as? GalleryControllerPresentationArguments, let transitionArguments = presentationArguments.transitionArguments(message.id, media) {
nodeAnimatesItself = true
centralItemNode.activateAsInitial()
if presentationArguments.animated {
centralItemNode.animateIn(from: transitionArguments.transitionNode, addToTransitionSurface: transitionArguments.addToTransitionSurface)
}
self._hiddenMedia.set(.single((message.id, media)))
} else if self.isPresentedInPreviewingContext() {
centralItemNode.activateAsInitial()
}
}
}
}
if !self.isPresentedInPreviewingContext() {
self.galleryNode.setControlsHidden(false, animated: false)
if let presentationArguments = self.presentationArguments as? GalleryControllerPresentationArguments {
if presentationArguments.animated {
self.galleryNode.animateIn(animateContent: !nodeAnimatesItself)
}
}
}
}
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition)
self.galleryNode.frame = CGRect(origin: CGPoint(), size: layout.size)
self.galleryNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition)
if !self.adjustedForInitialPreviewingLayout && self.isPresentedInPreviewingContext() {
self.adjustedForInitialPreviewingLayout = true
self.galleryNode.setControlsHidden(true, animated: false)
if let centralItemNode = self.galleryNode.pager.centralItemNode(), let itemSize = centralItemNode.contentSize() {
self.preferredContentSize = itemSize.aspectFitted(self.view.bounds.size)
self.containerLayoutUpdated(ContainerViewLayout(size: self.preferredContentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
}
}
}
}