mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Refactor PasswordSetupUI, PassportUI, GalleryUI and related modules
This commit is contained in:
966
submodules/GalleryUI/Sources/GalleryController.swift
Normal file
966
submodules/GalleryUI/Sources/GalleryController.swift
Normal file
@@ -0,0 +1,966 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import QuickLook
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import AsyncDisplayKit
|
||||
import TelegramCore
|
||||
import SafariServices
|
||||
import TelegramPresentationData
|
||||
import TextFormat
|
||||
import AccountContext
|
||||
import TelegramUniversalVideoContent
|
||||
import WebsiteType
|
||||
import OpenInExternalAppUI
|
||||
|
||||
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, TelegramMediaImage?)? {
|
||||
for media in message.media {
|
||||
if let result = galleryMediaForMedia(media: media) {
|
||||
return (result, nil)
|
||||
} else if let webpage = media as? TelegramMediaWebpage {
|
||||
switch webpage.content {
|
||||
case let .Loaded(content):
|
||||
if let embedUrl = content.embedUrl, !embedUrl.isEmpty {
|
||||
return (webpage, nil)
|
||||
} else if let file = content.file {
|
||||
if let result = galleryMediaForMedia(media: file) {
|
||||
return (result, content.image)
|
||||
}
|
||||
} else if let image = content.image {
|
||||
if let result = galleryMediaForMedia(media: image) {
|
||||
return (result, nil)
|
||||
}
|
||||
}
|
||||
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"
|
||||
]
|
||||
|
||||
public 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
|
||||
}
|
||||
for prefix in internalMimePrefixes {
|
||||
if type.hasPrefix(prefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private let textFont = Font.regular(16.0)
|
||||
private let boldFont = Font.bold(16.0)
|
||||
private let italicFont = Font.italic(16.0)
|
||||
private let boldItalicFont = Font.semiboldItalic(16.0)
|
||||
private let fixedFont = UIFont(name: "Menlo-Regular", size: 15.0) ?? textFont
|
||||
|
||||
public func galleryCaptionStringWithAppliedEntities(_ text: String, entities: [MessageTextEntity]) -> NSAttributedString {
|
||||
return stringWithAppliedEntities(text, entities: entities, baseColor: .white, linkColor: UIColor(rgb: 0x5ac8fa), baseFont: textFont, linkFont: textFont, boldFont: boldFont, italicFont: italicFont, boldItalicFont: boldItalicFont, fixedFont: fixedFont, blockQuoteFont: textFont, underlineLinks: false)
|
||||
}
|
||||
|
||||
private func galleryMessageCaptionText(_ message: Message) -> String {
|
||||
for media in message.media {
|
||||
if let _ = media as? TelegramMediaWebpage {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return message.text
|
||||
}
|
||||
|
||||
public func galleryItemForEntry(context: AccountContext, presentationData: PresentationData, entry: MessageHistoryEntry, isCentral: Bool = false, streamVideos: Bool, loopVideos: Bool = false, hideControls: Bool = false, fromPlayingVideo: Bool = false, landscape: Bool = false, timecode: Double? = nil, tempFilePath: String? = nil, playbackCompleted: @escaping () -> Void = {}, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void = { _ in }, openActionOptions: @escaping (GalleryControllerInteractionTapAction) -> Void = { _ in }) -> GalleryItem? {
|
||||
let message = entry.message
|
||||
let location = entry.location
|
||||
if let (media, mediaImage) = mediaForMessage(message: message) {
|
||||
if let _ = media as? TelegramMediaImage {
|
||||
return ChatImageGalleryItem(context: context, presentationData: presentationData, message: message, location: location, performAction: performAction, openActionOptions: openActionOptions)
|
||||
} else if let file = media as? TelegramMediaFile {
|
||||
if file.isVideo {
|
||||
let content: UniversalVideoContent
|
||||
if file.isAnimated {
|
||||
content = NativeVideoContent(id: .message(message.stableId, file.fileId), fileReference: .message(message: MessageReference(message), media: file), imageReference: mediaImage.flatMap({ ImageMediaReference.message(message: MessageReference(message), media: $0) }), loopVideo: true, enableSound: false, tempFilePath: tempFilePath)
|
||||
} else {
|
||||
if true || (file.mimeType == "video/mpeg4" || file.mimeType == "video/mov" || file.mimeType == "video/mp4") {
|
||||
content = NativeVideoContent(id: .message(message.stableId, file.fileId), fileReference: .message(message: MessageReference(message), media: file), imageReference: mediaImage.flatMap({ ImageMediaReference.message(message: MessageReference(message), media: $0) }), streamVideo: .conservative, loopVideo: loopVideos, tempFilePath: tempFilePath)
|
||||
} else {
|
||||
content = PlatformVideoContent(id: .message(message.id, message.stableId, file.fileId), fileReference: .message(message: MessageReference(message), media: file), streamVideo: streamVideos, loopVideo: loopVideos)
|
||||
}
|
||||
}
|
||||
|
||||
var entities: [MessageTextEntity] = []
|
||||
for attribute in message.attributes {
|
||||
if let attribute = attribute as? TextEntitiesMessageAttribute {
|
||||
entities = attribute.entities
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let text = galleryMessageCaptionText(message)
|
||||
if let result = addLocallyGeneratedEntities(text, enabledTypes: [.timecode], entities: entities, mediaDuration: file.duration.flatMap(Double.init)) {
|
||||
entities = result
|
||||
}
|
||||
|
||||
let caption = galleryCaptionStringWithAppliedEntities(text, entities: entities)
|
||||
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: GalleryItemOriginData(title: message.effectiveAuthor?.displayTitle, timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: caption, hideControls: hideControls, fromPlayingVideo: fromPlayingVideo, landscape: landscape, timecode: timecode, playbackCompleted: playbackCompleted, performAction: performAction, openActionOptions: openActionOptions)
|
||||
} else {
|
||||
if let fileName = file.fileName, (fileName as NSString).pathExtension.lowercased() == "json" {
|
||||
return ChatAnimationGalleryItem(context: context, presentationData: presentationData, message: message, location: location)
|
||||
}
|
||||
else if file.mimeType.hasPrefix("image/") && file.mimeType != "image/gif" {
|
||||
var pixelsCount: Int = 0
|
||||
if let dimensions = file.dimensions {
|
||||
pixelsCount = Int(dimensions.width) * Int(dimensions.height)
|
||||
}
|
||||
if (file.size == nil || file.size! < 4 * 1024 * 1024) && pixelsCount < 4096 * 4096 {
|
||||
return ChatImageGalleryItem(context: context, presentationData: presentationData, message: message, location: location, performAction: performAction, openActionOptions: openActionOptions)
|
||||
} else {
|
||||
return ChatDocumentGalleryItem(context: context, presentationData: presentationData, message: message, location: location)
|
||||
}
|
||||
} else if internalDocumentItemSupportsMimeType(file.mimeType, fileName: file.fileName) {
|
||||
return ChatDocumentGalleryItem(context: context, presentationData: presentationData, message: message, location: location)
|
||||
} else {
|
||||
return ChatExternalFileGalleryItem(context: context, presentationData: presentationData, message: message, location: location)
|
||||
}
|
||||
}
|
||||
} else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(webpageContent) = webpage.content {
|
||||
var content: UniversalVideoContent?
|
||||
switch websiteType(of: webpageContent.websiteName) {
|
||||
case .instagram where webpageContent.file != nil && webpageContent.image != nil && webpageContent.file!.isVideo:
|
||||
content = NativeVideoContent(id: .message(message.stableId, webpageContent.file?.id ?? webpage.webpageId), fileReference: .message(message: MessageReference(message), media: webpageContent.file!), imageReference: webpageContent.image.flatMap({ ImageMediaReference.message(message: MessageReference(message), media: $0) }), streamVideo: .conservative, enableSound: true)
|
||||
default:
|
||||
if let embedUrl = webpageContent.embedUrl, let image = webpageContent.image {
|
||||
if let file = webpageContent.file, file.isVideo {
|
||||
content = NativeVideoContent(id: .message(message.stableId, file.fileId), fileReference: .message(message: MessageReference(message), media: file), imageReference: mediaImage.flatMap({ ImageMediaReference.message(message: MessageReference(message), media: $0) }), streamVideo: .conservative, loopVideo: loopVideos, tempFilePath: tempFilePath)
|
||||
} else if URL(string: embedUrl)?.pathExtension == "mp4" {
|
||||
content = SystemVideoContent(url: embedUrl, imageReference: .webPage(webPage: WebpageReference(webpage), media: image), dimensions: webpageContent.embedSize ?? CGSize(width: 640.0, height: 640.0), duration: Int32(webpageContent.duration ?? 0))
|
||||
}
|
||||
}
|
||||
if content == nil, let webEmbedContent = WebEmbedVideoContent(webPage: webpage, webpageContent: webpageContent, forcedTimestamp: timecode.flatMap(Int.init)) {
|
||||
content = webEmbedContent
|
||||
}
|
||||
}
|
||||
if let content = content {
|
||||
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: GalleryItemOriginData(title: message.effectiveAuthor?.displayTitle, timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: NSAttributedString(string: ""), fromPlayingVideo: fromPlayingVideo, landscape: landscape, timecode: timecode, performAction: performAction, openActionOptions: openActionOptions)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public final class GalleryTransitionArguments {
|
||||
public let transitionNode: (ASDisplayNode, () -> (UIView?, UIView?))
|
||||
public let addToTransitionSurface: (UIView) -> Void
|
||||
|
||||
public init(transitionNode: (ASDisplayNode, () -> (UIView?, UIView?)), addToTransitionSurface: @escaping (UIView) -> Void) {
|
||||
self.transitionNode = transitionNode
|
||||
self.addToTransitionSurface = addToTransitionSurface
|
||||
}
|
||||
}
|
||||
|
||||
public final class GalleryControllerPresentationArguments {
|
||||
public let animated: Bool
|
||||
public let transitionArguments: (MessageId, Media) -> GalleryTransitionArguments?
|
||||
|
||||
public 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]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum GalleryControllerItemSource {
|
||||
case peerMessagesAtId(MessageId)
|
||||
case standaloneMessage(Message)
|
||||
}
|
||||
|
||||
public enum GalleryControllerInteractionTapAction {
|
||||
case url(url: String, concealed: Bool)
|
||||
case textMention(String)
|
||||
case peerMention(PeerId, String)
|
||||
case botCommand(String)
|
||||
case hashtag(String?, String)
|
||||
case timecode(Double, String)
|
||||
}
|
||||
|
||||
public enum GalleryControllerItemNodeAction {
|
||||
case timecode(Double)
|
||||
}
|
||||
|
||||
public class GalleryController: ViewController {
|
||||
public 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)
|
||||
public 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 context: AccountContext
|
||||
private var presentationData: PresentationData
|
||||
private let source: GalleryControllerItemSource
|
||||
|
||||
private let streamVideos: Bool
|
||||
|
||||
private let _ready = Promise<Bool>()
|
||||
override public var ready: Promise<Bool> {
|
||||
return self._ready
|
||||
}
|
||||
private var didSetReady = false
|
||||
|
||||
private var adjustedForInitialPreviewingLayout = false
|
||||
|
||||
public var temporaryDoNotWaitForReady = false
|
||||
private let fromPlayingVideo: Bool
|
||||
private let landscape: Bool
|
||||
private let timecode: Double?
|
||||
|
||||
private let accountInUseDisposable = MetaDisposable()
|
||||
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 centralItemRightBarButtonItems = Promise<[UIBarButtonItem]?>(nil)
|
||||
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?
|
||||
|
||||
private let actionInteraction: GalleryControllerActionInteraction?
|
||||
private var performAction: (GalleryControllerInteractionTapAction) -> Void
|
||||
private var openActionOptions: (GalleryControllerInteractionTapAction) -> Void
|
||||
|
||||
public init(context: AccountContext, source: GalleryControllerItemSource, invertItemOrder: Bool = false, streamSingleVideo: Bool = false, fromPlayingVideo: Bool = false, landscape: Bool = false, timecode: Double? = nil, synchronousLoad: Bool = false, replaceRootController: @escaping (ViewController, ValuePromise<Bool>?) -> Void, baseNavigationController: NavigationController?, actionInteraction: GalleryControllerActionInteraction? = nil) {
|
||||
self.context = context
|
||||
self.source = source
|
||||
self.replaceRootController = replaceRootController
|
||||
self.baseNavigationController = baseNavigationController
|
||||
self.actionInteraction = actionInteraction
|
||||
self.streamVideos = streamSingleVideo
|
||||
self.fromPlayingVideo = fromPlayingVideo
|
||||
self.landscape = landscape
|
||||
self.timecode = timecode
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
var performActionImpl: ((GalleryControllerInteractionTapAction) -> Void)?
|
||||
self.performAction = { action in
|
||||
performActionImpl?(action)
|
||||
}
|
||||
|
||||
var openActionOptionsImpl: ((GalleryControllerInteractionTapAction) -> Void)?
|
||||
self.openActionOptions = { action in
|
||||
openActionOptionsImpl?(action)
|
||||
}
|
||||
|
||||
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 = context.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 let tags = tagsForMessage(message!) {
|
||||
var excludeNamespaces: [MessageId.Namespace]
|
||||
if message!.id.namespace == Namespaces.Message.CloudScheduled {
|
||||
excludeNamespaces = [Namespaces.Message.Cloud, Namespaces.Message.Local, Namespaces.Message.SecretIncoming]
|
||||
} else {
|
||||
excludeNamespaces = [Namespaces.Message.CloudScheduled]
|
||||
}
|
||||
|
||||
let view = context.account.postbox.aroundMessageHistoryViewForLocation(.peer(message!.id.peerId), anchor: .index(message!.index), count: 50, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tags, excludeNamespaces: excludeNamespaces, orderStatistics: [.combinedLocation])
|
||||
|
||||
return view
|
||||
|> mapToSignal { (view, _, _) -> Signal<GalleryMessageHistoryView?, NoError> in
|
||||
let mapped = GalleryMessageHistoryView.view(view)
|
||||
return .single(mapped)
|
||||
}
|
||||
} else {
|
||||
return .single(GalleryMessageHistoryView.single(MessageHistoryEntry(message: message!, isRead: false, location: nil, monthLocation: nil, attributes: MutableMessageHistoryEntryAttributes(authorIsContact: false))))
|
||||
}
|
||||
case .standaloneMessage:
|
||||
return .single(GalleryMessageHistoryView.single(MessageHistoryEntry(message: message!, isRead: false, location: nil, monthLocation: nil, attributes: MutableMessageHistoryEntryAttributes(authorIsContact: false))))
|
||||
}
|
||||
}
|
||||
|> 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
|
||||
var centralEntryStableId: UInt32?
|
||||
loop: for i in 0 ..< entries.count {
|
||||
let message = entries[i].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
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
var isCentral = false
|
||||
if entry.message.stableId == strongSelf.centralEntryStableId {
|
||||
isCentral = true
|
||||
}
|
||||
if let item = galleryItemForEntry(context: context, presentationData: strongSelf.presentationData, entry: entry, isCentral: isCentral, streamVideos: streamSingleVideo, fromPlayingVideo: isCentral && fromPlayingVideo, landscape: isCentral && landscape, timecode: isCentral ? timecode : nil, performAction: strongSelf.performAction, openActionOptions: strongSelf.openActionOptions) {
|
||||
if isCentral {
|
||||
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(combineLatest(self.centralItemRightBarButtonItem.get(), self.centralItemRightBarButtonItems.get()).start(next: { [weak self] rightBarButtonItem, rightBarButtonItems in
|
||||
if let rightBarButtonItem = rightBarButtonItem {
|
||||
self?.navigationItem.rightBarButtonItem = rightBarButtonItem
|
||||
} else if let rightBarButtonItems = rightBarButtonItems {
|
||||
self?.navigationItem.rightBarButtonItems = rightBarButtonItems
|
||||
} else {
|
||||
self?.navigationItem.rightBarButtonItem = nil
|
||||
self?.navigationItem.rightBarButtonItems = nil
|
||||
}
|
||||
}))
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
let mediaManager = context.sharedContext.mediaManager
|
||||
self.hiddenMediaManagerIndex = mediaManager.galleryHiddenMediaManager.addSource(self._hiddenMedia.get()
|
||||
|> map { messageIdAndMedia in
|
||||
if let (messageId, media) = messageIdAndMedia {
|
||||
return .chat(context.account.id, messageId, media)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
})
|
||||
|
||||
performActionImpl = { [weak self] action in
|
||||
if let strongSelf = self {
|
||||
if case .timecode = action {
|
||||
} else {
|
||||
strongSelf.dismiss(forceAway: false)
|
||||
}
|
||||
switch action {
|
||||
case let .url(url, concealed):
|
||||
strongSelf.actionInteraction?.openUrl(url, concealed)
|
||||
case let .textMention(mention):
|
||||
strongSelf.actionInteraction?.openPeerMention(mention)
|
||||
case let .peerMention(peerId, _):
|
||||
strongSelf.actionInteraction?.openPeer(peerId)
|
||||
case let .botCommand(command):
|
||||
strongSelf.actionInteraction?.openBotCommand(command)
|
||||
case let .hashtag(peerName, hashtag):
|
||||
strongSelf.actionInteraction?.openHashtag(peerName, hashtag)
|
||||
case let .timecode(timecode, _):
|
||||
strongSelf.galleryNode.pager.centralItemNode()?.processAction(.timecode(timecode))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
openActionOptionsImpl = { [weak self] action in
|
||||
if let strongSelf = self {
|
||||
switch action {
|
||||
case let .url(url, _):
|
||||
var cleanUrl = url
|
||||
var canAddToReadingList = true
|
||||
let canOpenIn = availableOpenInOptions(context: strongSelf.context, item: .url(url: url)).count > 1
|
||||
let mailtoString = "mailto:"
|
||||
let telString = "tel:"
|
||||
var openText = strongSelf.presentationData.strings.Conversation_LinkDialogOpen
|
||||
var phoneNumber: String?
|
||||
if cleanUrl.hasPrefix(mailtoString) {
|
||||
canAddToReadingList = false
|
||||
cleanUrl = String(cleanUrl[cleanUrl.index(cleanUrl.startIndex, offsetBy: mailtoString.distance(from: mailtoString.startIndex, to: mailtoString.endIndex))...])
|
||||
} else if cleanUrl.hasPrefix(telString) {
|
||||
canAddToReadingList = false
|
||||
phoneNumber = String(cleanUrl[cleanUrl.index(cleanUrl.startIndex, offsetBy: telString.distance(from: telString.startIndex, to: telString.endIndex))...])
|
||||
cleanUrl = phoneNumber!
|
||||
openText = strongSelf.presentationData.strings.UserInfo_PhoneCall
|
||||
} else if canOpenIn {
|
||||
openText = strongSelf.presentationData.strings.Conversation_FileOpenIn
|
||||
}
|
||||
let actionSheet = ActionSheetController(presentationTheme: strongSelf.presentationData.theme)
|
||||
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ActionSheetTextItem(title: cleanUrl))
|
||||
items.append(ActionSheetButtonItem(title: openText, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
if let strongSelf = self {
|
||||
if canOpenIn {
|
||||
strongSelf.actionInteraction?.openUrlIn(url)
|
||||
} else {
|
||||
strongSelf.dismiss(forceAway: false)
|
||||
strongSelf.actionInteraction?.openUrl(url, false)
|
||||
}
|
||||
}
|
||||
}))
|
||||
if let phoneNumber = phoneNumber {
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_AddContact, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
if let strongSelf = self {
|
||||
strongSelf.dismiss(forceAway: false)
|
||||
strongSelf.actionInteraction?.addContact(phoneNumber)
|
||||
}
|
||||
}))
|
||||
}
|
||||
items.append(ActionSheetButtonItem(title: canAddToReadingList ? strongSelf.presentationData.strings.ShareMenu_CopyShareLink : strongSelf.presentationData.strings.Conversation_ContextMenuCopy, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
UIPasteboard.general.string = cleanUrl
|
||||
}))
|
||||
if canAddToReadingList {
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_AddToReadingList, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
if let link = URL(string: url) {
|
||||
let _ = try? SSReadingList.default()?.addItem(with: link, title: nil, previewText: nil)
|
||||
}
|
||||
}))
|
||||
}
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])])
|
||||
strongSelf.present(actionSheet, in: .window(.root))
|
||||
case let .peerMention(peerId, mention):
|
||||
let actionSheet = ActionSheetController(presentationTheme: strongSelf.presentationData.theme)
|
||||
var items: [ActionSheetItem] = []
|
||||
if !mention.isEmpty {
|
||||
items.append(ActionSheetTextItem(title: mention))
|
||||
}
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogOpen, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
if let strongSelf = self {
|
||||
strongSelf.dismiss(forceAway: false)
|
||||
strongSelf.actionInteraction?.openPeer(peerId)
|
||||
}
|
||||
}))
|
||||
if !mention.isEmpty {
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
UIPasteboard.general.string = mention
|
||||
}))
|
||||
}
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items:items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])])
|
||||
strongSelf.present(actionSheet, in: .window(.root))
|
||||
case let .textMention(mention):
|
||||
let actionSheet = ActionSheetController(presentationTheme: strongSelf.presentationData.theme)
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: [
|
||||
ActionSheetTextItem(title: mention),
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogOpen, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
if let strongSelf = self {
|
||||
strongSelf.dismiss(forceAway: false)
|
||||
strongSelf.actionInteraction?.openPeerMention(mention)
|
||||
}
|
||||
}),
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
UIPasteboard.general.string = mention
|
||||
})
|
||||
]), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])])
|
||||
strongSelf.present(actionSheet, in: .window(.root))
|
||||
case let .botCommand(command):
|
||||
let actionSheet = ActionSheetController(presentationTheme: strongSelf.presentationData.theme)
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ActionSheetTextItem(title: command))
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
UIPasteboard.general.string = command
|
||||
}))
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])])
|
||||
strongSelf.present(actionSheet, in: .window(.root))
|
||||
case let .hashtag(peerName, hashtag):
|
||||
let actionSheet = ActionSheetController(presentationTheme: strongSelf.presentationData.theme)
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: [
|
||||
ActionSheetTextItem(title: hashtag),
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogOpen, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
if let strongSelf = self {
|
||||
strongSelf.dismiss(forceAway: false)
|
||||
strongSelf.actionInteraction?.openHashtag(peerName, hashtag)
|
||||
}
|
||||
}),
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
UIPasteboard.general.string = hashtag
|
||||
})
|
||||
]), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])
|
||||
])
|
||||
strongSelf.present(actionSheet, in: .window(.root))
|
||||
case let .timecode(timecode, text):
|
||||
let actionSheet = ActionSheetController(presentationTheme: strongSelf.presentationData.theme)
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: [
|
||||
ActionSheetTextItem(title: text),
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogOpen, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
if let strongSelf = self {
|
||||
strongSelf.dismiss(forceAway: false)
|
||||
strongSelf.galleryNode.pager.centralItemNode()?.processAction(.timecode(timecode))
|
||||
}
|
||||
}),
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
UIPasteboard.general.string = text
|
||||
})
|
||||
]), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])
|
||||
])
|
||||
strongSelf.present(actionSheet, in: .window(.root))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
required init(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.accountInUseDisposable.dispose()
|
||||
self.disposable.dispose()
|
||||
self.centralItemAttributesDisposable.dispose()
|
||||
if let hiddenMediaManagerIndex = self.hiddenMediaManagerIndex {
|
||||
self.context.sharedContext.mediaManager.galleryHiddenMediaManager.removeSource(hiddenMediaManagerIndex)
|
||||
}
|
||||
}
|
||||
|
||||
@objc private 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 {
|
||||
let message = self.entries[centralItemNode.index].message
|
||||
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 public func loadDisplayNode() {
|
||||
let controllerInteraction = GalleryControllerInteraction(presentController: { [weak self] controller, arguments in
|
||||
if let strongSelf = self {
|
||||
strongSelf.present(controller, in: .window(.root), with: arguments, blockInteraction: true)
|
||||
}
|
||||
}, 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 {
|
||||
let message = strongSelf.entries[centralItemNode.index].message
|
||||
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 {
|
||||
var isCentral = false
|
||||
if entry.message.stableId == self.centralEntryStableId {
|
||||
isCentral = true
|
||||
}
|
||||
if let item = galleryItemForEntry(context: self.context, presentationData: self.presentationData, entry: entry, streamVideos: self.streamVideos, fromPlayingVideo: isCentral && self.fromPlayingVideo, landscape: isCentral && self.landscape, timecode: isCentral ? self.timecode : nil, performAction: self.performAction, openActionOptions: self.openActionOptions) {
|
||||
if isCentral {
|
||||
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 {
|
||||
let message = strongSelf.entries[index].message
|
||||
if 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.centralItemRightBarButtonItems.set(node.rightBarButtonItems())
|
||||
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 public func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
}
|
||||
|
||||
override public func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
var nodeAnimatesItself = false
|
||||
|
||||
if let centralItemNode = self.galleryNode.pager.centralItemNode() {
|
||||
let message = self.entries[centralItemNode.index].message
|
||||
self.centralItemTitle.set(centralItemNode.title())
|
||||
self.centralItemTitleView.set(centralItemNode.titleView())
|
||||
self.centralItemRightBarButtonItem.set(centralItemNode.rightBarButtonItem())
|
||||
self.centralItemRightBarButtonItems.set(centralItemNode.rightBarButtonItems())
|
||||
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
|
||||
if presentationArguments.animated {
|
||||
centralItemNode.animateIn(from: transitionArguments.transitionNode, addToTransitionSurface: transitionArguments.addToTransitionSurface)
|
||||
}
|
||||
|
||||
self._hiddenMedia.set(.single((message.id, media)))
|
||||
}
|
||||
centralItemNode.activateAsInitial()
|
||||
}
|
||||
}
|
||||
|
||||
if !self.isPresentedInPreviewingContext() {
|
||||
self.galleryNode.setControlsHidden(self.landscape, animated: false)
|
||||
if let presentationArguments = self.presentationArguments as? GalleryControllerPresentationArguments {
|
||||
if presentationArguments.animated {
|
||||
self.galleryNode.animateIn(animateContent: !nodeAnimatesItself)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.accountInUseDisposable.set(self.context.sharedContext.setAccountUserInterfaceInUse(self.context.account.id))
|
||||
}
|
||||
|
||||
override public func viewDidDisappear(_ animated: Bool) {
|
||||
super.viewDidDisappear(animated)
|
||||
|
||||
self.accountInUseDisposable.set(nil)
|
||||
}
|
||||
|
||||
override public 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, inVoiceOver: false), transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user