2024-06-15 20:34:07 +04:00

236 lines
11 KiB
Swift

import Foundation
import UIKit
import AsyncDisplayKit
import Display
import SwiftSignalKit
import Postbox
import TelegramCore
import ContextUI
import ChatPresentationInterfaceState
import AccountContext
import TelegramPresentationData
import WebsiteType
private enum OptionsId: Hashable {
case link
}
func presentLinkOptionsController(context: AccountContext, selfController: CreateLinkScreen, snapshotImage: UIImage?, isDark: Bool, sourceNode: ASDisplayNode, url: String, name: String, positionBelowText: Bool, largeMedia: Bool?, webPage: TelegramMediaWebpage, completion: @escaping (Bool, Bool?) -> Void, remove: @escaping () -> Void) {
var sources: [ContextController.Source] = []
if let source = linkOptions(context: context, selfController: selfController, snapshotImage: snapshotImage, isDark: isDark, sourceNode: sourceNode, url: url, text: name, positionBelowText: positionBelowText, largeMedia: largeMedia, webPage: webPage, completion: completion, remove: remove) {
sources.append(source)
}
if sources.isEmpty {
return
}
let contextController = ContextController(
presentationData: context.sharedContext.currentPresentationData.with { $0 }.withUpdated(theme: defaultDarkColorPresentationTheme),
configuration: ContextController.Configuration(
sources: sources,
initialId: AnyHashable(OptionsId.link)
)
)
selfController.presentInGlobalOverlay(contextController)
}
private func linkOptions(context: AccountContext, selfController: CreateLinkScreen, snapshotImage: UIImage?, isDark: Bool, sourceNode: ASDisplayNode, url: String, text: String, positionBelowText: Bool, largeMedia: Bool?, webPage: TelegramMediaWebpage, completion: @escaping (Bool, Bool?) -> Void, remove: @escaping () -> Void) -> ContextController.Source? {
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(1))
let presentationData = context.sharedContext.currentPresentationData.with { $0 }.withUpdated(theme: defaultDarkColorPresentationTheme)
let initialUrlPreview = ChatPresentationInterfaceState.UrlPreview(url: url, webPage: webPage, positionBelowText: positionBelowText, largeMedia: largeMedia)
let urlPreview = ValuePromise<ChatPresentationInterfaceState.UrlPreview>(initialUrlPreview)
let linkOptions = urlPreview.get()
|> deliverOnMainQueue
|> map { urlPreview -> ChatControllerSubject.LinkOptions in
var webpageHasLargeMedia = false
if case let .Loaded(content) = webPage.content {
if let isMediaLargeByDefault = content.isMediaLargeByDefault {
if isMediaLargeByDefault {
webpageHasLargeMedia = true
}
} else {
webpageHasLargeMedia = true
}
}
let entities = [MessageTextEntity(range: 0 ..< (text as NSString).length, type: .Url)]
var largeMedia = false
if webpageHasLargeMedia {
if let value = urlPreview.largeMedia {
largeMedia = value
} else if case .Loaded = webPage.content {
largeMedia = false //!defaultWebpageImageSizeIsSmall(webpage: content)
} else {
largeMedia = true
}
} else {
largeMedia = false
}
return ChatControllerSubject.LinkOptions(
messageText: text,
messageEntities: entities,
hasAlternativeLinks: false,
replyMessageId: nil,
replyQuote: nil,
url: urlPreview.url,
webpage: urlPreview.webPage,
linkBelowText: urlPreview.positionBelowText,
largeMedia: largeMedia
)
}
|> distinctUntilChanged
let wallpaper: TelegramWallpaper?
if let image = snapshotImage {
let wallpaperResource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
if let wallpaperData = image.jpegData(compressionQuality: 0.87) {
context.account.postbox.mediaBox.storeResourceData(wallpaperResource.id, data: wallpaperData, synchronous: true)
}
let wallpaperRepresentation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(image.size), resource: wallpaperResource, progressiveSizes: [], immediateThumbnailData: nil)
wallpaper = .image([wallpaperRepresentation], WallpaperSettings())
} else {
wallpaper = nil
}
let chatController = context.sharedContext.makeChatController(
context: context,
chatLocation: .peer(id: peerId),
subject: .messageOptions(peerIds: [peerId], ids: [], info: .link(ChatControllerSubject.MessageOptionsInfo.Link(options: linkOptions, isCentered: true))),
botStart: nil,
mode: .standard(.previewing),
params: ChatControllerParams(
forcedTheme: isDark ? defaultDarkColorPresentationTheme : defaultPresentationTheme,
forcedNavigationBarTheme: defaultDarkColorPresentationTheme,
forcedWallpaper: wallpaper
)
)
chatController.canReadHistory.set(false)
let items = linkOptions
|> deliverOnMainQueue
|> map { linkOptions -> ContextController.Items in
var items: [ContextMenuItem] = []
do {
items.append(.action(ContextMenuActionItem(text: linkOptions.linkBelowText ? presentationData.strings.Conversation_MessageOptionsLinkMoveUp : presentationData.strings.Conversation_MessageOptionsLinkMoveDown, icon: { theme in
return nil
}, iconAnimation: ContextMenuActionItem.IconAnimation(
name: linkOptions.linkBelowText ? "message_preview_sort_above" : "message_preview_sort_below"
), action: { _, f in
let _ = (urlPreview.get()
|> take(1)).start(next: { current in
var updatedUrlPreview = current
updatedUrlPreview.positionBelowText = !current.positionBelowText
urlPreview.set(updatedUrlPreview)
})
})))
}
if case let .Loaded(content) = linkOptions.webpage.content, let isMediaLargeByDefault = content.isMediaLargeByDefault, isMediaLargeByDefault {
let shrinkTitle: String
let enlargeTitle: String
if let file = content.file, file.isVideo {
shrinkTitle = presentationData.strings.Conversation_MessageOptionsShrinkVideo
enlargeTitle = presentationData.strings.Conversation_MessageOptionsEnlargeVideo
} else {
shrinkTitle = presentationData.strings.Conversation_MessageOptionsShrinkImage
enlargeTitle = presentationData.strings.Conversation_MessageOptionsEnlargeImage
}
items.append(.action(ContextMenuActionItem(text: linkOptions.largeMedia ? shrinkTitle : enlargeTitle, icon: { _ in
return nil
}, iconAnimation: ContextMenuActionItem.IconAnimation(
name: !linkOptions.largeMedia ? "message_preview_media_large" : "message_preview_media_small"
), action: { _, f in
let _ = (urlPreview.get()
|> take(1)).start(next: { current in
var updatedUrlPreview = current
if let largeMedia = current.largeMedia {
updatedUrlPreview.largeMedia = !largeMedia
} else {
updatedUrlPreview.largeMedia = false
}
urlPreview.set(updatedUrlPreview)
})
})))
}
if !items.isEmpty {
items.append(.separator)
}
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_MessageOptionsApplyChanges, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.contextMenu.primaryColor) }, action: { _, f in
f(.default)
let _ = (urlPreview.get()
|> take(1)).start(next: { current in
completion(current.positionBelowText, current.largeMedia)
})
})))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_LinkOptionsCancel, textColor: .destructive, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
remove()
f(.default)
})))
return ContextController.Items(id: AnyHashable(linkOptions.url), content: .list(items))
}
return ContextController.Source(
id: AnyHashable(OptionsId.link),
title: presentationData.strings.Conversation_MessageOptionsTabLink,
source: .controller(ChatContextControllerContentSourceImpl(controller: chatController, sourceNode: sourceNode, passthroughTouches: true)),
items: items
)
}
final class ChatContextControllerContentSourceImpl: ContextControllerContentSource {
let controller: ViewController
weak var sourceNode: ASDisplayNode?
weak var sourceView: UIView?
let sourceRect: CGRect?
let navigationController: NavigationController? = nil
let passthroughTouches: Bool
init(controller: ViewController, sourceNode: ASDisplayNode?, sourceRect: CGRect? = nil, passthroughTouches: Bool) {
self.controller = controller
self.sourceNode = sourceNode
self.sourceRect = sourceRect
self.passthroughTouches = passthroughTouches
}
init(controller: ViewController, sourceView: UIView?, sourceRect: CGRect? = nil, passthroughTouches: Bool) {
self.controller = controller
self.sourceView = sourceView
self.sourceRect = sourceRect
self.passthroughTouches = passthroughTouches
}
func transitionInfo() -> ContextControllerTakeControllerInfo? {
let sourceView = self.sourceView
let sourceNode = self.sourceNode
let sourceRect = self.sourceRect
return ContextControllerTakeControllerInfo(contentAreaInScreenSpace: CGRect(origin: CGPoint(), size: CGSize(width: 10.0, height: 10.0)), sourceNode: { [weak sourceNode] in
if let sourceView = sourceView {
return (sourceView, sourceRect ?? sourceView.bounds)
} else if let sourceNode = sourceNode {
return (sourceNode.view, sourceRect ?? sourceNode.bounds)
} else {
return nil
}
})
}
func animatedIn() {
}
}