Files
Mikhail Filimonov dd430361c8 no message
2024-06-03 12:30:31 +04:00

343 lines
14 KiB
Swift

//
// WPArticleLayout.swift
// Telegram-Mac
//
// Created by keepcoder on 18/10/2016.
// Copyright © 2016 Telegram. All rights reserved.
//
import Cocoa
import TelegramCore
import InAppVideoServices
import Postbox
import TGUIKit
import SwiftSignalKit
import InAppSettings
class WPArticleLayout: WPLayout {
var imageSize:NSSize?
var contrainedImageSize:NSSize = NSMakeSize(54, 54)
var smallThumb:Bool = true
var imageArguments:TransformImageArguments?
private(set) var duration:(TextNodeLayout, TextNode)?
private let durationAttributed:NSAttributedString?
private let fetchDisposable = MetaDisposable()
private let downloadSettings: AutomaticMediaDownloadSettings
private(set) var groupLayout: GroupedLayout?
private(set) var parameters:[ChatMediaLayoutParameters] = []
init(with content: TelegramMediaWebpageLoadedContent, context: AccountContext, chatInteraction:ChatInteraction, parent:Message, fontSize: CGFloat, presentation: WPLayoutPresentation, approximateSynchronousValue: Bool, downloadSettings: AutomaticMediaDownloadSettings, autoplayMedia: AutoplayMediaPreferences, theme: TelegramPresentationTheme, mayCopyText: Bool, entities: [MessageTextEntity]? = nil, adAttribute: AdMessageAttribute? = nil) {
var content = content
if let story = content.story, let media = parent.associatedStories[story.storyId]?.get(Stories.StoredItem.self), groupLayout == nil {
switch media {
case let .item(story):
if let image = story.media as? TelegramMediaImage {
content = content.withUpdatedImage(image)
} else if let file = story.media as? TelegramMediaFile {
content = content.withUpdatedFile(file)
}
default:
break
}
}
if let duration = content.duration {
self.durationAttributed = .initialize(string: String.durationTransformed(elapsed: duration), color: .white, font: .normal(.text))
} else {
durationAttributed = nil
}
if content.type == "telegram_theme" {
for attr in content.attributes {
switch attr {
case let .theme(theme):
for file in theme.files {
if file.mimeType == "application/x-tgtheme-macos", !file.previewRepresentations.isEmpty {
content = content.withUpdatedFile(file)
}
}
case .stickerPack:
break
case .unsupported:
break
}
}
}
self.downloadSettings = downloadSettings
super.init(with: content, context: context, chatInteraction: chatInteraction, parent:parent, fontSize: fontSize, presentation: presentation, approximateSynchronousValue: approximateSynchronousValue, mayCopyText: mayCopyText, entities: entities, adAttribute: adAttribute)
if let mediaCount = mediaCount, mediaCount > 1 {
var instantMedias = Array(instantPageMedias(for: parent.media[0] as! TelegramMediaWebpage).suffix(10))
if let file = content.file {
let page = InstantPageMedia(index: 0, media: file, webpage: parent.media[0] as! TelegramMediaWebpage, url: nil, caption: nil, credit: nil)
for i in 0 ..< instantMedias.count {
instantMedias[i] = instantMedias[i].withUpdatedIndex(i + 1)
}
instantMedias.insert(page, at: 0)
} else if let image = content.image {
let page = InstantPageMedia(index: 0, media: image, webpage: parent.media[0] as! TelegramMediaWebpage, url: nil, caption: nil, credit: nil)
for i in 0 ..< instantMedias.count {
instantMedias[i] = instantMedias[i].withUpdatedIndex(i + 1)
}
instantMedias.insert(page, at: 0)
} else {
for i in 0 ..< instantMedias.count {
instantMedias[i] = instantMedias[i].withUpdatedIndex(i)
}
}
var messages:[Message] = []
let groupingKey = arc4random64()
for i in 0 ..< instantMedias.count {
let media = instantMedias[i].media
let message = parent.withUpdatedMedia([media]).withUpdatedStableId(arc4random()).withUpdatedId(MessageId(peerId: chatInteraction.peerId, namespace: Namespaces.Message.Local, id: MessageId.Id(i))).withUpdatedGroupingKey(groupingKey)
messages.append(message)
weak var weakParameters:ChatMediaGalleryParameters?
let parameters = ChatMediaGalleryParameters(showMedia: { [weak self] _ in
guard let `self` = self else {return}
//
showInstantViewGallery(context: context, medias: instantMedias, firstIndex: i, firstStableId: ChatHistoryEntryId.message(parent), parent: parent, self.table, weakParameters)
}, showMessage: { [weak chatInteraction] _ in
chatInteraction?.focusMessageId(nil, .init(messageId: parent.id, string: nil), .CenterEmpty)
}, isWebpage: chatInteraction.isLogInteraction, presentation: .make(for: message, account: context.account, renderType: presentation.renderType, theme: theme), media: media, automaticDownload: downloadSettings.isDownloable(message), autoplayMedia: autoplayMedia)
weakParameters = parameters
self.parameters.append(parameters)
}
groupLayout = GroupedLayout(messages)
}
if let image = content.image, groupLayout == nil {
if let dimensions = largestImageRepresentation(image.representations)?.dimensions.size {
imageSize = dimensions
}
}
for attr in content.attributes {
switch attr {
case .stickerPack:
imageSize = NSMakeSize(50, 50)
default:
break
}
}
if let file = content.file, groupLayout == nil {
if let dimensions = file.dimensions?.size {
imageSize = dimensions
} else if isTheme {
imageSize = NSMakeSize(200, 200)
}
} else if isTheme {
imageSize = NSMakeSize(260, 260)
}
if let wallpaper = wallpaper {
switch wallpaper {
case let .wallpaper(_, _, preview):
switch preview {
case .color:
imageSize = NSMakeSize(150, 150)
case .gradient:
imageSize = NSMakeSize(200, 200)
default:
break
}
default:
break
}
}
if ExternalVideoLoader.isPlayable(content) {
_ = sharedVideoLoader.fetch(for: content).start()
}
}
var isAutoDownloable: Bool {
return downloadSettings.isDownloable(parent)
}
deinit {
fetchDisposable.dispose()
}
private let mediaTypes:[String] = ["photo","video"]
private let fullSizeSites:[String] = ["instagram","twitter"]
var isFullImageSize: Bool {
for attr in content.attributes {
switch attr {
case .stickerPack:
return false
default:
break
}
}
if let attr = parent.webpagePreviewAttribute {
if let forceLargeMedia = attr.forceLargeMedia {
return forceLargeMedia
}
}
// if let value = content.isMediaLargeByDefault {
// return value
// }
if content.type == "telegram_background" || content.type == "telegram_theme" {
return true
}
let website = content.websiteName?.lowercased()
if let type = content.type, mediaTypes.contains(type) || (fullSizeSites.contains(website ?? "") || content.instantPage != nil) || content.text == nil {
if let imageSize = imageSize {
if imageSize.width < 200 {
return false
}
}
if type == "telegram_user" {
return false
}
return true
}
return content.text == nil || content.text!.trimmed.isEmpty
}
override func measure(width: CGFloat) {
if oldWidth != width {
super.measure(width: width)
let maxw = min(width - insets.left - insets.right, 300)
var contentSize:NSSize = NSMakeSize(maxw, 0)
if let groupLayout = groupLayout {
groupLayout.measure(NSMakeSize(max(contentSize.width, maxw), maxw))
contentSize.height += groupLayout.dimensions.height + 6
contentSize.width = max(groupLayout.dimensions.width, contentSize.width)
}
var emptyColor: TransformImageEmptyColor? = nil
if let wallpaper = wallpaper {
switch wallpaper {
case let .wallpaper(_, _, preview):
switch preview {
case let .slug(_, settings):
if !settings.colors.isEmpty {
var patternIntensity: CGFloat = 0.5
let color = settings.colors.first ?? NSColor(rgb: 0xd6e2ee, alpha: 0.5).argb
if let intensity = settings.intensity {
patternIntensity = CGFloat(intensity) / 100.0
}
if settings.colors.count > 1 {
emptyColor = .gradient(colors: settings.colors.map { NSColor(argb: $0) }, intensity: patternIntensity, rotation: settings.rotation)
} else {
emptyColor = .color(NSColor(argb: color))
}
}
default:
break
}
default:
break
}
}
if let imageSize = imageSize, isFullImageSize {
if content.story != nil {
contrainedImageSize = imageSize.aspectFitted(NSMakeSize(maxw, maxw))
} else if isTheme {
contrainedImageSize = imageSize.fitted(NSMakeSize(maxw, maxw))
} else {
contrainedImageSize = imageSize.aspectFitted(NSMakeSize(maxw, maxw))
if action_text != nil, contrainedImageSize.width < 200 {
contrainedImageSize = NSMakeSize(min(300, maxw), min(300, maxw))
} else if contrainedImageSize.width < 200 {
contrainedImageSize = NSMakeSize(min(300, maxw), min(300, maxw))
}
}
textLayout?.cutout = nil
smallThumb = false
contentSize.height += contrainedImageSize.height
contentSize.width = contrainedImageSize.width
if textLayout != nil {
contentSize.height += insets.top
}
} else {
if let _ = imageSize, !isFullImageSize {
contrainedImageSize = NSMakeSize(54, 54)
textLayout?.cutout = TextViewCutout(topRight: NSMakeSize(contrainedImageSize.width + 16, contrainedImageSize.height + 10))
}
}
if let durationAttributed = durationAttributed {
duration = TextNode.layoutText(durationAttributed, nil, 1, .end, NSMakeSize(contentSize.width, .greatestFiniteMagnitude), nil, false, .center)
}
textLayout?.measure(width: contentSize.width)
if let textLayout = textLayout {
contentSize.height += textLayout.layoutSize.height
if textLayout.cutout != nil {
contentSize.height = max(imageSize != nil ? contrainedImageSize.height + imageInsets.top + imageInsets.bottom : 0, contentSize.height)
contentSize.width = min(max(max(textLayout.layoutSize.width, maxw), contrainedImageSize.width), maxw)
} else if imageSize == nil {
contentSize.width = max(max(textLayout.layoutSize.width, maxw), groupLayout?.dimensions.width ?? 0)
}
}
if let imageSize = imageSize {
let imgSize: NSSize
if isTheme {
imgSize = contrainedImageSize
} else if action_text != nil {
imgSize = imageSize.aspectFitted(contrainedImageSize)
} else {
imgSize = imageSize.aspectFilled(NSMakeSize(maxw, maxw))
}
let imageArguments = TransformImageArguments(corners: ImageCorners(radius: 4.0), imageSize: imgSize, boundingSize: contrainedImageSize, intrinsicInsets: NSEdgeInsets(), resizeMode: .blurBackground, emptyColor: emptyColor)
if imageArguments != self.imageArguments {
self.imageArguments = imageArguments
}
} else {
self.imageArguments = nil
}
layout(with :contentSize)
}
}
}