mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
243 lines
11 KiB
Swift
243 lines
11 KiB
Swift
import Foundation
|
|
import AsyncDisplayKit
|
|
import Display
|
|
import TelegramCore
|
|
import SwiftSignalKit
|
|
import Postbox
|
|
|
|
final class WebSearchItem: GridItem {
|
|
var section: GridSection?
|
|
|
|
let account: Account
|
|
let theme: PresentationTheme
|
|
let interfaceState: WebSearchInterfaceState
|
|
let result: ChatContextResult
|
|
let controllerInteraction: WebSearchControllerInteraction
|
|
|
|
public init(account: Account, theme: PresentationTheme, interfaceState: WebSearchInterfaceState, result: ChatContextResult, controllerInteraction: WebSearchControllerInteraction) {
|
|
self.account = account
|
|
self.theme = theme
|
|
self.result = result
|
|
self.interfaceState = interfaceState
|
|
self.controllerInteraction = controllerInteraction
|
|
}
|
|
|
|
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
|
|
let node = WebSearchItemNode()
|
|
node.setup(item: self)
|
|
return node
|
|
}
|
|
|
|
func update(node: GridItemNode) {
|
|
guard let node = node as? WebSearchItemNode else {
|
|
assertionFailure()
|
|
return
|
|
}
|
|
node.setup(item: self)
|
|
}
|
|
}
|
|
|
|
final class WebSearchItemNode: GridItemNode {
|
|
private let imageNodeBackground: ASDisplayNode
|
|
private let imageNode: TransformImageNode
|
|
private var selectionNode: GridMessageSelectionNode?
|
|
|
|
private var currentImageResource: TelegramMediaResource?
|
|
private var currentVideoFile: TelegramMediaFile?
|
|
private var currentDimensions: CGSize?
|
|
|
|
private(set) var item: WebSearchItem?
|
|
|
|
private let fetchStatusDisposable = MetaDisposable()
|
|
private let fetchDisposable = MetaDisposable()
|
|
private var resourceStatus: MediaResourceStatus?
|
|
|
|
private let statusNode: RadialStatusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.5))
|
|
|
|
override init() {
|
|
self.imageNodeBackground = ASDisplayNode()
|
|
self.imageNodeBackground.isLayerBacked = true
|
|
|
|
self.imageNode = TransformImageNode()
|
|
self.imageNode.contentAnimations = [.subsequentUpdates]
|
|
self.imageNode.displaysAsynchronously = false
|
|
|
|
super.init()
|
|
|
|
self.addSubnode(self.imageNodeBackground)
|
|
self.addSubnode(self.imageNode)
|
|
}
|
|
|
|
deinit {
|
|
self.fetchStatusDisposable.dispose()
|
|
self.fetchDisposable.dispose()
|
|
}
|
|
|
|
override func didLoad() {
|
|
super.didLoad()
|
|
|
|
let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:)))
|
|
recognizer.tapActionAtPoint = { _ in
|
|
return .waitForSingleTap
|
|
}
|
|
self.imageNode.view.addGestureRecognizer(recognizer)
|
|
}
|
|
|
|
func setup(item: WebSearchItem) {
|
|
if self.item !== item {
|
|
var updateImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>?
|
|
var updatedStatusSignal: Signal<MediaResourceStatus, NoError>?
|
|
|
|
var imageResource: TelegramMediaResource?
|
|
var stickerFile: TelegramMediaFile?
|
|
var videoFile: TelegramMediaFile?
|
|
var imageDimensions: CGSize?
|
|
switch item.result {
|
|
case let .externalReference(_, _, type, title, _, url, content, thumbnail, _):
|
|
if let content = content {
|
|
imageResource = content.resource
|
|
} else if let thumbnail = thumbnail {
|
|
imageResource = thumbnail.resource
|
|
}
|
|
imageDimensions = content?.dimensions
|
|
if type == "gif", let thumbnailResource = imageResource, let content = content, let dimensions = content.dimensions {
|
|
videoFile = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: content.resource, previewRepresentations: [TelegramMediaImageRepresentation(dimensions: dimensions, resource: thumbnailResource)], mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: dimensions, flags: [])])
|
|
imageResource = nil
|
|
}
|
|
|
|
if let file = videoFile {
|
|
updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(file.resource)
|
|
} else if let imageResource = imageResource {
|
|
updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(imageResource)
|
|
}
|
|
case let .internalReference(_, _, _, title, _, image, file, _):
|
|
if let image = image {
|
|
if let largestRepresentation = largestImageRepresentation(image.representations) {
|
|
imageDimensions = largestRepresentation.dimensions
|
|
}
|
|
imageResource = imageRepresentationLargerThan(image.representations, size: CGSize(width: 200.0, height: 100.0))?.resource
|
|
} else if let file = file {
|
|
if let dimensions = file.dimensions {
|
|
imageDimensions = dimensions
|
|
} else if let largestRepresentation = largestImageRepresentation(file.previewRepresentations) {
|
|
imageDimensions = largestRepresentation.dimensions
|
|
}
|
|
imageResource = smallestImageRepresentation(file.previewRepresentations)?.resource
|
|
}
|
|
|
|
// if let file = file {
|
|
// if file.isVideo && file.isAnimated {
|
|
// videoFile = file
|
|
// imageResource = nil
|
|
// updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(file.resource)
|
|
// } else if let imageResource = imageResource {
|
|
// updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(imageResource)
|
|
// }
|
|
// } else if let imageResource = imageResource {
|
|
// updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(imageResource)
|
|
// }
|
|
}
|
|
|
|
if let imageResource = imageResource, let imageDimensions = imageDimensions {
|
|
let tmpRepresentation = TelegramMediaImageRepresentation(dimensions: imageDimensions, resource: imageResource)
|
|
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [tmpRepresentation], reference: nil, partialReference: nil)
|
|
updateImageSignal = mediaGridMessagePhoto(account: item.account, photoReference: .standalone(media: tmpImage))
|
|
} else {
|
|
updateImageSignal = .complete()
|
|
}
|
|
|
|
if let updateImageSignal = updateImageSignal {
|
|
self.imageNode.setSignal(updateImageSignal)
|
|
}
|
|
|
|
self.currentImageResource = imageResource
|
|
self.currentVideoFile = videoFile
|
|
self.currentDimensions = imageDimensions
|
|
if let _ = imageDimensions {
|
|
self.setNeedsLayout()
|
|
}
|
|
}
|
|
|
|
self.item = item
|
|
self.updateSelectionState(animated: false)
|
|
}
|
|
|
|
func updateSelectionState(animated: Bool) {
|
|
if self.selectionNode == nil, let item = self.item {
|
|
let selectionNode = GridMessageSelectionNode(theme: item.theme, toggle: { [weak self] value in
|
|
if let strongSelf = self, let item = strongSelf.item {
|
|
item.controllerInteraction.toggleSelection([item.result.id], value)
|
|
strongSelf.updateSelectionState(animated: true)
|
|
}
|
|
})
|
|
|
|
selectionNode.frame = CGRect(origin: CGPoint(), size: self.bounds.size)
|
|
self.addSubnode(selectionNode)
|
|
self.selectionNode = selectionNode
|
|
}
|
|
|
|
if let item = self.item {
|
|
if let selectionState = item.controllerInteraction.selectionState {
|
|
let selected = selectionState.selectedIds.contains(item.result.id)
|
|
self.selectionNode?.updateSelected(selected, animated: animated)
|
|
}
|
|
}
|
|
}
|
|
|
|
override func layout() {
|
|
super.layout()
|
|
|
|
let imageFrame = self.bounds
|
|
self.imageNode.frame = imageFrame
|
|
|
|
if let item = self.item, let dimensions = self.currentDimensions {
|
|
let imageSize = dimensions.aspectFilled(imageFrame.size)
|
|
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageFrame.size, intrinsicInsets: UIEdgeInsets(), emptyColor: item.theme.list.mediaPlaceholderColor))()
|
|
}
|
|
|
|
self.selectionNode?.frame = CGRect(origin: CGPoint(), size: self.bounds.size)
|
|
let progressDiameter: CGFloat = 40.0
|
|
self.statusNode.frame = CGRect(origin: CGPoint(x: floor((imageFrame.size.width - progressDiameter) / 2.0), y: floor((imageFrame.size.height - progressDiameter) / 2.0)), size: CGSize(width: progressDiameter, height: progressDiameter))
|
|
|
|
//self.videoAccessoryNode.frame = CGRect(origin: CGPoint(x: imageFrame.maxX - self.videoAccessoryNode.contentSize.width - 5, y: imageFrame.maxY - self.videoAccessoryNode.contentSize.height - 5), size: self.videoAccessoryNode.contentSize)
|
|
}
|
|
|
|
@objc func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
|
// guard let controllerInteraction = self.controllerInteraction, let message = self.item?.message else {
|
|
// return
|
|
// }
|
|
//
|
|
// switch recognizer.state {
|
|
// case .ended:
|
|
// if let (gesture, _) = recognizer.lastRecognizedGestureAndLocation {
|
|
// switch gesture {
|
|
// case .tap:
|
|
// if let (account, media, _) = self.currentState {
|
|
// if let file = media as? TelegramMediaFile {
|
|
// if let resourceStatus = self.resourceStatus {
|
|
// switch resourceStatus {
|
|
// case .Fetching:
|
|
// messageMediaFileCancelInteractiveFetch(account: account, messageId: message.id, file: file)
|
|
// case .Local:
|
|
// let _ = controllerInteraction.openMessage(message, .default)
|
|
// case .Remote:
|
|
// self.fetchDisposable.set(messageMediaFileInteractiveFetched(account: account, message: message, file: file, userInitiated: true).start())
|
|
// }
|
|
// }
|
|
// } else {
|
|
// let _ = controllerInteraction.openMessage(message, .default)
|
|
// }
|
|
// }
|
|
// case .longTap:
|
|
// controllerInteraction.openMessageContextMenu(message, false, self, self.bounds)
|
|
// default:
|
|
// break
|
|
// }
|
|
// }
|
|
// default:
|
|
// break
|
|
// }
|
|
}
|
|
}
|
|
|