mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
485 lines
31 KiB
Swift
485 lines
31 KiB
Swift
import Foundation
|
|
import Display
|
|
import AsyncDisplayKit
|
|
import Postbox
|
|
import TelegramCore
|
|
import SwiftSignalKit
|
|
import PassKit
|
|
import Lottie
|
|
import TelegramUIPreferences
|
|
import TelegramPresentationData
|
|
import AccountContext
|
|
import GalleryUI
|
|
import InstantPageUI
|
|
import LocationUI
|
|
import StickerPackPreviewUI
|
|
import PeerAvatarGalleryUI
|
|
import PeerInfoUI
|
|
import SettingsUI
|
|
import AlertUI
|
|
import PresentationDataUtils
|
|
import ShareController
|
|
import UndoUI
|
|
import WebsiteType
|
|
import GalleryData
|
|
import StoryContainerScreen
|
|
import WallpaperGalleryScreen
|
|
import BrowserUI
|
|
|
|
func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
|
|
var story: TelegramMediaStory?
|
|
for media in params.message.media {
|
|
if let media = media as? TelegramMediaStory {
|
|
story = media
|
|
} else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content, content.story != nil {
|
|
story = content.story
|
|
}
|
|
}
|
|
|
|
if let story {
|
|
let navigationController = params.navigationController
|
|
let context = params.context
|
|
let storyContent = SingleStoryContentContextImpl(context: params.context, storyId: story.storyId, readGlobally: true)
|
|
let _ = (storyContent.state
|
|
|> take(1)
|
|
|> deliverOnMainQueue).startStandalone(next: { [weak navigationController] _ in
|
|
var transitionIn: StoryContainerScreen.TransitionIn? = nil
|
|
|
|
var selectedTransitionNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?
|
|
selectedTransitionNode = params.transitionNode(params.message.id, story, true)
|
|
|
|
if let selectedTransitionNode {
|
|
var cornerRadius: CGFloat = 0.0
|
|
if let imageNode = selectedTransitionNode.0 as? TransformImageNode, let currentArguments = imageNode.currentArguments {
|
|
cornerRadius = currentArguments.corners.topLeft.radius
|
|
}
|
|
transitionIn = StoryContainerScreen.TransitionIn(
|
|
sourceView: selectedTransitionNode.0.view,
|
|
sourceRect: selectedTransitionNode.1,
|
|
sourceCornerRadius: cornerRadius,
|
|
sourceIsAvatar: false
|
|
)
|
|
}
|
|
|
|
let hiddenMediaSource = params.context.sharedContext.mediaManager.galleryHiddenMediaManager.addSource(.single(GalleryHiddenMediaId.chat(params.context.account.id, params.message.id, story)))
|
|
|
|
let storyContainerScreen = StoryContainerScreen(
|
|
context: context,
|
|
content: storyContent,
|
|
transitionIn: transitionIn,
|
|
transitionOut: { _, _ in
|
|
var transitionOut: StoryContainerScreen.TransitionOut? = nil
|
|
|
|
var selectedTransitionNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?
|
|
selectedTransitionNode = params.transitionNode(params.message.id, story, true)
|
|
if let selectedTransitionNode {
|
|
var cornerRadius: CGFloat = 0.0
|
|
if let imageNode = selectedTransitionNode.0 as? TransformImageNode, let currentArguments = imageNode.currentArguments {
|
|
cornerRadius = currentArguments.corners.topLeft.radius
|
|
}
|
|
|
|
transitionOut = StoryContainerScreen.TransitionOut(
|
|
destinationView: selectedTransitionNode.0.view,
|
|
transitionView: StoryContainerScreen.TransitionView(
|
|
makeView: {
|
|
let view = UIView()
|
|
if let transitionView = selectedTransitionNode.2().0 {
|
|
transitionView.layer.anchorPoint = CGPoint()
|
|
view.addSubview(transitionView)
|
|
}
|
|
return view
|
|
},
|
|
updateView: { view, state, transition in
|
|
guard let view = view.subviews.first else {
|
|
return
|
|
}
|
|
if state.progress == 0.0 {
|
|
view.frame = CGRect(origin: CGPoint(), size: state.destinationSize)
|
|
}
|
|
|
|
let toScaleX = state.sourceSize.width / state.destinationSize.width
|
|
let toScaleY = state.sourceSize.height / state.destinationSize.height
|
|
let fromScaleX: CGFloat = 1.0
|
|
let fromScaleY: CGFloat = 1.0
|
|
let scaleX = toScaleX.interpolate(to: fromScaleX, amount: state.progress)
|
|
let scaleY = toScaleY.interpolate(to: fromScaleY, amount: state.progress)
|
|
transition.setTransform(view: view, transform: CATransform3DMakeScale(scaleX, scaleY, 1.0))
|
|
},
|
|
insertCloneTransitionView: { view in
|
|
params.addToTransitionSurface(view)
|
|
}
|
|
),
|
|
destinationRect: selectedTransitionNode.1,
|
|
destinationCornerRadius: cornerRadius,
|
|
destinationIsAvatar: false,
|
|
completed: {
|
|
params.context.sharedContext.mediaManager.galleryHiddenMediaManager.removeSource(hiddenMediaSource)
|
|
}
|
|
)
|
|
} else {
|
|
params.context.sharedContext.mediaManager.galleryHiddenMediaManager.removeSource(hiddenMediaSource)
|
|
}
|
|
|
|
return transitionOut
|
|
}
|
|
)
|
|
navigationController?.pushViewController(storyContainerScreen)
|
|
})
|
|
return true
|
|
}
|
|
|
|
if let mediaData = chatMessageGalleryControllerData(context: params.context, chatLocation: params.chatLocation, chatFilterTag: params.chatFilterTag, chatLocationContextHolder: params.chatLocationContextHolder, message: params.message, mediaIndex: params.mediaIndex, navigationController: params.navigationController, standalone: params.standalone, reverseMessageGalleryOrder: params.reverseMessageGalleryOrder, mode: params.mode, source: params.gallerySource, synchronousLoad: false, actionInteraction: params.actionInteraction) {
|
|
switch mediaData {
|
|
case let .url(url):
|
|
params.openUrl(url)
|
|
return true
|
|
case let .pass(file):
|
|
let _ = (params.context.account.postbox.mediaBox.resourceData(file.resource, option: .complete(waitUntilFetchStatus: true))
|
|
|> take(1)
|
|
|> deliverOnMainQueue).startStandalone(next: { data in
|
|
guard let navigationController = params.navigationController else {
|
|
return
|
|
}
|
|
if data.complete, let content = try? Data(contentsOf: URL(fileURLWithPath: data.path)) {
|
|
if let pass = try? PKPass(data: content), let controller = PKAddPassesViewController(pass: pass) {
|
|
if let window = navigationController.view.window {
|
|
controller.popoverPresentationController?.sourceView = window
|
|
controller.popoverPresentationController?.sourceRect = CGRect(origin: CGPoint(x: window.bounds.width / 2.0, y: window.bounds.size.height - 1.0), size: CGSize(width: 1.0, height: 1.0))
|
|
window.rootViewController?.present(controller, animated: true)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
return true
|
|
case let .instantPage(gallery, centralIndex, galleryMedia):
|
|
params.setupTemporaryHiddenMedia(gallery.hiddenMedia |> map { a -> Any? in a }, centralIndex, galleryMedia)
|
|
|
|
params.dismissInput()
|
|
params.present(gallery, InstantPageGalleryControllerPresentationArguments(transitionArguments: { entry in
|
|
var selectedTransitionNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?
|
|
if entry.index == centralIndex {
|
|
selectedTransitionNode = params.transitionNode(params.message.id, galleryMedia, false)
|
|
}
|
|
if let selectedTransitionNode = selectedTransitionNode {
|
|
return GalleryTransitionArguments(transitionNode: selectedTransitionNode, addToTransitionSurface: params.addToTransitionSurface)
|
|
}
|
|
return nil
|
|
}), .window(.root))
|
|
return true
|
|
case .map:
|
|
params.dismissInput()
|
|
|
|
let controllerParams = LocationViewParams(sendLiveLocation: { location in
|
|
let outMessage: EnqueueMessage = .message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: location), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])
|
|
params.enqueueMessage(outMessage)
|
|
}, stopLiveLocation: { messageId in
|
|
params.context.liveLocationManager?.cancelLiveLocation(peerId: messageId?.peerId ?? params.message.id.peerId)
|
|
}, openUrl: params.openUrl, openPeer: { peer in
|
|
params.openPeer(peer._asPeer(), .info(nil))
|
|
}, showAll: params.modal)
|
|
let controller = LocationViewController(context: params.context, updatedPresentationData: params.updatedPresentationData, subject: EngineMessage(params.message), params: controllerParams)
|
|
controller.navigationPresentation = .modal
|
|
params.navigationController?.pushViewController(controller)
|
|
return true
|
|
case let .stickerPack(reference):
|
|
let controller = StickerPackScreen(context: params.context, updatedPresentationData: params.updatedPresentationData, mainStickerPack: reference, stickerPacks: [reference], parentNavigationController: params.navigationController, sendSticker: params.sendSticker, sendEmoji: params.sendEmoji, actionPerformed: { actions in
|
|
let presentationData = params.context.sharedContext.currentPresentationData.with { $0 }
|
|
|
|
if actions.count > 1, let first = actions.first {
|
|
if case .add = first.2 {
|
|
params.navigationController?.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.EmojiPackActionInfo_AddedTitle, text: presentationData.strings.EmojiPackActionInfo_MultipleAddedText(Int32(actions.count)), undo: false, info: first.0, topItem: first.1.first, context: params.context), elevatedLayout: false, animateInAsReplacement: false, action: { _ in
|
|
return true
|
|
}))
|
|
}
|
|
} else if let (info, items, action) = actions.first {
|
|
let isEmoji = info.id.namespace == Namespaces.ItemCollection.CloudEmojiPacks
|
|
|
|
var animateInAsReplacement = false
|
|
if let navigationController = params.navigationController {
|
|
for controller in navigationController.overlayControllers {
|
|
if let controller = controller as? UndoOverlayController {
|
|
controller.dismissWithCommitActionAndReplacementAnimation()
|
|
animateInAsReplacement = true
|
|
}
|
|
}
|
|
}
|
|
switch action {
|
|
case .add:
|
|
let controller = UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_AddedTitle : presentationData.strings.StickerPackActionInfo_AddedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_AddedText(info.title).string : presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: items.first, context: params.context), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in
|
|
return true
|
|
})
|
|
(params.navigationController?.topViewController as? ViewController)?.present(controller, in: .current)
|
|
case let .remove(positionInList):
|
|
let controller = UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_RemovedTitle : presentationData.strings.StickerPackActionInfo_RemovedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_RemovedText(info.title).string : presentationData.strings.StickerPackActionInfo_RemovedText(info.title).string, undo: true, info: info, topItem: items.first, context: params.context), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { action in
|
|
if case .undo = action {
|
|
let _ = params.context.engine.stickers.addStickerPackInteractively(info: info, items: items, positionInList: positionInList).startStandalone()
|
|
}
|
|
return true
|
|
})
|
|
(params.navigationController?.topViewController as? ViewController)?.present(controller, in: .current)
|
|
}
|
|
}
|
|
}, getSourceRect: params.getSourceRect)
|
|
params.dismissInput()
|
|
params.present(controller, nil, .window(.root))
|
|
return true
|
|
case let .document(file, immediateShare):
|
|
params.dismissInput()
|
|
let presentationData = params.context.sharedContext.currentPresentationData.with { $0 }
|
|
if immediateShare {
|
|
let controller = ShareController(context: params.context, subject: .media(.standalone(media: file)), immediateExternalShare: true)
|
|
params.present(controller, nil, .window(.root))
|
|
} else if let rootController = params.navigationController?.view.window?.rootViewController {
|
|
let proceed = {
|
|
let canShare = !params.message.isCopyProtected()
|
|
var useBrowserScreen = false
|
|
if BrowserScreen.supportedDocumentMimeTypes.contains(file.mimeType) {
|
|
useBrowserScreen = true
|
|
} else if let fileName = file.fileName as? NSString, BrowserScreen.supportedDocumentExtensions.contains(fileName.pathExtension.lowercased()) {
|
|
useBrowserScreen = true
|
|
}
|
|
if useBrowserScreen {
|
|
let subject: BrowserScreen.Subject
|
|
if file.mimeType == "application/pdf" {
|
|
subject = .pdfDocument(file: file, canShare: canShare)
|
|
} else {
|
|
subject = .document(file: file, canShare: canShare)
|
|
}
|
|
let controller = BrowserScreen(context: params.context, subject: subject)
|
|
controller.openDocument = { file, canShare in
|
|
controller.dismiss()
|
|
|
|
presentDocumentPreviewController(rootController: rootController, theme: presentationData.theme, strings: presentationData.strings, postbox: params.context.account.postbox, file: file, canShare: canShare)
|
|
}
|
|
params.navigationController?.pushViewController(controller)
|
|
} else {
|
|
presentDocumentPreviewController(rootController: rootController, theme: presentationData.theme, strings: presentationData.strings, postbox: params.context.account.postbox, file: file, canShare: canShare)
|
|
}
|
|
}
|
|
if file.mimeType.contains("image/svg") {
|
|
let presentationData = params.context.sharedContext.currentPresentationData.with { $0 }
|
|
params.present(textAlertController(context: params.context, title: nil, text: presentationData.strings.OpenFile_PotentiallyDangerousContentAlert, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.OpenFile_Proceed, action: { proceed() })] ), nil, .window(.root))
|
|
} else {
|
|
proceed()
|
|
}
|
|
}
|
|
return true
|
|
case let .audio(file):
|
|
let location: PeerMessagesPlaylistLocation
|
|
let playerType: MediaManagerPlayerType
|
|
var control = SharedMediaPlayerControlAction.playback(.play)
|
|
if case let .timecode(time) = params.mode {
|
|
control = .seek(time)
|
|
}
|
|
if (file.isVoice || file.isInstantVideo) && params.message.tags.contains(.voiceOrInstantVideo) {
|
|
if let playlistLocation = params.playlistLocation {
|
|
location = playlistLocation
|
|
} else if params.standalone {
|
|
location = .recentActions(params.message)
|
|
} else {
|
|
location = .messages(chatLocation: params.chatLocation ?? .peer(id: params.message.id.peerId), tagMask: .voiceOrInstantVideo, at: params.message.id)
|
|
}
|
|
playerType = .voice
|
|
} else if file.isMusic && params.message.tags.contains(.music) {
|
|
if let playlistLocation = params.playlistLocation {
|
|
location = playlistLocation
|
|
} else if params.standalone {
|
|
location = .recentActions(params.message)
|
|
} else {
|
|
location = .messages(chatLocation: params.chatLocation ?? .peer(id: params.message.id.peerId), tagMask: .music, at: params.message.id)
|
|
}
|
|
playerType = .music
|
|
} else {
|
|
if let playlistLocation = params.playlistLocation {
|
|
location = playlistLocation
|
|
} else if params.standalone {
|
|
location = .recentActions(params.message)
|
|
} else {
|
|
location = .singleMessage(params.message.id)
|
|
}
|
|
playerType = (file.isVoice || file.isInstantVideo) ? .voice : .file
|
|
}
|
|
params.context.sharedContext.mediaManager.setPlaylist((params.context.account, PeerMessagesMediaPlaylist(context: params.context, location: location, chatLocationContextHolder: params.chatLocationContextHolder)), type: playerType, control: control)
|
|
return true
|
|
case let .story(storyController):
|
|
params.dismissInput()
|
|
let _ = (storyController
|
|
|> deliverOnMainQueue).startStandalone(next: { storyController in
|
|
params.navigationController?.pushViewController(storyController)
|
|
})
|
|
case let .gallery(gallery):
|
|
params.dismissInput()
|
|
let _ = (gallery
|
|
|> deliverOnMainQueue).startStandalone(next: { gallery in
|
|
gallery.centralItemUpdated = { messageId in
|
|
params.centralItemUpdated?(messageId)
|
|
}
|
|
params.present(gallery, GalleryControllerPresentationArguments(transitionArguments: { messageId, media in
|
|
let selectedTransitionNode = params.transitionNode(messageId, media, false)
|
|
if let selectedTransitionNode = selectedTransitionNode {
|
|
return GalleryTransitionArguments(transitionNode: selectedTransitionNode, addToTransitionSurface: params.addToTransitionSurface)
|
|
}
|
|
return nil
|
|
}), params.message.adAttribute != nil ? .current : .window(.root))
|
|
})
|
|
return true
|
|
case let .secretGallery(gallery):
|
|
params.dismissInput()
|
|
params.present(gallery, GalleryControllerPresentationArguments(transitionArguments: { messageId, media in
|
|
let selectedTransitionNode = params.transitionNode(messageId, media, false)
|
|
if let selectedTransitionNode = selectedTransitionNode {
|
|
return GalleryTransitionArguments(transitionNode: selectedTransitionNode, addToTransitionSurface: params.addToTransitionSurface)
|
|
}
|
|
return nil
|
|
}), .window(.root))
|
|
return true
|
|
case let .other(otherMedia):
|
|
params.dismissInput()
|
|
if let contact = otherMedia as? TelegramMediaContact {
|
|
let paramsSignal: Signal<(EnginePeer?, Bool), NoError>
|
|
if let peerId = contact.peerId {
|
|
paramsSignal = params.context.engine.data.get(
|
|
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId),
|
|
TelegramEngine.EngineData.Item.Peer.IsContact(id: peerId)
|
|
)
|
|
} else {
|
|
paramsSignal = .single((nil, false))
|
|
}
|
|
|
|
let _ = (paramsSignal
|
|
|> deliverOnMainQueue).startStandalone(next: { peer, isContact in
|
|
let contactData: DeviceContactExtendedData
|
|
if let vCard = contact.vCardData, let vCardData = vCard.data(using: .utf8), let parsed = DeviceContactExtendedData(vcard: vCardData) {
|
|
contactData = parsed
|
|
} else {
|
|
contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: contact.firstName, lastName: contact.lastName, phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: contact.phoneNumber)]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
|
|
}
|
|
let controller = deviceContactInfoController(context: ShareControllerAppAccountContext(context: params.context), environment: ShareControllerAppEnvironment(sharedContext: params.context.sharedContext), updatedPresentationData: params.updatedPresentationData, subject: .vcard(peer?._asPeer(), nil, contactData), completed: nil, cancelled: nil)
|
|
params.navigationController?.pushViewController(controller)
|
|
})
|
|
return true
|
|
}
|
|
case let .chatAvatars(controller, media):
|
|
params.dismissInput()
|
|
params.chatAvatarHiddenMedia(controller.hiddenMedia |> map { value -> MessageId? in
|
|
if value != nil {
|
|
return params.message.id
|
|
} else {
|
|
return nil
|
|
}
|
|
}, media)
|
|
|
|
params.present(controller, AvatarGalleryControllerPresentationArguments(transitionArguments: { entry in
|
|
if let selectedTransitionNode = params.transitionNode(params.message.id, media, false) {
|
|
return GalleryTransitionArguments(transitionNode: selectedTransitionNode, addToTransitionSurface: params.addToTransitionSurface)
|
|
}
|
|
return nil
|
|
}), .window(.root))
|
|
case let .theme(media):
|
|
params.dismissInput()
|
|
let path = params.context.account.postbox.mediaBox.completedResourcePath(media.resource)
|
|
var previewTheme: PresentationTheme?
|
|
if let path = path, let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe) {
|
|
previewTheme = makePresentationTheme(data: data)
|
|
}
|
|
|
|
guard let theme = previewTheme else {
|
|
return false
|
|
}
|
|
let controller = ThemePreviewController(context: params.context, previewTheme: theme, source: .media(.message(message: MessageReference(params.message), media: media)))
|
|
params.navigationController?.pushViewController(controller)
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func makeInstantPageControllerImpl(context: AccountContext, message: Message, sourcePeerType: MediaAutoDownloadPeerType?) -> ViewController? {
|
|
guard let (webpage, anchor) = instantPageAndAnchor(message: message) else {
|
|
return nil
|
|
}
|
|
let sourceLocation = InstantPageSourceLocation(userLocation: .peer(message.id.peerId), peerType: sourcePeerType ?? .channel)
|
|
return makeInstantPageControllerImpl(context: context, webPage: webpage, anchor: anchor, sourceLocation: sourceLocation)
|
|
}
|
|
|
|
func makeInstantPageControllerImpl(context: AccountContext, webPage: TelegramMediaWebpage, anchor: String?, sourceLocation: InstantPageSourceLocation) -> ViewController {
|
|
return BrowserScreen(context: context, subject: .instantPage(webPage: webPage, anchor: anchor, sourceLocation: sourceLocation, preloadedResources: nil))
|
|
}
|
|
|
|
func openChatWallpaperImpl(context: AccountContext, message: Message, present: @escaping (ViewController, Any?) -> Void) {
|
|
for media in message.media {
|
|
if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
|
|
let _ = (context.sharedContext.resolveUrl(context: context, peerId: nil, url: content.url, skipUrlAuth: true)
|
|
|> deliverOnMainQueue).startStandalone(next: { resolvedUrl in
|
|
if case let .wallpaper(parameter) = resolvedUrl {
|
|
let source: WallpaperListSource
|
|
switch parameter {
|
|
case let .slug(slug, options, colors, intensity, rotation):
|
|
source = .slug(slug, content.file, options, colors, intensity, rotation, message)
|
|
case let .color(color):
|
|
source = .wallpaper(.color(color.argb), nil, [], nil, nil, message)
|
|
case let .gradient(colors, rotation):
|
|
source = .wallpaper(.gradient(TelegramWallpaper.Gradient(id: nil, colors: colors, settings: WallpaperSettings(rotation: rotation))), nil, [], nil, rotation, message)
|
|
}
|
|
|
|
let controller = WallpaperGalleryController(context: context, source: source)
|
|
present(controller, nil)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func openChatTheme(context: AccountContext, message: Message, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
|
for media in message.media {
|
|
if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
|
|
let _ = (context.sharedContext.resolveUrl(context: context, peerId: nil, url: content.url, skipUrlAuth: true)
|
|
|> deliverOnMainQueue).startStandalone(next: { resolvedUrl in
|
|
var file: TelegramMediaFile?
|
|
var settings: TelegramThemeSettings?
|
|
let themeMimeType = "application/x-tgtheme-ios"
|
|
|
|
for attribute in content.attributes {
|
|
if case let .theme(attribute) = attribute {
|
|
if let attributeSettings = attribute.settings {
|
|
settings = attributeSettings
|
|
} else if let filteredFile = attribute.files.filter({ $0.mimeType == themeMimeType }).first {
|
|
file = filteredFile
|
|
}
|
|
}
|
|
}
|
|
|
|
if file == nil && settings == nil, let contentFile = content.file, contentFile.mimeType == themeMimeType {
|
|
file = contentFile
|
|
}
|
|
let displayUnsupportedAlert: () -> Void = {
|
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
present(textAlertController(context: context, title: nil, text: presentationData.strings.Theme_Unsupported, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
|
}
|
|
if case let .theme(slug) = resolvedUrl {
|
|
if let file = file {
|
|
if let path = context.sharedContext.accountManager.mediaBox.completedResourcePath(file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
|
if let theme = makePresentationTheme(data: data) {
|
|
let controller = ThemePreviewController(context: context, previewTheme: theme, source: .slug(slug, file))
|
|
pushController(controller)
|
|
} else {
|
|
displayUnsupportedAlert()
|
|
}
|
|
}
|
|
} else if let settings = settings {
|
|
if let theme = makePresentationTheme(settings: settings, title: content.title) {
|
|
let controller = ThemePreviewController(context: context, previewTheme: theme, source: .themeSettings(slug, settings))
|
|
pushController(controller)
|
|
} else {
|
|
displayUnsupportedAlert()
|
|
}
|
|
} else {
|
|
displayUnsupportedAlert()
|
|
}
|
|
} else {
|
|
displayUnsupportedAlert()
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|