mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Paid media improvements
This commit is contained in:
parent
9fe5a800e9
commit
63d380a534
@ -12364,7 +12364,7 @@ Sorry for the inconvenience.";
|
|||||||
"Stars.BotRevenue.Withdraw.WithdrawShort" = "Withdraw";
|
"Stars.BotRevenue.Withdraw.WithdrawShort" = "Withdraw";
|
||||||
"Stars.BotRevenue.Withdraw.BuyAds" = "Buy Ads";
|
"Stars.BotRevenue.Withdraw.BuyAds" = "Buy Ads";
|
||||||
"Stars.BotRevenue.Withdraw.Info" = "You can collect rewards for Stars using Fragment, or use Stars to advertise your bot. [Learn More >]()";
|
"Stars.BotRevenue.Withdraw.Info" = "You can collect rewards for Stars using Fragment, or use Stars to advertise your bot. [Learn More >]()";
|
||||||
"Stars.BotRevenue.Withdraw.Info_URL" = "https://telegram.org/tos";
|
"Stars.BotRevenue.Withdraw.Info_URL" = "https://telegram.org/tos/bot-developers#6-2-2-tpa-balance";
|
||||||
|
|
||||||
"Stars.BotRevenue.Transactions.Title" = "Transaction History";
|
"Stars.BotRevenue.Transactions.Title" = "Transaction History";
|
||||||
|
|
||||||
@ -12383,7 +12383,7 @@ Sorry for the inconvenience.";
|
|||||||
"Stars.PaidContent.AmountTitle" = "ENTER UNLOCK COST";
|
"Stars.PaidContent.AmountTitle" = "ENTER UNLOCK COST";
|
||||||
"Stars.PaidContent.AmountPlaceholder" = "Stars to Unlock";
|
"Stars.PaidContent.AmountPlaceholder" = "Stars to Unlock";
|
||||||
"Stars.PaidContent.AmountInfo" = "Users will have to transfer this amount of Stars to your channel in order to view this media.\n[More about Stars >]()";
|
"Stars.PaidContent.AmountInfo" = "Users will have to transfer this amount of Stars to your channel in order to view this media.\n[More about Stars >]()";
|
||||||
"Stars.PaidContent.AmountInfo_URL" = "https://telegram.org";
|
"Stars.PaidContent.AmountInfo_URL" = "https://telegram.org/tos/stars";
|
||||||
"Stars.PaidContent.Create" = "Make This Media Paid";
|
"Stars.PaidContent.Create" = "Make This Media Paid";
|
||||||
|
|
||||||
"MediaEditor.AddLink" = "LINK";
|
"MediaEditor.AddLink" = "LINK";
|
||||||
|
@ -817,7 +817,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
|||||||
self.currentMessage = message
|
self.currentMessage = message
|
||||||
|
|
||||||
var displayInfo = displayInfo
|
var displayInfo = displayInfo
|
||||||
if Namespaces.Message.allNonRegular.contains(message.id.namespace) {
|
if Namespaces.Message.allNonRegular.contains(message.id.namespace) || message.timestamp == 0 {
|
||||||
displayInfo = false
|
displayInfo = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +189,18 @@ class ChatImageGalleryItem: GalleryItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func thumbnailItem() -> (Int64, GalleryThumbnailItem)? {
|
func thumbnailItem() -> (Int64, GalleryThumbnailItem)? {
|
||||||
if let id = self.message.groupInfo?.stableId {
|
if let paidContent = self.message.paidContent {
|
||||||
|
var mediaReference: AnyMediaReference?
|
||||||
|
let mediaIndex = self.mediaIndex ?? 0
|
||||||
|
if case let .full(fullMedia) = paidContent.extendedMedia[Int(mediaIndex)], let m = fullMedia as? TelegramMediaImage {
|
||||||
|
mediaReference = .message(message: MessageReference(self.message), media: m)
|
||||||
|
}
|
||||||
|
if let mediaReference = mediaReference {
|
||||||
|
if let item = ChatMediaGalleryThumbnailItem(account: self.context.account, userLocation: .peer(self.message.id.peerId), mediaReference: mediaReference) {
|
||||||
|
return (0, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let id = self.message.groupInfo?.stableId {
|
||||||
var mediaReference: AnyMediaReference?
|
var mediaReference: AnyMediaReference?
|
||||||
for m in self.message.media {
|
for m in self.message.media {
|
||||||
if let m = m as? TelegramMediaImage {
|
if let m = m as? TelegramMediaImage {
|
||||||
|
@ -119,7 +119,18 @@ public class UniversalVideoGalleryItem: GalleryItem {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if case let .message(message) = contentInfo {
|
if case let .message(message) = contentInfo {
|
||||||
if let id = message.groupInfo?.stableId {
|
if let paidContent = message.paidContent {
|
||||||
|
var mediaReference: AnyMediaReference?
|
||||||
|
let mediaIndex = 0//self.mediaIndex ?? 0
|
||||||
|
if case let .full(fullMedia) = paidContent.extendedMedia[Int(mediaIndex)], let m = fullMedia as? TelegramMediaFile {
|
||||||
|
mediaReference = .message(message: MessageReference(message), media: m)
|
||||||
|
}
|
||||||
|
if let mediaReference = mediaReference {
|
||||||
|
if let item = ChatMediaGalleryThumbnailItem(account: self.context.account, userLocation: .peer(message.id.peerId), mediaReference: mediaReference) {
|
||||||
|
return (0, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let id = message.groupInfo?.stableId {
|
||||||
var mediaReference: AnyMediaReference?
|
var mediaReference: AnyMediaReference?
|
||||||
for m in message.media {
|
for m in message.media {
|
||||||
if let m = m as? TelegramMediaImage {
|
if let m = m as? TelegramMediaImage {
|
||||||
|
@ -59,7 +59,7 @@ public final class StarsAvatarComponent: Component {
|
|||||||
private var imageFrameNode: UIView?
|
private var imageFrameNode: UIView?
|
||||||
private var secondImageNode: TransformImageNode?
|
private var secondImageNode: TransformImageNode?
|
||||||
|
|
||||||
private let fetchDisposable = MetaDisposable()
|
private let fetchDisposable = DisposableSet()
|
||||||
|
|
||||||
private var component: StarsAvatarComponent?
|
private var component: StarsAvatarComponent?
|
||||||
private weak var state: EmptyComponentState?
|
private weak var state: EmptyComponentState?
|
||||||
@ -98,24 +98,30 @@ public final class StarsAvatarComponent: Component {
|
|||||||
case let .peer(peer):
|
case let .peer(peer):
|
||||||
if !component.media.isEmpty {
|
if !component.media.isEmpty {
|
||||||
let imageNode: TransformImageNode
|
let imageNode: TransformImageNode
|
||||||
|
var isFirstTime = false
|
||||||
if let current = self.imageNode {
|
if let current = self.imageNode {
|
||||||
imageNode = current
|
imageNode = current
|
||||||
} else {
|
} else {
|
||||||
|
isFirstTime = true
|
||||||
imageNode = TransformImageNode()
|
imageNode = TransformImageNode()
|
||||||
imageNode.contentAnimations = [.subsequentUpdates]
|
imageNode.contentAnimations = [.subsequentUpdates]
|
||||||
self.addSubview(imageNode.view)
|
self.addSubview(imageNode.view)
|
||||||
self.imageNode = imageNode
|
self.imageNode = imageNode
|
||||||
|
}
|
||||||
if let image = component.media.first as? TelegramMediaImage {
|
|
||||||
if let imageDimensions = largestImageRepresentation(image.representations)?.dimensions {
|
if let image = component.media.first as? TelegramMediaImage {
|
||||||
dimensions = imageDimensions.cgSize.aspectFilled(size)
|
if let imageDimensions = largestImageRepresentation(image.representations)?.dimensions {
|
||||||
}
|
dimensions = imageDimensions.cgSize.aspectFilled(size)
|
||||||
|
}
|
||||||
|
if isFirstTime {
|
||||||
imageNode.setSignal(chatMessagePhotoThumbnail(account: component.context.account, userLocation: .other, photoReference: .standalone(media: image), onlyFullSize: false, blurred: false))
|
imageNode.setSignal(chatMessagePhotoThumbnail(account: component.context.account, userLocation: .other, photoReference: .standalone(media: image), onlyFullSize: false, blurred: false))
|
||||||
self.fetchDisposable.set(chatMessagePhotoInteractiveFetched(context: component.context, userLocation: .other, photoReference: .standalone(media: image), displayAtSize: nil, storeToDownloadsPeerId: nil).startStrict())
|
self.fetchDisposable.add(chatMessagePhotoInteractiveFetched(context: component.context, userLocation: .other, photoReference: .standalone(media: image), displayAtSize: nil, storeToDownloadsPeerId: nil).startStrict())
|
||||||
} else if let file = component.media.first as? TelegramMediaFile {
|
}
|
||||||
if let videoDimensions = file.dimensions {
|
} else if let file = component.media.first as? TelegramMediaFile {
|
||||||
dimensions = videoDimensions.cgSize.aspectFilled(size)
|
if let videoDimensions = file.dimensions {
|
||||||
}
|
dimensions = videoDimensions.cgSize.aspectFilled(size)
|
||||||
|
}
|
||||||
|
if isFirstTime {
|
||||||
imageNode.setSignal(mediaGridMessageVideo(postbox: component.context.account.postbox, userLocation: .other, videoReference: .standalone(media: file), autoFetchFullSizeThumbnail: true))
|
imageNode.setSignal(mediaGridMessageVideo(postbox: component.context.account.postbox, userLocation: .other, videoReference: .standalone(media: file), autoFetchFullSizeThumbnail: true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,10 +136,13 @@ public final class StarsAvatarComponent: Component {
|
|||||||
if component.media.count > 1 {
|
if component.media.count > 1 {
|
||||||
let secondImageNode: TransformImageNode
|
let secondImageNode: TransformImageNode
|
||||||
let imageFrameNode: UIView
|
let imageFrameNode: UIView
|
||||||
|
var secondDimensions = size
|
||||||
|
var isFirstTime = false
|
||||||
if let current = self.secondImageNode, let currentFrame = self.imageFrameNode {
|
if let current = self.secondImageNode, let currentFrame = self.imageFrameNode {
|
||||||
secondImageNode = current
|
secondImageNode = current
|
||||||
imageFrameNode = currentFrame
|
imageFrameNode = currentFrame
|
||||||
} else {
|
} else {
|
||||||
|
isFirstTime = true
|
||||||
secondImageNode = TransformImageNode()
|
secondImageNode = TransformImageNode()
|
||||||
secondImageNode.contentAnimations = [.firstUpdate, .subsequentUpdates]
|
secondImageNode.contentAnimations = [.firstUpdate, .subsequentUpdates]
|
||||||
self.insertSubview(secondImageNode.view, belowSubview: imageNode.view)
|
self.insertSubview(secondImageNode.view, belowSubview: imageNode.view)
|
||||||
@ -143,21 +152,27 @@ public final class StarsAvatarComponent: Component {
|
|||||||
imageFrameNode.layer.cornerRadius = 8.0
|
imageFrameNode.layer.cornerRadius = 8.0
|
||||||
self.insertSubview(imageFrameNode, belowSubview: imageNode.view)
|
self.insertSubview(imageFrameNode, belowSubview: imageNode.view)
|
||||||
self.imageFrameNode = imageFrameNode
|
self.imageFrameNode = imageFrameNode
|
||||||
|
}
|
||||||
if let image = component.media[1] as? TelegramMediaImage {
|
|
||||||
if let imageDimensions = largestImageRepresentation(image.representations)?.dimensions {
|
if let image = component.media[1] as? TelegramMediaImage {
|
||||||
dimensions = imageDimensions.cgSize.aspectFilled(size)
|
if let imageDimensions = largestImageRepresentation(image.representations)?.dimensions {
|
||||||
}
|
secondDimensions = imageDimensions.cgSize.aspectFilled(size)
|
||||||
|
}
|
||||||
|
if isFirstTime {
|
||||||
secondImageNode.setSignal(chatMessagePhotoThumbnail(account: component.context.account, userLocation: .other, photoReference: .standalone(media: image), onlyFullSize: false, blurred: false))
|
secondImageNode.setSignal(chatMessagePhotoThumbnail(account: component.context.account, userLocation: .other, photoReference: .standalone(media: image), onlyFullSize: false, blurred: false))
|
||||||
} else if let file = component.media[1] as? TelegramMediaFile {
|
self.fetchDisposable.add(chatMessagePhotoInteractiveFetched(context: component.context, userLocation: .other, photoReference: .standalone(media: image), displayAtSize: nil, storeToDownloadsPeerId: nil).startStrict())
|
||||||
if let videoDimensions = file.dimensions {
|
}
|
||||||
dimensions = videoDimensions.cgSize.aspectFilled(size)
|
} else if let file = component.media[1] as? TelegramMediaFile {
|
||||||
}
|
if let videoDimensions = file.dimensions {
|
||||||
|
secondDimensions = videoDimensions.cgSize.aspectFilled(size)
|
||||||
|
}
|
||||||
|
if isFirstTime {
|
||||||
secondImageNode.setSignal(mediaGridMessageVideo(postbox: component.context.account.postbox, userLocation: .other, videoReference: .standalone(media: file), useLargeThumbnail: true, autoFetchFullSizeThumbnail: true))
|
secondImageNode.setSignal(mediaGridMessageVideo(postbox: component.context.account.postbox, userLocation: .other, videoReference: .standalone(media: file), useLargeThumbnail: true, autoFetchFullSizeThumbnail: true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
imageFrameNode.backgroundColor = component.backgroundColor
|
imageFrameNode.backgroundColor = component.backgroundColor
|
||||||
secondImageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(radius: 8.0), imageSize: dimensions, boundingSize: size, intrinsicInsets: UIEdgeInsets(), emptyColor: component.theme.list.mediaPlaceholderColor))()
|
secondImageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(radius: 8.0), imageSize: secondDimensions, boundingSize: size, intrinsicInsets: UIEdgeInsets(), emptyColor: component.theme.list.mediaPlaceholderColor))()
|
||||||
secondImageNode.frame = imageFrame.offsetBy(dx: 4.0, dy: -4.0)
|
secondImageNode.frame = imageFrame.offsetBy(dx: 4.0, dy: -4.0)
|
||||||
imageFrameNode.frame = imageFrame.insetBy(dx: -1.0 - UIScreenPixel, dy: -1.0 - UIScreenPixel)
|
imageFrameNode.frame = imageFrame.insetBy(dx: -1.0 - UIScreenPixel, dy: -1.0 - UIScreenPixel)
|
||||||
}
|
}
|
||||||
@ -176,7 +191,7 @@ public final class StarsAvatarComponent: Component {
|
|||||||
self.imageNode = imageNode
|
self.imageNode = imageNode
|
||||||
|
|
||||||
imageNode.setSignal(chatWebFileImage(account: component.context.account, file: photo))
|
imageNode.setSignal(chatWebFileImage(account: component.context.account, file: photo))
|
||||||
self.fetchDisposable.set(chatMessageWebFileInteractiveFetched(account: component.context.account, userLocation: .other, image: photo).startStrict())
|
self.fetchDisposable.add(chatMessageWebFileInteractiveFetched(account: component.context.account, userLocation: .other, image: photo).startStrict())
|
||||||
}
|
}
|
||||||
|
|
||||||
imageNode.frame = CGRect(origin: .zero, size: size)
|
imageNode.frame = CGRect(origin: .zero, size: size)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import AsyncDisplayKit
|
||||||
import Display
|
import Display
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import Postbox
|
import Postbox
|
||||||
@ -292,19 +293,22 @@ public final class StarsImageComponent: Component {
|
|||||||
public let theme: PresentationTheme
|
public let theme: PresentationTheme
|
||||||
public let diameter: CGFloat
|
public let diameter: CGFloat
|
||||||
public let backgroundColor: UIColor
|
public let backgroundColor: UIColor
|
||||||
|
public let action: ((@escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void)?
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
subject: Subject,
|
subject: Subject,
|
||||||
theme: PresentationTheme,
|
theme: PresentationTheme,
|
||||||
diameter: CGFloat,
|
diameter: CGFloat,
|
||||||
backgroundColor: UIColor
|
backgroundColor: UIColor,
|
||||||
|
action: ((@escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void)? = nil
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.subject = subject
|
self.subject = subject
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.diameter = diameter
|
self.diameter = diameter
|
||||||
self.backgroundColor = backgroundColor
|
self.backgroundColor = backgroundColor
|
||||||
|
self.action = action
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: StarsImageComponent, rhs: StarsImageComponent) -> Bool {
|
public static func ==(lhs: StarsImageComponent, rhs: StarsImageComponent) -> Bool {
|
||||||
@ -328,10 +332,12 @@ public final class StarsImageComponent: Component {
|
|||||||
|
|
||||||
public final class View: UIView {
|
public final class View: UIView {
|
||||||
private var component: StarsImageComponent?
|
private var component: StarsImageComponent?
|
||||||
|
private var state: EmptyComponentState?
|
||||||
|
|
||||||
private var smallParticlesView: StarsParticlesView?
|
private var smallParticlesView: StarsParticlesView?
|
||||||
private var largeParticlesView: StarsParticlesView?
|
private var largeParticlesView: StarsParticlesView?
|
||||||
|
|
||||||
|
private var containerNode: ASDisplayNode?
|
||||||
private var imageNode: TransformImageNode?
|
private var imageNode: TransformImageNode?
|
||||||
private var imageFrameNode: UIView?
|
private var imageFrameNode: UIView?
|
||||||
private var secondImageNode: TransformImageNode?
|
private var secondImageNode: TransformImageNode?
|
||||||
@ -339,10 +345,14 @@ public final class StarsImageComponent: Component {
|
|||||||
private var iconBackgroundView: UIImageView?
|
private var iconBackgroundView: UIImageView?
|
||||||
private var iconView: UIImageView?
|
private var iconView: UIImageView?
|
||||||
private var dustNode: MediaDustNode?
|
private var dustNode: MediaDustNode?
|
||||||
|
private var button: UIControl?
|
||||||
|
|
||||||
private var countView = ComponentView<Empty>()
|
private var countView = ComponentView<Empty>()
|
||||||
|
|
||||||
private let fetchDisposable = MetaDisposable()
|
private let fetchDisposable = MetaDisposable()
|
||||||
|
private var hiddenMediaDisposable: Disposable?
|
||||||
|
|
||||||
|
private var hiddenMedia: [Media] = []
|
||||||
|
|
||||||
public override init(frame: CGRect) {
|
public override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
@ -353,10 +363,41 @@ public final class StarsImageComponent: Component {
|
|||||||
}
|
}
|
||||||
deinit {
|
deinit {
|
||||||
self.fetchDisposable.dispose()
|
self.fetchDisposable.dispose()
|
||||||
|
self.hiddenMediaDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(component: StarsImageComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
|
@objc private func buttonPressed() {
|
||||||
|
guard let component = self.component else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
component.action?({ [weak self] media in
|
||||||
|
guard let self else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return self.transitionNode(media)
|
||||||
|
}, { [weak self] view in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.superview?.addSubview(view)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public func transitionNode(_ transitionMedia: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
|
||||||
|
guard let component = self.component, let containerNode = self.containerNode else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if case let .media(media) = component.subject, media.first?.id == transitionMedia.id {
|
||||||
|
return (containerNode, containerNode.bounds, { [weak containerNode] in
|
||||||
|
return (containerNode?.view.snapshotContentTree(unhide: true), nil)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(component: StarsImageComponent, state: EmptyComponentState, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
|
||||||
self.component = component
|
self.component = component
|
||||||
|
self.state = state
|
||||||
|
|
||||||
let smallParticlesView: StarsParticlesView
|
let smallParticlesView: StarsParticlesView
|
||||||
if let current = self.smallParticlesView {
|
if let current = self.smallParticlesView {
|
||||||
@ -382,14 +423,26 @@ public final class StarsImageComponent: Component {
|
|||||||
largeParticlesView.update(size: availableSize)
|
largeParticlesView.update(size: availableSize)
|
||||||
largeParticlesView.frame = CGRect(origin: .zero, size: availableSize)
|
largeParticlesView.frame = CGRect(origin: .zero, size: availableSize)
|
||||||
|
|
||||||
|
let containerNode: ASDisplayNode
|
||||||
|
if let current = self.containerNode {
|
||||||
|
containerNode = current
|
||||||
|
} else {
|
||||||
|
containerNode = ASDisplayNode()
|
||||||
|
|
||||||
|
self.addSubview(containerNode.view)
|
||||||
|
self.containerNode = containerNode
|
||||||
|
}
|
||||||
|
|
||||||
var imageSize = CGSize(width: component.diameter, height: component.diameter)
|
var imageSize = CGSize(width: component.diameter, height: component.diameter)
|
||||||
|
let containerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - imageSize.width) / 2.0), y: floorToScreenPixels((availableSize.height - imageSize.height) / 2.0)), size: imageSize)
|
||||||
|
containerNode.frame = containerFrame
|
||||||
|
|
||||||
if case let .media(media) = component.subject, media.count > 1 {
|
if case let .media(media) = component.subject, media.count > 1 {
|
||||||
imageSize = CGSize(width: component.diameter - 6.0, height: component.diameter - 6.0)
|
imageSize = CGSize(width: component.diameter - 6.0, height: component.diameter - 6.0)
|
||||||
} else if case let .extendedMedia(media) = component.subject, media.count > 1 {
|
} else if case let .extendedMedia(media) = component.subject, media.count > 1 {
|
||||||
imageSize = CGSize(width: component.diameter - 6.0, height: component.diameter - 6.0)
|
imageSize = CGSize(width: component.diameter - 6.0, height: component.diameter - 6.0)
|
||||||
}
|
}
|
||||||
|
let imageFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((containerFrame.width - imageSize.width) / 2.0), y: floorToScreenPixels((containerFrame.height - imageSize.height) / 2.0)), size: imageSize)
|
||||||
let imageFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - imageSize.width) / 2.0), y: floorToScreenPixels((availableSize.height - imageSize.height) / 2.0)), size: imageSize)
|
|
||||||
|
|
||||||
switch component.subject {
|
switch component.subject {
|
||||||
case .none:
|
case .none:
|
||||||
@ -401,7 +454,7 @@ public final class StarsImageComponent: Component {
|
|||||||
} else {
|
} else {
|
||||||
imageNode = TransformImageNode()
|
imageNode = TransformImageNode()
|
||||||
imageNode.contentAnimations = [.firstUpdate, .subsequentUpdates]
|
imageNode.contentAnimations = [.firstUpdate, .subsequentUpdates]
|
||||||
self.addSubview(imageNode.view)
|
containerNode.view.addSubview(imageNode.view)
|
||||||
self.imageNode = imageNode
|
self.imageNode = imageNode
|
||||||
|
|
||||||
imageNode.setSignal(chatWebFileImage(account: component.context.account, file: photo))
|
imageNode.setSignal(chatWebFileImage(account: component.context.account, file: photo))
|
||||||
@ -413,60 +466,77 @@ public final class StarsImageComponent: Component {
|
|||||||
case let .media(media):
|
case let .media(media):
|
||||||
let imageNode: TransformImageNode
|
let imageNode: TransformImageNode
|
||||||
var dimensions = imageSize
|
var dimensions = imageSize
|
||||||
|
var isFirstTime = false
|
||||||
if let current = self.imageNode {
|
if let current = self.imageNode {
|
||||||
imageNode = current
|
imageNode = current
|
||||||
} else {
|
} else {
|
||||||
|
isFirstTime = true
|
||||||
imageNode = TransformImageNode()
|
imageNode = TransformImageNode()
|
||||||
imageNode.contentAnimations = [.firstUpdate, .subsequentUpdates]
|
imageNode.contentAnimations = [.firstUpdate, .subsequentUpdates]
|
||||||
self.addSubview(imageNode.view)
|
containerNode.view.addSubview(imageNode.view)
|
||||||
self.imageNode = imageNode
|
self.imageNode = imageNode
|
||||||
|
}
|
||||||
if let image = media.first as? TelegramMediaImage {
|
if let image = media.first as? TelegramMediaImage {
|
||||||
if let imageDimensions = largestImageRepresentation(image.representations)?.dimensions {
|
if let imageDimensions = largestImageRepresentation(image.representations)?.dimensions {
|
||||||
dimensions = imageDimensions.cgSize.aspectFilled(imageSize)
|
dimensions = imageDimensions.cgSize.aspectFilled(imageSize)
|
||||||
}
|
}
|
||||||
|
if isFirstTime {
|
||||||
imageNode.setSignal(chatMessagePhotoThumbnail(account: component.context.account, userLocation: .other, photoReference: .standalone(media: image), onlyFullSize: false, blurred: false))
|
imageNode.setSignal(chatMessagePhotoThumbnail(account: component.context.account, userLocation: .other, photoReference: .standalone(media: image), onlyFullSize: false, blurred: false))
|
||||||
} else if let file = media.first as? TelegramMediaFile {
|
}
|
||||||
if let videoDimensions = file.dimensions {
|
} else if let file = media.first as? TelegramMediaFile {
|
||||||
dimensions = videoDimensions.cgSize.aspectFilled(imageSize)
|
if let videoDimensions = file.dimensions {
|
||||||
}
|
dimensions = videoDimensions.cgSize.aspectFilled(imageSize)
|
||||||
|
}
|
||||||
|
if isFirstTime {
|
||||||
imageNode.setSignal(mediaGridMessageVideo(postbox: component.context.account.postbox, userLocation: .other, videoReference: .standalone(media: file), useLargeThumbnail: true, autoFetchFullSizeThumbnail: true))
|
imageNode.setSignal(mediaGridMessageVideo(postbox: component.context.account.postbox, userLocation: .other, videoReference: .standalone(media: file), useLargeThumbnail: true, autoFetchFullSizeThumbnail: true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
imageNode.frame = imageFrame
|
imageNode.frame = imageFrame
|
||||||
imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(radius: 16.0), imageSize: dimensions, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(), emptyColor: component.theme.list.mediaPlaceholderColor))()
|
imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(radius: 16.0), imageSize: dimensions, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(), emptyColor: component.theme.list.mediaPlaceholderColor))()
|
||||||
|
|
||||||
|
if let firstMedia = media.first, self.hiddenMedia.contains(where: { $0.id == firstMedia.id }) {
|
||||||
|
containerNode.isHidden = true
|
||||||
|
} else {
|
||||||
|
containerNode.isHidden = false
|
||||||
|
}
|
||||||
|
|
||||||
if media.count > 1 {
|
if media.count > 1 {
|
||||||
let secondImageNode: TransformImageNode
|
let secondImageNode: TransformImageNode
|
||||||
let imageFrameNode: UIView
|
let imageFrameNode: UIView
|
||||||
|
var secondDimensions = imageSize
|
||||||
if let current = self.secondImageNode, let currentFrame = self.imageFrameNode {
|
if let current = self.secondImageNode, let currentFrame = self.imageFrameNode {
|
||||||
secondImageNode = current
|
secondImageNode = current
|
||||||
imageFrameNode = currentFrame
|
imageFrameNode = currentFrame
|
||||||
} else {
|
} else {
|
||||||
secondImageNode = TransformImageNode()
|
secondImageNode = TransformImageNode()
|
||||||
secondImageNode.contentAnimations = [.firstUpdate, .subsequentUpdates]
|
secondImageNode.contentAnimations = [.firstUpdate, .subsequentUpdates]
|
||||||
self.insertSubview(secondImageNode.view, belowSubview: imageNode.view)
|
containerNode.view.insertSubview(secondImageNode.view, belowSubview: imageNode.view)
|
||||||
self.secondImageNode = secondImageNode
|
self.secondImageNode = secondImageNode
|
||||||
|
|
||||||
imageFrameNode = UIView()
|
imageFrameNode = UIView()
|
||||||
imageFrameNode.layer.cornerRadius = 17.0
|
imageFrameNode.layer.cornerRadius = 17.0
|
||||||
self.insertSubview(imageFrameNode, belowSubview: imageNode.view)
|
containerNode.view.insertSubview(imageFrameNode, belowSubview: imageNode.view)
|
||||||
self.imageFrameNode = imageFrameNode
|
self.imageFrameNode = imageFrameNode
|
||||||
|
}
|
||||||
if let image = media[1] as? TelegramMediaImage {
|
|
||||||
if let imageDimensions = largestImageRepresentation(image.representations)?.dimensions {
|
if let image = media[1] as? TelegramMediaImage {
|
||||||
dimensions = imageDimensions.cgSize.aspectFilled(imageSize)
|
if let imageDimensions = largestImageRepresentation(image.representations)?.dimensions {
|
||||||
}
|
secondDimensions = imageDimensions.cgSize.aspectFilled(imageSize)
|
||||||
|
}
|
||||||
|
if isFirstTime {
|
||||||
secondImageNode.setSignal(chatMessagePhotoThumbnail(account: component.context.account, userLocation: .other, photoReference: .standalone(media: image), onlyFullSize: false, blurred: false))
|
secondImageNode.setSignal(chatMessagePhotoThumbnail(account: component.context.account, userLocation: .other, photoReference: .standalone(media: image), onlyFullSize: false, blurred: false))
|
||||||
} else if let file = media[1] as? TelegramMediaFile {
|
}
|
||||||
if let videoDimensions = file.dimensions {
|
} else if let file = media[1] as? TelegramMediaFile {
|
||||||
dimensions = videoDimensions.cgSize.aspectFilled(imageSize)
|
if let videoDimensions = file.dimensions {
|
||||||
}
|
secondDimensions = videoDimensions.cgSize.aspectFilled(imageSize)
|
||||||
|
}
|
||||||
|
if isFirstTime {
|
||||||
secondImageNode.setSignal(mediaGridMessageVideo(postbox: component.context.account.postbox, userLocation: .other, videoReference: .standalone(media: file), useLargeThumbnail: true, autoFetchFullSizeThumbnail: true))
|
secondImageNode.setSignal(mediaGridMessageVideo(postbox: component.context.account.postbox, userLocation: .other, videoReference: .standalone(media: file), useLargeThumbnail: true, autoFetchFullSizeThumbnail: true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
imageFrameNode.backgroundColor = component.backgroundColor
|
imageFrameNode.backgroundColor = component.backgroundColor
|
||||||
secondImageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(radius: 16.0), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(), emptyColor: component.theme.list.mediaPlaceholderColor))()
|
secondImageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(radius: 16.0), imageSize: secondDimensions, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(), emptyColor: component.theme.list.mediaPlaceholderColor))()
|
||||||
secondImageNode.frame = imageFrame.offsetBy(dx: 6.0, dy: -6.0)
|
secondImageNode.frame = imageFrame.offsetBy(dx: 6.0, dy: -6.0)
|
||||||
imageFrameNode.frame = imageFrame.insetBy(dx: -2.0, dy: -2.0)
|
imageFrameNode.frame = imageFrame.insetBy(dx: -2.0, dy: -2.0)
|
||||||
|
|
||||||
@ -481,7 +551,7 @@ public final class StarsImageComponent: Component {
|
|||||||
let countFrame = CGRect(origin: CGPoint(x: imageFrame.minX + floorToScreenPixels((imageFrame.width - countSize.width) / 2.0), y: imageFrame.minY + floorToScreenPixels((imageFrame.height - countSize.height) / 2.0)), size: countSize)
|
let countFrame = CGRect(origin: CGPoint(x: imageFrame.minX + floorToScreenPixels((imageFrame.width - countSize.width) / 2.0), y: imageFrame.minY + floorToScreenPixels((imageFrame.height - countSize.height) / 2.0)), size: countSize)
|
||||||
if let countView = self.countView.view {
|
if let countView = self.countView.view {
|
||||||
if countView.superview == nil {
|
if countView.superview == nil {
|
||||||
self.addSubview(countView)
|
containerNode.view.addSubview(countView)
|
||||||
}
|
}
|
||||||
countView.frame = countFrame
|
countView.frame = countFrame
|
||||||
}
|
}
|
||||||
@ -489,72 +559,88 @@ public final class StarsImageComponent: Component {
|
|||||||
case let .extendedMedia(extendedMedia):
|
case let .extendedMedia(extendedMedia):
|
||||||
let imageNode: TransformImageNode
|
let imageNode: TransformImageNode
|
||||||
let dustNode: MediaDustNode
|
let dustNode: MediaDustNode
|
||||||
|
var dimensions = imageSize
|
||||||
|
var isFirstTime = false
|
||||||
if let current = self.imageNode, let currentDust = self.dustNode {
|
if let current = self.imageNode, let currentDust = self.dustNode {
|
||||||
imageNode = current
|
imageNode = current
|
||||||
dustNode = currentDust
|
dustNode = currentDust
|
||||||
} else {
|
} else {
|
||||||
|
isFirstTime = true
|
||||||
imageNode = TransformImageNode()
|
imageNode = TransformImageNode()
|
||||||
imageNode.contentAnimations = [.firstUpdate, .subsequentUpdates]
|
imageNode.contentAnimations = [.firstUpdate, .subsequentUpdates]
|
||||||
self.addSubview(imageNode.view)
|
containerNode.view.addSubview(imageNode.view)
|
||||||
self.imageNode = imageNode
|
self.imageNode = imageNode
|
||||||
|
|
||||||
let media: TelegramMediaImage
|
|
||||||
switch extendedMedia.first {
|
|
||||||
case let .preview(_, immediateThumbnailData, _):
|
|
||||||
let thumbnailMedia = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [], immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
|
||||||
media = thumbnailMedia
|
|
||||||
default:
|
|
||||||
fatalError()
|
|
||||||
}
|
|
||||||
|
|
||||||
imageNode.setSignal(chatSecretPhoto(account: component.context.account, userLocation: .other, photoReference: .standalone(media: media), ignoreFullSize: true, synchronousLoad: true))
|
|
||||||
|
|
||||||
dustNode = MediaDustNode(enableAnimations: true)
|
dustNode = MediaDustNode(enableAnimations: true)
|
||||||
dustNode.isUserInteractionEnabled = false
|
dustNode.isUserInteractionEnabled = false
|
||||||
self.addSubview(dustNode.view)
|
containerNode.view.addSubview(dustNode.view)
|
||||||
self.dustNode = dustNode
|
self.dustNode = dustNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let media: TelegramMediaImage
|
||||||
|
switch extendedMedia.first {
|
||||||
|
case let .preview(imageDimensions, immediateThumbnailData, _):
|
||||||
|
let thumbnailMedia = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [], immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
||||||
|
media = thumbnailMedia
|
||||||
|
if let imageDimensions {
|
||||||
|
dimensions = imageDimensions.cgSize.aspectFilled(imageSize)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
if isFirstTime {
|
||||||
|
imageNode.setSignal(chatSecretPhoto(account: component.context.account, userLocation: .other, photoReference: .standalone(media: media), ignoreFullSize: true, synchronousLoad: true))
|
||||||
|
}
|
||||||
|
|
||||||
|
imageNode.frame = imageFrame
|
||||||
|
imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(radius: 16.0), imageSize: dimensions, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(), emptyColor: component.theme.list.mediaPlaceholderColor))()
|
||||||
|
|
||||||
|
dustNode.frame = imageFrame
|
||||||
|
dustNode.update(size: imageFrame.size, color: .white, transition: .immediate)
|
||||||
|
|
||||||
if extendedMedia.count > 1 {
|
if extendedMedia.count > 1 {
|
||||||
let secondImageNode: TransformImageNode
|
let secondImageNode: TransformImageNode
|
||||||
let imageFrameNode: UIView
|
let imageFrameNode: UIView
|
||||||
|
var secondDimensions = imageSize
|
||||||
|
var isFirstTime = false
|
||||||
if let current = self.secondImageNode, let currentFrame = self.imageFrameNode {
|
if let current = self.secondImageNode, let currentFrame = self.imageFrameNode {
|
||||||
secondImageNode = current
|
secondImageNode = current
|
||||||
imageFrameNode = currentFrame
|
imageFrameNode = currentFrame
|
||||||
} else {
|
} else {
|
||||||
|
isFirstTime = true
|
||||||
secondImageNode = TransformImageNode()
|
secondImageNode = TransformImageNode()
|
||||||
secondImageNode.contentAnimations = [.firstUpdate, .subsequentUpdates]
|
secondImageNode.contentAnimations = [.firstUpdate, .subsequentUpdates]
|
||||||
self.insertSubview(secondImageNode.view, belowSubview: imageNode.view)
|
containerNode.view.insertSubview(secondImageNode.view, belowSubview: imageNode.view)
|
||||||
self.secondImageNode = secondImageNode
|
self.secondImageNode = secondImageNode
|
||||||
|
|
||||||
imageFrameNode = UIView()
|
imageFrameNode = UIView()
|
||||||
imageFrameNode.layer.cornerRadius = 17.0
|
imageFrameNode.layer.cornerRadius = 17.0
|
||||||
self.insertSubview(imageFrameNode, belowSubview: imageNode.view)
|
containerNode.view.insertSubview(imageFrameNode, belowSubview: imageNode.view)
|
||||||
self.imageFrameNode = imageFrameNode
|
self.imageFrameNode = imageFrameNode
|
||||||
|
}
|
||||||
let media: TelegramMediaImage
|
|
||||||
switch extendedMedia[1] {
|
let media: TelegramMediaImage
|
||||||
case let .preview(_, immediateThumbnailData, _):
|
switch extendedMedia[1] {
|
||||||
let thumbnailMedia = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [], immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
case let .preview(imageDimensions, immediateThumbnailData, _):
|
||||||
media = thumbnailMedia
|
let thumbnailMedia = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [], immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
||||||
default:
|
media = thumbnailMedia
|
||||||
fatalError()
|
if let imageDimensions {
|
||||||
|
secondDimensions = imageDimensions.cgSize.aspectFilled(imageSize)
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
|
||||||
|
if isFirstTime {
|
||||||
secondImageNode.setSignal(chatSecretPhoto(account: component.context.account, userLocation: .other, photoReference: .standalone(media: media), ignoreFullSize: true, synchronousLoad: true))
|
secondImageNode.setSignal(chatSecretPhoto(account: component.context.account, userLocation: .other, photoReference: .standalone(media: media), ignoreFullSize: true, synchronousLoad: true))
|
||||||
}
|
}
|
||||||
|
|
||||||
imageFrameNode.backgroundColor = component.backgroundColor
|
imageFrameNode.backgroundColor = component.backgroundColor
|
||||||
secondImageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(radius: 16.0), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(), emptyColor: component.theme.list.mediaPlaceholderColor))()
|
secondImageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(radius: 16.0), imageSize: secondDimensions, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(), emptyColor: component.theme.list.mediaPlaceholderColor))()
|
||||||
secondImageNode.frame = imageFrame.offsetBy(dx: 6.0, dy: -6.0)
|
secondImageNode.frame = imageFrame.offsetBy(dx: 6.0, dy: -6.0)
|
||||||
imageFrameNode.frame = imageFrame.insetBy(dx: -2.0, dy: -2.0)
|
imageFrameNode.frame = imageFrame.insetBy(dx: -2.0, dy: -2.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
imageNode.frame = imageFrame
|
|
||||||
imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(radius: 16.0), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(), emptyColor: component.theme.list.mediaPlaceholderColor))()
|
|
||||||
|
|
||||||
dustNode.frame = imageFrame
|
|
||||||
dustNode.update(size: imageFrame.size, color: .white, transition: .immediate)
|
|
||||||
|
|
||||||
if extendedMedia.count > 1 {
|
if extendedMedia.count > 1 {
|
||||||
let countSize = self.countView.update(
|
let countSize = self.countView.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
@ -567,7 +653,7 @@ public final class StarsImageComponent: Component {
|
|||||||
let countFrame = CGRect(origin: CGPoint(x: imageFrame.minX + floorToScreenPixels((imageFrame.width - countSize.width) / 2.0), y: imageFrame.minY + floorToScreenPixels((imageFrame.height - countSize.height) / 2.0)), size: countSize)
|
let countFrame = CGRect(origin: CGPoint(x: imageFrame.minX + floorToScreenPixels((imageFrame.width - countSize.width) / 2.0), y: imageFrame.minY + floorToScreenPixels((imageFrame.height - countSize.height) / 2.0)), size: countSize)
|
||||||
if let countView = self.countView.view {
|
if let countView = self.countView.view {
|
||||||
if countView.superview == nil {
|
if countView.superview == nil {
|
||||||
self.addSubview(countView)
|
containerNode.view.addSubview(countView)
|
||||||
}
|
}
|
||||||
countView.frame = countFrame
|
countView.frame = countFrame
|
||||||
}
|
}
|
||||||
@ -580,7 +666,7 @@ public final class StarsImageComponent: Component {
|
|||||||
} else {
|
} else {
|
||||||
avatarNode = ImageNode()
|
avatarNode = ImageNode()
|
||||||
avatarNode.displaysAsynchronously = false
|
avatarNode.displaysAsynchronously = false
|
||||||
self.addSubview(avatarNode.view)
|
containerNode.view.addSubview(avatarNode.view)
|
||||||
self.avatarNode = avatarNode
|
self.avatarNode = avatarNode
|
||||||
|
|
||||||
avatarNode.setSignal(peerAvatarCompleteImage(account: component.context.account, peer: peer, size: imageSize, font: avatarPlaceholderFont(size: 43.0), fullSize: true))
|
avatarNode.setSignal(peerAvatarCompleteImage(account: component.context.account, peer: peer, size: imageSize, font: avatarPlaceholderFont(size: 43.0), fullSize: true))
|
||||||
@ -596,8 +682,8 @@ public final class StarsImageComponent: Component {
|
|||||||
iconBackgroundView = UIImageView()
|
iconBackgroundView = UIImageView()
|
||||||
iconView = UIImageView()
|
iconView = UIImageView()
|
||||||
|
|
||||||
self.addSubview(iconBackgroundView)
|
containerNode.view.addSubview(iconBackgroundView)
|
||||||
self.addSubview(iconView)
|
containerNode.view.addSubview(iconView)
|
||||||
|
|
||||||
self.iconBackgroundView = iconBackgroundView
|
self.iconBackgroundView = iconBackgroundView
|
||||||
self.iconView = iconView
|
self.iconView = iconView
|
||||||
@ -670,6 +756,40 @@ public final class StarsImageComponent: Component {
|
|||||||
iconView.frame = imageFrame.insetBy(dx: iconInset, dy: iconInset).offsetBy(dx: 0.0, dy: iconOffset)
|
iconView.frame = imageFrame.insetBy(dx: iconInset, dy: iconInset).offsetBy(dx: 0.0, dy: iconOffset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let _ = component.action {
|
||||||
|
if self.button == nil {
|
||||||
|
let button = UIControl(frame: imageFrame)
|
||||||
|
button.addTarget(self, action: #selector(self.buttonPressed), for: .touchUpInside)
|
||||||
|
containerNode.view.addSubview(button)
|
||||||
|
self.button = button
|
||||||
|
}
|
||||||
|
} else if let button = self.button {
|
||||||
|
self.button = nil
|
||||||
|
button.removeFromSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
if case .media = component.subject {
|
||||||
|
if self.hiddenMediaDisposable == nil {
|
||||||
|
self.hiddenMediaDisposable = component.context.sharedContext.mediaManager.galleryHiddenMediaManager.hiddenIds().startStrict(next: { [weak self] ids in
|
||||||
|
guard let self, let component = self.component else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var hiddenMedia: [Media] = []
|
||||||
|
for id in ids {
|
||||||
|
if case let .chat(accountId, _, media) = id, accountId == component.context.account.id {
|
||||||
|
hiddenMedia.append(media)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.hiddenMedia = hiddenMedia
|
||||||
|
self.state?.updated()
|
||||||
|
}).strict()
|
||||||
|
}
|
||||||
|
} else if let hiddenMediaDisposable = self.hiddenMediaDisposable {
|
||||||
|
self.hiddenMediaDisposable = nil
|
||||||
|
hiddenMediaDisposable.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
return availableSize
|
return availableSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -679,6 +799,6 @@ public final class StarsImageComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
||||||
return view.update(component: self, availableSize: availableSize, transition: transition)
|
return view.update(component: self, state: state, availableSize: availableSize, transition: transition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ swift_library(
|
|||||||
"//submodules/Components/SolidRoundedButtonComponent",
|
"//submodules/Components/SolidRoundedButtonComponent",
|
||||||
"//submodules/AvatarNode",
|
"//submodules/AvatarNode",
|
||||||
"//submodules/TelegramUI/Components/Stars/StarsImageComponent",
|
"//submodules/TelegramUI/Components/Stars/StarsImageComponent",
|
||||||
|
"//submodules/GalleryUI",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -21,6 +21,7 @@ import TextFormat
|
|||||||
import TelegramStringFormatting
|
import TelegramStringFormatting
|
||||||
import UndoUI
|
import UndoUI
|
||||||
import StarsImageComponent
|
import StarsImageComponent
|
||||||
|
import GalleryUI
|
||||||
|
|
||||||
private final class StarsTransactionSheetContent: CombinedComponent {
|
private final class StarsTransactionSheetContent: CombinedComponent {
|
||||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||||
@ -31,6 +32,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
|||||||
let cancel: (Bool) -> Void
|
let cancel: (Bool) -> Void
|
||||||
let openPeer: (EnginePeer) -> Void
|
let openPeer: (EnginePeer) -> Void
|
||||||
let openMessage: (EngineMessage.Id) -> Void
|
let openMessage: (EngineMessage.Id) -> Void
|
||||||
|
let openMedia: ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void
|
||||||
let copyTransactionId: () -> Void
|
let copyTransactionId: () -> Void
|
||||||
|
|
||||||
init(
|
init(
|
||||||
@ -40,6 +42,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
|||||||
cancel: @escaping (Bool) -> Void,
|
cancel: @escaping (Bool) -> Void,
|
||||||
openPeer: @escaping (EnginePeer) -> Void,
|
openPeer: @escaping (EnginePeer) -> Void,
|
||||||
openMessage: @escaping (EngineMessage.Id) -> Void,
|
openMessage: @escaping (EngineMessage.Id) -> Void,
|
||||||
|
openMedia: @escaping ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void,
|
||||||
copyTransactionId: @escaping () -> Void
|
copyTransactionId: @escaping () -> Void
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
@ -48,6 +51,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
|||||||
self.cancel = cancel
|
self.cancel = cancel
|
||||||
self.openPeer = openPeer
|
self.openPeer = openPeer
|
||||||
self.openMessage = openMessage
|
self.openMessage = openMessage
|
||||||
|
self.openMedia = openMedia
|
||||||
self.copyTransactionId = copyTransactionId
|
self.copyTransactionId = copyTransactionId
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,7 +341,10 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
|||||||
subject: imageSubject,
|
subject: imageSubject,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
diameter: 90.0,
|
diameter: 90.0,
|
||||||
backgroundColor: theme.actionSheet.opaqueItemBackgroundColor
|
backgroundColor: theme.actionSheet.opaqueItemBackgroundColor,
|
||||||
|
action: !media.isEmpty ? { transitionNode, addToTransitionSurface in
|
||||||
|
component.openMedia(media, transitionNode, addToTransitionSurface)
|
||||||
|
} : nil
|
||||||
),
|
),
|
||||||
availableSize: CGSize(width: context.availableSize.width, height: 200.0),
|
availableSize: CGSize(width: context.availableSize.width, height: 200.0),
|
||||||
transition: .immediate
|
transition: .immediate
|
||||||
@ -642,6 +649,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent {
|
|||||||
let action: () -> Void
|
let action: () -> Void
|
||||||
let openPeer: (EnginePeer) -> Void
|
let openPeer: (EnginePeer) -> Void
|
||||||
let openMessage: (EngineMessage.Id) -> Void
|
let openMessage: (EngineMessage.Id) -> Void
|
||||||
|
let openMedia: ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void
|
||||||
let copyTransactionId: () -> Void
|
let copyTransactionId: () -> Void
|
||||||
|
|
||||||
init(
|
init(
|
||||||
@ -650,6 +658,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent {
|
|||||||
action: @escaping () -> Void,
|
action: @escaping () -> Void,
|
||||||
openPeer: @escaping (EnginePeer) -> Void,
|
openPeer: @escaping (EnginePeer) -> Void,
|
||||||
openMessage: @escaping (EngineMessage.Id) -> Void,
|
openMessage: @escaping (EngineMessage.Id) -> Void,
|
||||||
|
openMedia: @escaping ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void,
|
||||||
copyTransactionId: @escaping () -> Void
|
copyTransactionId: @escaping () -> Void
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
@ -657,6 +666,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent {
|
|||||||
self.action = action
|
self.action = action
|
||||||
self.openPeer = openPeer
|
self.openPeer = openPeer
|
||||||
self.openMessage = openMessage
|
self.openMessage = openMessage
|
||||||
|
self.openMedia = openMedia
|
||||||
self.copyTransactionId = copyTransactionId
|
self.copyTransactionId = copyTransactionId
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -700,6 +710,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent {
|
|||||||
},
|
},
|
||||||
openPeer: context.component.openPeer,
|
openPeer: context.component.openPeer,
|
||||||
openMessage: context.component.openMessage,
|
openMessage: context.component.openMessage,
|
||||||
|
openMedia: context.component.openMedia,
|
||||||
copyTransactionId: context.component.copyTransactionId
|
copyTransactionId: context.component.copyTransactionId
|
||||||
)),
|
)),
|
||||||
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
|
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
|
||||||
@ -787,6 +798,7 @@ public class StarsTransactionScreen: ViewControllerComponentContainer {
|
|||||||
|
|
||||||
var openPeerImpl: ((EnginePeer) -> Void)?
|
var openPeerImpl: ((EnginePeer) -> Void)?
|
||||||
var openMessageImpl: ((EngineMessage.Id) -> Void)?
|
var openMessageImpl: ((EngineMessage.Id) -> Void)?
|
||||||
|
var openMediaImpl: (([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void)?
|
||||||
var copyTransactionIdImpl: (() -> Void)?
|
var copyTransactionIdImpl: (() -> Void)?
|
||||||
super.init(
|
super.init(
|
||||||
context: context,
|
context: context,
|
||||||
@ -800,6 +812,9 @@ public class StarsTransactionScreen: ViewControllerComponentContainer {
|
|||||||
openMessage: { messageId in
|
openMessage: { messageId in
|
||||||
openMessageImpl?(messageId)
|
openMessageImpl?(messageId)
|
||||||
},
|
},
|
||||||
|
openMedia: { media, transitionNode, addToTransitionSurface in
|
||||||
|
openMediaImpl?(media, transitionNode, addToTransitionSurface)
|
||||||
|
},
|
||||||
copyTransactionId: {
|
copyTransactionId: {
|
||||||
copyTransactionIdImpl?()
|
copyTransactionIdImpl?()
|
||||||
}
|
}
|
||||||
@ -846,6 +861,47 @@ public class StarsTransactionScreen: ViewControllerComponentContainer {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openMediaImpl = { [weak self] media, transitionNode, addToTransitionSurface in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let message = Message(
|
||||||
|
stableId: 0,
|
||||||
|
stableVersion: 0,
|
||||||
|
id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(0)), namespace: Namespaces.Message.Local, id: 0),
|
||||||
|
globallyUniqueId: 0,
|
||||||
|
groupingKey: nil,
|
||||||
|
groupInfo: nil,
|
||||||
|
threadId: nil,
|
||||||
|
timestamp: 0,
|
||||||
|
flags: [],
|
||||||
|
tags: [],
|
||||||
|
globalTags: [],
|
||||||
|
localTags: [],
|
||||||
|
customTags: [],
|
||||||
|
forwardInfo: nil,
|
||||||
|
author: nil,
|
||||||
|
text: "",
|
||||||
|
attributes: [],
|
||||||
|
media: [TelegramMediaPaidContent(amount: 0, extendedMedia: media.map { .full(media: $0) })],
|
||||||
|
peers: SimpleDictionary(),
|
||||||
|
associatedMessages: SimpleDictionary(),
|
||||||
|
associatedMessageIds: [],
|
||||||
|
associatedMedia: [:],
|
||||||
|
associatedThreadInfo: nil,
|
||||||
|
associatedStories: [:]
|
||||||
|
)
|
||||||
|
let gallery = GalleryController(context: self.context, source: .standaloneMessage(message, 0), replaceRootController: { _, _ in
|
||||||
|
}, baseNavigationController: nil)
|
||||||
|
self.present(gallery, in: .window(.root), with: GalleryControllerPresentationArguments(transitionArguments: { messageId, media in
|
||||||
|
if let transitionNode = transitionNode(media) {
|
||||||
|
return GalleryTransitionArguments(transitionNode: transitionNode, addToTransitionSurface: addToTransitionSurface)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
copyTransactionIdImpl = { [weak self] in
|
copyTransactionIdImpl = { [weak self] in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
|
Loading…
x
Reference in New Issue
Block a user