mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Update API
This commit is contained in:
parent
8cfec897ee
commit
cdc82e4235
@ -13641,3 +13641,12 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Gift.View.Outgoing.NameHidden" = "Only %@ can see your name.";
|
||||
"Gift.View.Outgoing.NameAndMessageHidden" = "Only %@ can see your name and message.";
|
||||
|
||||
"Conversation.ViewStarGift" = "VIEW COLLECTIBLE";
|
||||
|
||||
"ChatList.AddPhoto.Title" = "Add your photo! 📸";
|
||||
"ChatList.AddPhoto.Text" = "Help your friends spot you easily.";
|
||||
|
||||
"Story.ViewGift" = "View Gift";
|
||||
|
||||
"Camera.OpenChat" = "Open Chat";
|
||||
|
@ -318,6 +318,7 @@ public enum ResolvedUrl {
|
||||
case boost(peerId: PeerId?, status: ChannelBoostStatus?, myBoostStatus: MyBoostStatus?)
|
||||
case premiumGiftCode(slug: String)
|
||||
case premiumMultiGift(reference: String?)
|
||||
case collectible(gift: StarGift.UniqueGift?)
|
||||
case messageLink(link: TelegramResolvedMessageLink?)
|
||||
}
|
||||
|
||||
@ -1099,10 +1100,13 @@ public protocol SharedAccountContext: AnyObject {
|
||||
func makeStarsGiftScreen(context: AccountContext, message: EngineMessage) -> ViewController
|
||||
func makeStarsGiveawayBoostScreen(context: AccountContext, peerId: EnginePeer.Id, boost: ChannelBoostersContext.State.Boost) -> ViewController
|
||||
func makeStarsIntroScreen(context: AccountContext) -> ViewController
|
||||
func makeGiftViewScreen(context: AccountContext, message: EngineMessage) -> ViewController
|
||||
func makeGiftViewScreen(context: AccountContext, message: EngineMessage, shareStory: (() -> Void)?) -> ViewController
|
||||
func makeGiftViewScreen(context: AccountContext, gift: StarGift.UniqueGift, shareStory: (() -> Void)?) -> ViewController
|
||||
|
||||
func makeContentReportScreen(context: AccountContext, subject: ReportContentSubject, forceDark: Bool, present: @escaping (ViewController) -> Void, completion: @escaping () -> Void, requestSelectMessages: ((String, Data, String?) -> Void)?)
|
||||
|
||||
func makeShareController(context: AccountContext, subject: ShareControllerSubject, forceExternal: Bool, shareStory: (() -> Void)?, actionCompleted: (() -> Void)?) -> ViewController
|
||||
|
||||
func makeMiniAppListScreenInitialData(context: AccountContext) -> Signal<MiniAppListScreenInitialData, NoError>
|
||||
func makeMiniAppListScreen(context: AccountContext, initialData: MiniAppListScreenInitialData) -> ViewController
|
||||
|
||||
@ -1338,28 +1342,3 @@ public struct StickersSearchConfiguration {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public protocol ShareControllerAccountContext: AnyObject {
|
||||
var accountId: AccountRecordId { get }
|
||||
var accountPeerId: EnginePeer.Id { get }
|
||||
var stateManager: AccountStateManager { get }
|
||||
var engineData: TelegramEngine.EngineData { get }
|
||||
var animationCache: AnimationCache { get }
|
||||
var animationRenderer: MultiAnimationRenderer { get }
|
||||
var contentSettings: ContentSettings { get }
|
||||
var appConfiguration: AppConfiguration { get }
|
||||
|
||||
func resolveInlineStickers(fileIds: [Int64]) -> Signal<[Int64: TelegramMediaFile], NoError>
|
||||
}
|
||||
|
||||
public protocol ShareControllerEnvironment: AnyObject {
|
||||
var presentationData: PresentationData { get }
|
||||
var updatedPresentationData: Signal<PresentationData, NoError> { get }
|
||||
var isMainApp: Bool { get }
|
||||
var energyUsageSettings: EnergyUsageSettings { get }
|
||||
|
||||
var mediaManager: MediaManager? { get }
|
||||
|
||||
func setAccountUserInterfaceInUse(id: AccountRecordId) -> Disposable
|
||||
func donateSendMessageIntent(account: ShareControllerAccountContext, peerIds: [EnginePeer.Id])
|
||||
}
|
||||
|
55
submodules/AccountContext/Sources/ShareController.swift
Normal file
55
submodules/AccountContext/Sources/ShareController.swift
Normal file
@ -0,0 +1,55 @@
|
||||
import Foundation
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
|
||||
public protocol ShareControllerAccountContext: AnyObject {
|
||||
var accountId: AccountRecordId { get }
|
||||
var accountPeerId: EnginePeer.Id { get }
|
||||
var stateManager: AccountStateManager { get }
|
||||
var engineData: TelegramEngine.EngineData { get }
|
||||
var animationCache: AnimationCache { get }
|
||||
var animationRenderer: MultiAnimationRenderer { get }
|
||||
var contentSettings: ContentSettings { get }
|
||||
var appConfiguration: AppConfiguration { get }
|
||||
|
||||
func resolveInlineStickers(fileIds: [Int64]) -> Signal<[Int64: TelegramMediaFile], NoError>
|
||||
}
|
||||
|
||||
public protocol ShareControllerEnvironment: AnyObject {
|
||||
var presentationData: PresentationData { get }
|
||||
var updatedPresentationData: Signal<PresentationData, NoError> { get }
|
||||
var isMainApp: Bool { get }
|
||||
var energyUsageSettings: EnergyUsageSettings { get }
|
||||
|
||||
var mediaManager: MediaManager? { get }
|
||||
|
||||
func setAccountUserInterfaceInUse(id: AccountRecordId) -> Disposable
|
||||
func donateSendMessageIntent(account: ShareControllerAccountContext, peerIds: [EnginePeer.Id])
|
||||
}
|
||||
|
||||
public enum ShareControllerExternalStatus {
|
||||
case preparing(Bool)
|
||||
case progress(Float)
|
||||
case done
|
||||
}
|
||||
|
||||
public enum ShareControllerError {
|
||||
case generic
|
||||
case fileTooBig(Int64)
|
||||
}
|
||||
|
||||
public enum ShareControllerSubject {
|
||||
case url(String)
|
||||
case text(String)
|
||||
case quote(text: String, url: String)
|
||||
case messages([Message])
|
||||
case image([ImageRepresentationWithReference])
|
||||
case media(AnyMediaReference)
|
||||
case mapMedia(TelegramMediaMap)
|
||||
case fromExternal(([PeerId], [PeerId: Int64], String, ShareControllerAccountContext, Bool) -> Signal<ShareControllerExternalStatus, ShareControllerError>)
|
||||
}
|
@ -6538,7 +6538,13 @@ private final class ChatListLocationContext {
|
||||
if channel.flags.contains(.requestToJoin) {
|
||||
actionTitle = presentationData.strings.Group_ApplyToJoin
|
||||
} else {
|
||||
actionTitle = presentationData.strings.Channel_JoinChannel
|
||||
switch channel.info {
|
||||
case .broadcast:
|
||||
actionTitle = presentationData.strings.Channel_JoinChannel
|
||||
case .group:
|
||||
actionTitle = presentationData.strings.Group_JoinGroup
|
||||
}
|
||||
|
||||
}
|
||||
toolbar = Toolbar(leftAction: nil, rightAction: nil, middleAction: ToolbarAction(title: actionTitle, isEnabled: true))
|
||||
}
|
||||
|
@ -289,9 +289,8 @@ final class ChatListNoticeItemNode: ItemListRevealOptionsItemNode {
|
||||
titleString = attributedTitle
|
||||
textString = NSAttributedString(string: text, font: smallTextFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
|
||||
case let .setupPhoto(accountPeer):
|
||||
//TODO:localize
|
||||
titleString = NSAttributedString(string: "Add your photo! 📸", font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor)
|
||||
textString = NSAttributedString(string: "Help your friends spot you easily.", font: smallTextFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
|
||||
titleString = NSAttributedString(string: item.strings.ChatList_AddPhoto_Title, font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor)
|
||||
textString = NSAttributedString(string: item.strings.ChatList_AddPhoto_Text, font: smallTextFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
|
||||
avatarPeer = accountPeer
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/LottieComponent",
|
||||
"//submodules/TelegramUI/Components/LottieComponentResourceContent",
|
||||
"//submodules/ImageTransparency",
|
||||
"//submodules/GalleryUI",
|
||||
#"//submodules/GalleryUI",
|
||||
"//submodules/MediaPlayer:UniversalMediaPlayer",
|
||||
"//submodules/TelegramUniversalVideoContent",
|
||||
"//submodules/TelegramUI/Components/CameraButtonComponent",
|
||||
|
@ -142,6 +142,8 @@ public class DrawingStickerEntityView: DrawingEntityView {
|
||||
return image
|
||||
} else if case .message = self.stickerEntity.content {
|
||||
return self.animatedImageView?.image
|
||||
} else if case .gift = self.stickerEntity.content {
|
||||
return self.animatedImageView?.image
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
@ -167,7 +169,7 @@ public class DrawingStickerEntityView: DrawingEntityView {
|
||||
return file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0)
|
||||
case .dualVideoReference:
|
||||
return CGSize(width: 512.0, height: 512.0)
|
||||
case let .message(_, size, _, _, _):
|
||||
case let .message(_, size, _, _, _), let .gift(_, size):
|
||||
return size
|
||||
}
|
||||
}
|
||||
@ -296,6 +298,43 @@ public class DrawingStickerEntityView: DrawingEntityView {
|
||||
if let file, let _ = mediaRect {
|
||||
self.setupWithVideo(file)
|
||||
}
|
||||
} else if case let .gift(gift, _) = self.stickerEntity.content {
|
||||
if let image = self.stickerEntity.renderImage {
|
||||
self.setupWithImage(image, overlayImage: self.stickerEntity.overlayRenderImage)
|
||||
}
|
||||
|
||||
var file: TelegramMediaFile?
|
||||
for attribute in gift.attributes {
|
||||
if case let .model(_, fileValue, _) = attribute {
|
||||
file = fileValue
|
||||
break
|
||||
}
|
||||
}
|
||||
guard let file, let dimensions = file.dimensions else {
|
||||
return
|
||||
}
|
||||
if self.animationNode == nil {
|
||||
let animationNode = DefaultAnimatedStickerNodeImpl()
|
||||
animationNode.clipsToBounds = true
|
||||
animationNode.autoplay = false
|
||||
self.animationNode = animationNode
|
||||
animationNode.started = { [weak self, weak animationNode] in
|
||||
self?.imageNode.isHidden = true
|
||||
|
||||
if let animationNode = animationNode {
|
||||
let _ = (animationNode.status
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||
self?.started?(status.duration)
|
||||
})
|
||||
}
|
||||
}
|
||||
self.addSubnode(self.imageNode)
|
||||
self.addSubnode(animationNode)
|
||||
}
|
||||
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: self.context.account.postbox, userLocation: .other, file: file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 256.0, height: 256.0))))
|
||||
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: stickerPackFileReference(file), resource: file.resource).start())
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
}
|
||||
|
||||
@ -418,7 +457,18 @@ public class DrawingStickerEntityView: DrawingEntityView {
|
||||
if self.isPlaying != isPlaying {
|
||||
self.isPlaying = isPlaying
|
||||
|
||||
if let file = self.file {
|
||||
var file: TelegramMediaFile?
|
||||
if let fileValue = self.file {
|
||||
file = fileValue
|
||||
} else if case let .gift(gift, _) = self.stickerEntity.content {
|
||||
for attribute in gift.attributes {
|
||||
if case let .model(_, fileValue, _) = attribute {
|
||||
file = fileValue
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if let file {
|
||||
if isPlaying && !self.didSetUpAnimationNode {
|
||||
self.didSetUpAnimationNode = true
|
||||
let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512)
|
||||
@ -596,15 +646,22 @@ public class DrawingStickerEntityView: DrawingEntityView {
|
||||
|
||||
let imageSize = self.dimensions.aspectFitted(boundingSize)
|
||||
let imageFrame = CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) / 2.0), y: (size.height - imageSize.height) / 2.0), size: imageSize)
|
||||
|
||||
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))()
|
||||
self.imageNode.frame = imageFrame
|
||||
|
||||
var animationSize = CGSize(width: imageSize.width, height: imageSize.width)
|
||||
var animationFrame = imageFrame
|
||||
if case .gift = self.stickerEntity.content {
|
||||
animationSize = CGSize(width: animationSize.width * 0.48, height: animationSize.height * 0.48)
|
||||
animationFrame = CGRect(origin: CGPoint(x: floor((size.width - animationSize.width) / 2.0), y: 22.0), size: animationSize)
|
||||
}
|
||||
|
||||
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: animationSize, boundingSize: animationSize, intrinsicInsets: UIEdgeInsets()))()
|
||||
self.imageNode.frame = animationFrame
|
||||
if let animationNode = self.animationNode {
|
||||
if self.isReaction {
|
||||
animationNode.cornerRadius = floor(imageSize.width * 0.1)
|
||||
animationNode.cornerRadius = floor(animationSize.width * 0.1)
|
||||
}
|
||||
animationNode.frame = imageFrame
|
||||
animationNode.updateLayout(size: imageSize)
|
||||
animationNode.frame = animationFrame
|
||||
animationNode.updateLayout(size: animationSize)
|
||||
|
||||
if !self.didApplyVisibility {
|
||||
self.didApplyVisibility = true
|
||||
@ -818,6 +875,35 @@ public class DrawingStickerEntityView: DrawingEntityView {
|
||||
|
||||
return entities
|
||||
}
|
||||
} else if case let .gift(gift, _) = self.stickerEntity.content {
|
||||
var file: TelegramMediaFile?
|
||||
for attribute in gift.attributes {
|
||||
if case let .model(_, fileValue, _) = attribute {
|
||||
file = fileValue
|
||||
break
|
||||
}
|
||||
}
|
||||
if let file, let animationNode = self.animationNode {
|
||||
let stickerSize = self.bounds.size
|
||||
let stickerPosition = self.stickerEntity.position
|
||||
let videoSize = animationNode.frame.size
|
||||
let scale = self.stickerEntity.scale
|
||||
let rotation = self.stickerEntity.rotation
|
||||
|
||||
let videoPosition = animationNode.position.offsetBy(dx: -stickerSize.width / 2.0, dy: -stickerSize.height / 2.0)
|
||||
let videoScale = videoSize.width / stickerSize.width
|
||||
|
||||
let videoEntity = DrawingStickerEntity(content: .file(.standalone(media: file), .sticker))
|
||||
videoEntity.referenceDrawingSize = self.stickerEntity.referenceDrawingSize
|
||||
videoEntity.position = stickerPosition.offsetBy(
|
||||
dx: (videoPosition.x * cos(rotation) - videoPosition.y * sin(rotation)) * scale,
|
||||
dy: (videoPosition.y * cos(rotation) + videoPosition.x * sin(rotation)) * scale
|
||||
)
|
||||
videoEntity.scale = scale * videoScale
|
||||
videoEntity.rotation = rotation
|
||||
|
||||
return [videoEntity]
|
||||
}
|
||||
}
|
||||
return []
|
||||
}
|
||||
@ -1103,6 +1189,9 @@ final class DrawingStickerEntitySelectionView: DrawingEntitySelectionView {
|
||||
if case .message = entity.content {
|
||||
cornerRadius *= 2.1
|
||||
count = 24
|
||||
} else if case .gift = entity.content {
|
||||
cornerRadius *= 2.1
|
||||
count = 24
|
||||
} else if case .image = entity.content {
|
||||
count = 24
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
|
||||
case let .image(image, _):
|
||||
self.file = nil
|
||||
self.imagePromise.set(.single(image))
|
||||
case .animatedImage, .video, .dualVideoReference, .message:
|
||||
case .animatedImage, .video, .dualVideoReference, .message, .gift:
|
||||
self.file = nil
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,9 @@ swift_library(
|
||||
"//submodules/Components/MultilineTextComponent",
|
||||
"//submodules/Components/BundleIconComponent",
|
||||
"//submodules/TelegramUI/Components/LottieComponent",
|
||||
#"//submodules/TelegramUI/Components/MessageInputPanelComponent",
|
||||
"//submodules/TelegramUI/Components/MessageInputPanelComponent",
|
||||
"//submodules/TelegramUI/Components/ChatEntityKeyboardInputNode",
|
||||
"//submodules/ChatPresentationInterfaceState",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -40,17 +40,6 @@ public enum ShareControllerPreferredAction {
|
||||
case custom(action: ShareControllerAction)
|
||||
}
|
||||
|
||||
public enum ShareControllerExternalStatus {
|
||||
case preparing(Bool)
|
||||
case progress(Float)
|
||||
case done
|
||||
}
|
||||
|
||||
public enum ShareControllerError {
|
||||
case generic
|
||||
case fileTooBig(Int64)
|
||||
}
|
||||
|
||||
public struct ShareControllerSegmentedValue {
|
||||
let title: String
|
||||
let subject: ShareControllerSubject
|
||||
@ -65,17 +54,6 @@ public struct ShareControllerSegmentedValue {
|
||||
}
|
||||
}
|
||||
|
||||
public enum ShareControllerSubject {
|
||||
case url(String)
|
||||
case text(String)
|
||||
case quote(text: String, url: String)
|
||||
case messages([Message])
|
||||
case image([ImageRepresentationWithReference])
|
||||
case media(AnyMediaReference)
|
||||
case mapMedia(TelegramMediaMap)
|
||||
case fromExternal(([PeerId], [PeerId: Int64], String, ShareControllerAccountContext, Bool) -> Signal<ShareControllerExternalStatus, ShareControllerError>)
|
||||
}
|
||||
|
||||
private enum ExternalShareItem {
|
||||
case text(String)
|
||||
case url(URL)
|
||||
|
@ -18,7 +18,6 @@ swift_library(
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
|
||||
"//submodules/ShareController:ShareController",
|
||||
"//submodules/StickerResources:StickerResources",
|
||||
"//submodules/AlertUI:AlertUI",
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
|
@ -7,7 +7,6 @@ import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import TelegramUIPreferences
|
||||
import AccountContext
|
||||
import ShareController
|
||||
import StickerResources
|
||||
import AlertUI
|
||||
import PresentationDataUtils
|
||||
@ -116,15 +115,19 @@ public final class StickerPackPreviewController: ViewController, StandalonePrese
|
||||
}
|
||||
|
||||
if let stickerPackContentsValue = strongSelf.stickerPackContentsValue, case let .result(info, _, _) = stickerPackContentsValue, !info.shortName.isEmpty {
|
||||
let shareController = ShareController(context: strongSelf.context, subject: .url("https://t.me/addstickers/\(info.shortName)"), externalShare: true)
|
||||
|
||||
let parentNavigationController = strongSelf.parentNavigationController
|
||||
shareController.actionCompleted = { [weak parentNavigationController] in
|
||||
if let parentNavigationController = parentNavigationController, let controller = parentNavigationController.topViewController as? ViewController {
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
controller.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
let shareController = strongSelf.context.sharedContext.makeShareController(
|
||||
context: strongSelf.context,
|
||||
subject: .url("https://t.me/addstickers/\(info.shortName)"),
|
||||
forceExternal: true,
|
||||
shareStory: nil,
|
||||
actionCompleted: { [weak parentNavigationController] in
|
||||
if let parentNavigationController = parentNavigationController, let controller = parentNavigationController.topViewController as? ViewController {
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
controller.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
strongSelf.present(shareController, in: .window(.root))
|
||||
strongSelf.dismiss()
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import ShimmerEffect
|
||||
import ContextUI
|
||||
import MoreButtonNode
|
||||
import UndoUI
|
||||
import ShareController
|
||||
import TextFormat
|
||||
import PremiumUI
|
||||
import OverlayStatusController
|
||||
@ -1133,13 +1132,18 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
|
||||
if let strongSelf = self {
|
||||
let parentNavigationController = strongSelf.controller?.parentNavigationController
|
||||
let shareController = ShareController(context: strongSelf.context, subject: shareSubject)
|
||||
shareController.actionCompleted = { [weak parentNavigationController] in
|
||||
if let parentNavigationController = parentNavigationController, let controller = parentNavigationController.topViewController as? ViewController {
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
controller.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
let shareController = strongSelf.context.sharedContext.makeShareController(
|
||||
context: strongSelf.context,
|
||||
subject: shareSubject,
|
||||
forceExternal: false,
|
||||
shareStory: nil,
|
||||
actionCompleted: { [weak parentNavigationController] in
|
||||
if let parentNavigationController = parentNavigationController, let controller = parentNavigationController.topViewController as? ViewController {
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
controller.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
strongSelf.controller?.present(shareController, in: .window(.root))
|
||||
}
|
||||
})))
|
||||
|
@ -534,6 +534,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1300094593] = { return Api.MediaArea.parse_inputMediaAreaVenue($0) }
|
||||
dict[1996756655] = { return Api.MediaArea.parse_mediaAreaChannelPost($0) }
|
||||
dict[-891992787] = { return Api.MediaArea.parse_mediaAreaGeoPoint($0) }
|
||||
dict[1468491885] = { return Api.MediaArea.parse_mediaAreaStarGift($0) }
|
||||
dict[340088945] = { return Api.MediaArea.parse_mediaAreaSuggestedReaction($0) }
|
||||
dict[926421125] = { return Api.MediaArea.parse_mediaAreaUrl($0) }
|
||||
dict[-1098720356] = { return Api.MediaArea.parse_mediaAreaVenue($0) }
|
||||
@ -909,7 +910,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1301522832] = { return Api.SponsoredMessage.parse_sponsoredMessage($0) }
|
||||
dict[1124938064] = { return Api.SponsoredMessageReportOption.parse_sponsoredMessageReportOption($0) }
|
||||
dict[46953416] = { return Api.StarGift.parse_starGift($0) }
|
||||
dict[1779697613] = { return Api.StarGift.parse_starGiftUnique($0) }
|
||||
dict[880997154] = { return Api.StarGift.parse_starGiftUnique($0) }
|
||||
dict[-1809377438] = { return Api.StarGiftAttribute.parse_starGiftAttributeBackdrop($0) }
|
||||
dict[970559507] = { return Api.StarGiftAttribute.parse_starGiftAttributeModel($0) }
|
||||
dict[-1070837941] = { return Api.StarGiftAttribute.parse_starGiftAttributeOriginalDetails($0) }
|
||||
@ -1156,6 +1157,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1355547603] = { return Api.WebPageAttribute.parse_webPageAttributeStickerSet($0) }
|
||||
dict[781501415] = { return Api.WebPageAttribute.parse_webPageAttributeStory($0) }
|
||||
dict[1421174295] = { return Api.WebPageAttribute.parse_webPageAttributeTheme($0) }
|
||||
dict[-814781000] = { return Api.WebPageAttribute.parse_webPageAttributeUniqueStarGift($0) }
|
||||
dict[211046684] = { return Api.WebViewMessageSent.parse_webViewMessageSent($0) }
|
||||
dict[1294139288] = { return Api.WebViewResult.parse_webViewResultUrl($0) }
|
||||
dict[-1389486888] = { return Api.account.AuthorizationForm.parse_authorizationForm($0) }
|
||||
@ -1361,6 +1363,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[870003448] = { return Api.messages.TranslatedText.parse_translateResult($0) }
|
||||
dict[1218005070] = { return Api.messages.VotesList.parse_votesList($0) }
|
||||
dict[-44166467] = { return Api.messages.WebPage.parse_webPage($0) }
|
||||
dict[-1254192351] = { return Api.messages.WebPagePreview.parse_webPagePreview($0) }
|
||||
dict[1042605427] = { return Api.payments.BankCardData.parse_bankCardData($0) }
|
||||
dict[675942550] = { return Api.payments.CheckedGiftCode.parse_checkedGiftCode($0) }
|
||||
dict[-1730811363] = { return Api.payments.ConnectedStarRefBots.parse_connectedStarRefBots($0) }
|
||||
@ -1383,6 +1386,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[497778871] = { return Api.payments.StarsRevenueWithdrawalUrl.parse_starsRevenueWithdrawalUrl($0) }
|
||||
dict[1822222573] = { return Api.payments.StarsStatus.parse_starsStatus($0) }
|
||||
dict[-1261053863] = { return Api.payments.SuggestedStarRefBots.parse_suggestedStarRefBots($0) }
|
||||
dict[-895289845] = { return Api.payments.UniqueStarGift.parse_uniqueStarGift($0) }
|
||||
dict[1801827607] = { return Api.payments.UserStarGifts.parse_userStarGifts($0) }
|
||||
dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) }
|
||||
dict[541839704] = { return Api.phone.ExportedGroupCallInvite.parse_exportedGroupCallInvite($0) }
|
||||
@ -2440,6 +2444,8 @@ public extension Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.WebPage:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.WebPagePreview:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.payments.BankCardData:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.payments.CheckedGiftCode:
|
||||
@ -2472,6 +2478,8 @@ public extension Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.payments.SuggestedStarRefBots:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.payments.UniqueStarGift:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.payments.UserStarGifts:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.payments.ValidatedRequestedInfo:
|
||||
|
@ -868,6 +868,7 @@ public extension Api {
|
||||
case inputMediaAreaVenue(coordinates: Api.MediaAreaCoordinates, queryId: Int64, resultId: String)
|
||||
case mediaAreaChannelPost(coordinates: Api.MediaAreaCoordinates, channelId: Int64, msgId: Int32)
|
||||
case mediaAreaGeoPoint(flags: Int32, coordinates: Api.MediaAreaCoordinates, geo: Api.GeoPoint, address: Api.GeoPointAddress?)
|
||||
case mediaAreaStarGift(coordinates: Api.MediaAreaCoordinates, slug: String)
|
||||
case mediaAreaSuggestedReaction(flags: Int32, coordinates: Api.MediaAreaCoordinates, reaction: Api.Reaction)
|
||||
case mediaAreaUrl(coordinates: Api.MediaAreaCoordinates, url: String)
|
||||
case mediaAreaVenue(coordinates: Api.MediaAreaCoordinates, geo: Api.GeoPoint, title: String, address: String, provider: String, venueId: String, venueType: String)
|
||||
@ -908,6 +909,13 @@ public extension Api {
|
||||
geo.serialize(buffer, true)
|
||||
if Int(flags) & Int(1 << 0) != 0 {address!.serialize(buffer, true)}
|
||||
break
|
||||
case .mediaAreaStarGift(let coordinates, let slug):
|
||||
if boxed {
|
||||
buffer.appendInt32(1468491885)
|
||||
}
|
||||
coordinates.serialize(buffer, true)
|
||||
serializeString(slug, buffer: buffer, boxed: false)
|
||||
break
|
||||
case .mediaAreaSuggestedReaction(let flags, let coordinates, let reaction):
|
||||
if boxed {
|
||||
buffer.appendInt32(340088945)
|
||||
@ -957,6 +965,8 @@ public extension Api {
|
||||
return ("mediaAreaChannelPost", [("coordinates", coordinates as Any), ("channelId", channelId as Any), ("msgId", msgId as Any)])
|
||||
case .mediaAreaGeoPoint(let flags, let coordinates, let geo, let address):
|
||||
return ("mediaAreaGeoPoint", [("flags", flags as Any), ("coordinates", coordinates as Any), ("geo", geo as Any), ("address", address as Any)])
|
||||
case .mediaAreaStarGift(let coordinates, let slug):
|
||||
return ("mediaAreaStarGift", [("coordinates", coordinates as Any), ("slug", slug as Any)])
|
||||
case .mediaAreaSuggestedReaction(let flags, let coordinates, let reaction):
|
||||
return ("mediaAreaSuggestedReaction", [("flags", flags as Any), ("coordinates", coordinates as Any), ("reaction", reaction as Any)])
|
||||
case .mediaAreaUrl(let coordinates, let url):
|
||||
@ -1053,6 +1063,22 @@ public extension Api {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_mediaAreaStarGift(_ reader: BufferReader) -> MediaArea? {
|
||||
var _1: Api.MediaAreaCoordinates?
|
||||
if let signature = reader.readInt32() {
|
||||
_1 = Api.parse(reader, signature: signature) as? Api.MediaAreaCoordinates
|
||||
}
|
||||
var _2: String?
|
||||
_2 = parseString(reader)
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.MediaArea.mediaAreaStarGift(coordinates: _1!, slug: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_mediaAreaSuggestedReaction(_ reader: BufferReader) -> MediaArea? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
|
@ -575,7 +575,7 @@ public extension Api {
|
||||
public extension Api {
|
||||
enum StarGift: TypeConstructorDescription {
|
||||
case starGift(flags: Int32, id: Int64, sticker: Api.Document, stars: Int64, availabilityRemains: Int32?, availabilityTotal: Int32?, convertStars: Int64, firstSaleDate: Int32?, lastSaleDate: Int32?, upgradeStars: Int64?)
|
||||
case starGiftUnique(id: Int64, title: String, num: Int32, ownerId: Int64, attributes: [Api.StarGiftAttribute], availabilityIssued: Int32, availabilityTotal: Int32)
|
||||
case starGiftUnique(flags: Int32, id: Int64, title: String, slug: String, num: Int32, ownerId: Int64?, ownerName: String?, attributes: [Api.StarGiftAttribute], availabilityIssued: Int32, availabilityTotal: Int32)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
@ -594,14 +594,17 @@ public extension Api {
|
||||
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(lastSaleDate!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 3) != 0 {serializeInt64(upgradeStars!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
case .starGiftUnique(let id, let title, let num, let ownerId, let attributes, let availabilityIssued, let availabilityTotal):
|
||||
case .starGiftUnique(let flags, let id, let title, let slug, let num, let ownerId, let ownerName, let attributes, let availabilityIssued, let availabilityTotal):
|
||||
if boxed {
|
||||
buffer.appendInt32(1779697613)
|
||||
buffer.appendInt32(880997154)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt64(id, buffer: buffer, boxed: false)
|
||||
serializeString(title, buffer: buffer, boxed: false)
|
||||
serializeString(slug, buffer: buffer, boxed: false)
|
||||
serializeInt32(num, buffer: buffer, boxed: false)
|
||||
serializeInt64(ownerId, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(ownerId!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 1) != 0 {serializeString(ownerName!, buffer: buffer, boxed: false)}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(attributes.count))
|
||||
for item in attributes {
|
||||
@ -617,8 +620,8 @@ public extension Api {
|
||||
switch self {
|
||||
case .starGift(let flags, let id, let sticker, let stars, let availabilityRemains, let availabilityTotal, let convertStars, let firstSaleDate, let lastSaleDate, let upgradeStars):
|
||||
return ("starGift", [("flags", flags as Any), ("id", id as Any), ("sticker", sticker as Any), ("stars", stars as Any), ("availabilityRemains", availabilityRemains as Any), ("availabilityTotal", availabilityTotal as Any), ("convertStars", convertStars as Any), ("firstSaleDate", firstSaleDate as Any), ("lastSaleDate", lastSaleDate as Any), ("upgradeStars", upgradeStars as Any)])
|
||||
case .starGiftUnique(let id, let title, let num, let ownerId, let attributes, let availabilityIssued, let availabilityTotal):
|
||||
return ("starGiftUnique", [("id", id as Any), ("title", title as Any), ("num", num as Any), ("ownerId", ownerId as Any), ("attributes", attributes as Any), ("availabilityIssued", availabilityIssued as Any), ("availabilityTotal", availabilityTotal as Any)])
|
||||
case .starGiftUnique(let flags, let id, let title, let slug, let num, let ownerId, let ownerName, let attributes, let availabilityIssued, let availabilityTotal):
|
||||
return ("starGiftUnique", [("flags", flags as Any), ("id", id as Any), ("title", title as Any), ("slug", slug as Any), ("num", num as Any), ("ownerId", ownerId as Any), ("ownerName", ownerName as Any), ("attributes", attributes as Any), ("availabilityIssued", availabilityIssued as Any), ("availabilityTotal", availabilityTotal as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -663,31 +666,40 @@ public extension Api {
|
||||
}
|
||||
}
|
||||
public static func parse_starGiftUnique(_ reader: BufferReader) -> StarGift? {
|
||||
var _1: Int64?
|
||||
_1 = reader.readInt64()
|
||||
var _2: String?
|
||||
_2 = parseString(reader)
|
||||
var _3: Int32?
|
||||
_3 = reader.readInt32()
|
||||
var _4: Int64?
|
||||
_4 = reader.readInt64()
|
||||
var _5: [Api.StarGiftAttribute]?
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int64?
|
||||
_2 = reader.readInt64()
|
||||
var _3: String?
|
||||
_3 = parseString(reader)
|
||||
var _4: String?
|
||||
_4 = parseString(reader)
|
||||
var _5: Int32?
|
||||
_5 = reader.readInt32()
|
||||
var _6: Int64?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_6 = reader.readInt64() }
|
||||
var _7: String?
|
||||
if Int(_1!) & Int(1 << 1) != 0 {_7 = parseString(reader) }
|
||||
var _8: [Api.StarGiftAttribute]?
|
||||
if let _ = reader.readInt32() {
|
||||
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StarGiftAttribute.self)
|
||||
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StarGiftAttribute.self)
|
||||
}
|
||||
var _6: Int32?
|
||||
_6 = reader.readInt32()
|
||||
var _7: Int32?
|
||||
_7 = reader.readInt32()
|
||||
var _9: Int32?
|
||||
_9 = reader.readInt32()
|
||||
var _10: Int32?
|
||||
_10 = reader.readInt32()
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = _6 != nil
|
||||
let _c7 = _7 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
|
||||
return Api.StarGift.starGiftUnique(id: _1!, title: _2!, num: _3!, ownerId: _4!, attributes: _5!, availabilityIssued: _6!, availabilityTotal: _7!)
|
||||
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
|
||||
let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil
|
||||
let _c8 = _8 != nil
|
||||
let _c9 = _9 != nil
|
||||
let _c10 = _10 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 {
|
||||
return Api.StarGift.starGiftUnique(flags: _1!, id: _2!, title: _3!, slug: _4!, num: _5!, ownerId: _6, ownerName: _7, attributes: _8!, availabilityIssued: _9!, availabilityTotal: _10!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -207,6 +207,7 @@ public extension Api {
|
||||
case webPageAttributeStickerSet(flags: Int32, stickers: [Api.Document])
|
||||
case webPageAttributeStory(flags: Int32, peer: Api.Peer, id: Int32, story: Api.StoryItem?)
|
||||
case webPageAttributeTheme(flags: Int32, documents: [Api.Document]?, settings: Api.ThemeSettings?)
|
||||
case webPageAttributeUniqueStarGift(gift: Api.StarGift)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
@ -242,6 +243,12 @@ public extension Api {
|
||||
}}
|
||||
if Int(flags) & Int(1 << 1) != 0 {settings!.serialize(buffer, true)}
|
||||
break
|
||||
case .webPageAttributeUniqueStarGift(let gift):
|
||||
if boxed {
|
||||
buffer.appendInt32(-814781000)
|
||||
}
|
||||
gift.serialize(buffer, true)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,6 +260,8 @@ public extension Api {
|
||||
return ("webPageAttributeStory", [("flags", flags as Any), ("peer", peer as Any), ("id", id as Any), ("story", story as Any)])
|
||||
case .webPageAttributeTheme(let flags, let documents, let settings):
|
||||
return ("webPageAttributeTheme", [("flags", flags as Any), ("documents", documents as Any), ("settings", settings as Any)])
|
||||
case .webPageAttributeUniqueStarGift(let gift):
|
||||
return ("webPageAttributeUniqueStarGift", [("gift", gift as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,6 +326,19 @@ public extension Api {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_webPageAttributeUniqueStarGift(_ reader: BufferReader) -> WebPageAttribute? {
|
||||
var _1: Api.StarGift?
|
||||
if let signature = reader.readInt32() {
|
||||
_1 = Api.parse(reader, signature: signature) as? Api.StarGift
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.WebPageAttribute.webPageAttributeUniqueStarGift(gift: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -744,6 +744,54 @@ public extension Api.messages {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
indirect enum WebPagePreview: TypeConstructorDescription {
|
||||
case webPagePreview(media: Api.MessageMedia, users: [Api.User])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .webPagePreview(let media, let users):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1254192351)
|
||||
}
|
||||
media.serialize(buffer, true)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(users.count))
|
||||
for item in users {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .webPagePreview(let media, let users):
|
||||
return ("webPagePreview", [("media", media as Any), ("users", users as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_webPagePreview(_ reader: BufferReader) -> WebPagePreview? {
|
||||
var _1: Api.MessageMedia?
|
||||
if let signature = reader.readInt32() {
|
||||
_1 = Api.parse(reader, signature: signature) as? Api.MessageMedia
|
||||
}
|
||||
var _2: [Api.User]?
|
||||
if let _ = reader.readInt32() {
|
||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.messages.WebPagePreview.webPagePreview(media: _1!, users: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.payments {
|
||||
enum BankCardData: TypeConstructorDescription {
|
||||
case bankCardData(title: String, openUrls: [Api.BankCardOpenUrl])
|
||||
@ -1538,45 +1586,3 @@ public extension Api.payments {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.payments {
|
||||
enum StarGiftUpgradePreview: TypeConstructorDescription {
|
||||
case starGiftUpgradePreview(sampleAttributes: [Api.StarGiftAttribute])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .starGiftUpgradePreview(let sampleAttributes):
|
||||
if boxed {
|
||||
buffer.appendInt32(377215243)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(sampleAttributes.count))
|
||||
for item in sampleAttributes {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .starGiftUpgradePreview(let sampleAttributes):
|
||||
return ("starGiftUpgradePreview", [("sampleAttributes", sampleAttributes as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_starGiftUpgradePreview(_ reader: BufferReader) -> StarGiftUpgradePreview? {
|
||||
var _1: [Api.StarGiftAttribute]?
|
||||
if let _ = reader.readInt32() {
|
||||
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StarGiftAttribute.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.payments.StarGiftUpgradePreview.starGiftUpgradePreview(sampleAttributes: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,45 @@
|
||||
public extension Api.payments {
|
||||
enum StarGiftUpgradePreview: TypeConstructorDescription {
|
||||
case starGiftUpgradePreview(sampleAttributes: [Api.StarGiftAttribute])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .starGiftUpgradePreview(let sampleAttributes):
|
||||
if boxed {
|
||||
buffer.appendInt32(377215243)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(sampleAttributes.count))
|
||||
for item in sampleAttributes {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .starGiftUpgradePreview(let sampleAttributes):
|
||||
return ("starGiftUpgradePreview", [("sampleAttributes", sampleAttributes as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_starGiftUpgradePreview(_ reader: BufferReader) -> StarGiftUpgradePreview? {
|
||||
var _1: [Api.StarGiftAttribute]?
|
||||
if let _ = reader.readInt32() {
|
||||
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StarGiftAttribute.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.payments.StarGiftUpgradePreview.starGiftUpgradePreview(sampleAttributes: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.payments {
|
||||
enum StarGifts: TypeConstructorDescription {
|
||||
case starGifts(hash: Int32, gifts: [Api.StarGift])
|
||||
@ -334,6 +376,54 @@ public extension Api.payments {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.payments {
|
||||
enum UniqueStarGift: TypeConstructorDescription {
|
||||
case uniqueStarGift(gift: Api.StarGift, users: [Api.User])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .uniqueStarGift(let gift, let users):
|
||||
if boxed {
|
||||
buffer.appendInt32(-895289845)
|
||||
}
|
||||
gift.serialize(buffer, true)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(users.count))
|
||||
for item in users {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .uniqueStarGift(let gift, let users):
|
||||
return ("uniqueStarGift", [("gift", gift as Any), ("users", users as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_uniqueStarGift(_ reader: BufferReader) -> UniqueStarGift? {
|
||||
var _1: Api.StarGift?
|
||||
if let signature = reader.readInt32() {
|
||||
_1 = Api.parse(reader, signature: signature) as? Api.StarGift
|
||||
}
|
||||
var _2: [Api.User]?
|
||||
if let _ = reader.readInt32() {
|
||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.payments.UniqueStarGift.uniqueStarGift(gift: _1!, users: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.payments {
|
||||
enum UserStarGifts: TypeConstructorDescription {
|
||||
case userStarGifts(flags: Int32, count: Int32, gifts: [Api.UserStarGift], nextOffset: String?, users: [Api.User])
|
||||
@ -1776,121 +1866,3 @@ public extension Api.stats {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.stats {
|
||||
enum PublicForwards: TypeConstructorDescription {
|
||||
case publicForwards(flags: Int32, count: Int32, forwards: [Api.PublicForward], nextOffset: String?, chats: [Api.Chat], users: [Api.User])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .publicForwards(let flags, let count, let forwards, let nextOffset, let chats, let users):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1828487648)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(count, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(forwards.count))
|
||||
for item in forwards {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(chats.count))
|
||||
for item in chats {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(users.count))
|
||||
for item in users {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .publicForwards(let flags, let count, let forwards, let nextOffset, let chats, let users):
|
||||
return ("publicForwards", [("flags", flags as Any), ("count", count as Any), ("forwards", forwards as Any), ("nextOffset", nextOffset as Any), ("chats", chats as Any), ("users", users as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_publicForwards(_ reader: BufferReader) -> PublicForwards? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int32?
|
||||
_2 = reader.readInt32()
|
||||
var _3: [Api.PublicForward]?
|
||||
if let _ = reader.readInt32() {
|
||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PublicForward.self)
|
||||
}
|
||||
var _4: String?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) }
|
||||
var _5: [Api.Chat]?
|
||||
if let _ = reader.readInt32() {
|
||||
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
||||
}
|
||||
var _6: [Api.User]?
|
||||
if let _ = reader.readInt32() {
|
||||
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = _6 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
||||
return Api.stats.PublicForwards.publicForwards(flags: _1!, count: _2!, forwards: _3!, nextOffset: _4, chats: _5!, users: _6!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.stats {
|
||||
enum StoryStats: TypeConstructorDescription {
|
||||
case storyStats(viewsGraph: Api.StatsGraph, reactionsByEmotionGraph: Api.StatsGraph)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .storyStats(let viewsGraph, let reactionsByEmotionGraph):
|
||||
if boxed {
|
||||
buffer.appendInt32(1355613820)
|
||||
}
|
||||
viewsGraph.serialize(buffer, true)
|
||||
reactionsByEmotionGraph.serialize(buffer, true)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .storyStats(let viewsGraph, let reactionsByEmotionGraph):
|
||||
return ("storyStats", [("viewsGraph", viewsGraph as Any), ("reactionsByEmotionGraph", reactionsByEmotionGraph as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_storyStats(_ reader: BufferReader) -> StoryStats? {
|
||||
var _1: Api.StatsGraph?
|
||||
if let signature = reader.readInt32() {
|
||||
_1 = Api.parse(reader, signature: signature) as? Api.StatsGraph
|
||||
}
|
||||
var _2: Api.StatsGraph?
|
||||
if let signature = reader.readInt32() {
|
||||
_2 = Api.parse(reader, signature: signature) as? Api.StatsGraph
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.stats.StoryStats.storyStats(viewsGraph: _1!, reactionsByEmotionGraph: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,121 @@
|
||||
public extension Api.stats {
|
||||
enum PublicForwards: TypeConstructorDescription {
|
||||
case publicForwards(flags: Int32, count: Int32, forwards: [Api.PublicForward], nextOffset: String?, chats: [Api.Chat], users: [Api.User])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .publicForwards(let flags, let count, let forwards, let nextOffset, let chats, let users):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1828487648)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(count, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(forwards.count))
|
||||
for item in forwards {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(chats.count))
|
||||
for item in chats {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(users.count))
|
||||
for item in users {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .publicForwards(let flags, let count, let forwards, let nextOffset, let chats, let users):
|
||||
return ("publicForwards", [("flags", flags as Any), ("count", count as Any), ("forwards", forwards as Any), ("nextOffset", nextOffset as Any), ("chats", chats as Any), ("users", users as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_publicForwards(_ reader: BufferReader) -> PublicForwards? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int32?
|
||||
_2 = reader.readInt32()
|
||||
var _3: [Api.PublicForward]?
|
||||
if let _ = reader.readInt32() {
|
||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PublicForward.self)
|
||||
}
|
||||
var _4: String?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) }
|
||||
var _5: [Api.Chat]?
|
||||
if let _ = reader.readInt32() {
|
||||
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
||||
}
|
||||
var _6: [Api.User]?
|
||||
if let _ = reader.readInt32() {
|
||||
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = _6 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
||||
return Api.stats.PublicForwards.publicForwards(flags: _1!, count: _2!, forwards: _3!, nextOffset: _4, chats: _5!, users: _6!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.stats {
|
||||
enum StoryStats: TypeConstructorDescription {
|
||||
case storyStats(viewsGraph: Api.StatsGraph, reactionsByEmotionGraph: Api.StatsGraph)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .storyStats(let viewsGraph, let reactionsByEmotionGraph):
|
||||
if boxed {
|
||||
buffer.appendInt32(1355613820)
|
||||
}
|
||||
viewsGraph.serialize(buffer, true)
|
||||
reactionsByEmotionGraph.serialize(buffer, true)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .storyStats(let viewsGraph, let reactionsByEmotionGraph):
|
||||
return ("storyStats", [("viewsGraph", viewsGraph as Any), ("reactionsByEmotionGraph", reactionsByEmotionGraph as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_storyStats(_ reader: BufferReader) -> StoryStats? {
|
||||
var _1: Api.StatsGraph?
|
||||
if let signature = reader.readInt32() {
|
||||
_1 = Api.parse(reader, signature: signature) as? Api.StatsGraph
|
||||
}
|
||||
var _2: Api.StatsGraph?
|
||||
if let signature = reader.readInt32() {
|
||||
_2 = Api.parse(reader, signature: signature) as? Api.StatsGraph
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.stats.StoryStats.storyStats(viewsGraph: _1!, reactionsByEmotionGraph: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.stickers {
|
||||
enum SuggestedShortName: TypeConstructorDescription {
|
||||
case suggestedShortName(shortName: String)
|
||||
@ -1276,57 +1394,3 @@ public extension Api.upload {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.upload {
|
||||
enum WebFile: TypeConstructorDescription {
|
||||
case webFile(size: Int32, mimeType: String, fileType: Api.storage.FileType, mtime: Int32, bytes: Buffer)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .webFile(let size, let mimeType, let fileType, let mtime, let bytes):
|
||||
if boxed {
|
||||
buffer.appendInt32(568808380)
|
||||
}
|
||||
serializeInt32(size, buffer: buffer, boxed: false)
|
||||
serializeString(mimeType, buffer: buffer, boxed: false)
|
||||
fileType.serialize(buffer, true)
|
||||
serializeInt32(mtime, buffer: buffer, boxed: false)
|
||||
serializeBytes(bytes, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .webFile(let size, let mimeType, let fileType, let mtime, let bytes):
|
||||
return ("webFile", [("size", size as Any), ("mimeType", mimeType as Any), ("fileType", fileType as Any), ("mtime", mtime as Any), ("bytes", bytes as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_webFile(_ reader: BufferReader) -> WebFile? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: String?
|
||||
_2 = parseString(reader)
|
||||
var _3: Api.storage.FileType?
|
||||
if let signature = reader.readInt32() {
|
||||
_3 = Api.parse(reader, signature: signature) as? Api.storage.FileType
|
||||
}
|
||||
var _4: Int32?
|
||||
_4 = reader.readInt32()
|
||||
var _5: Buffer?
|
||||
_5 = parseBytes(reader)
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||
return Api.upload.WebFile.webFile(size: _1!, mimeType: _2!, fileType: _3!, mtime: _4!, bytes: _5!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,57 @@
|
||||
public extension Api.upload {
|
||||
enum WebFile: TypeConstructorDescription {
|
||||
case webFile(size: Int32, mimeType: String, fileType: Api.storage.FileType, mtime: Int32, bytes: Buffer)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .webFile(let size, let mimeType, let fileType, let mtime, let bytes):
|
||||
if boxed {
|
||||
buffer.appendInt32(568808380)
|
||||
}
|
||||
serializeInt32(size, buffer: buffer, boxed: false)
|
||||
serializeString(mimeType, buffer: buffer, boxed: false)
|
||||
fileType.serialize(buffer, true)
|
||||
serializeInt32(mtime, buffer: buffer, boxed: false)
|
||||
serializeBytes(bytes, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .webFile(let size, let mimeType, let fileType, let mtime, let bytes):
|
||||
return ("webFile", [("size", size as Any), ("mimeType", mimeType as Any), ("fileType", fileType as Any), ("mtime", mtime as Any), ("bytes", bytes as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_webFile(_ reader: BufferReader) -> WebFile? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: String?
|
||||
_2 = parseString(reader)
|
||||
var _3: Api.storage.FileType?
|
||||
if let signature = reader.readInt32() {
|
||||
_3 = Api.parse(reader, signature: signature) as? Api.storage.FileType
|
||||
}
|
||||
var _4: Int32?
|
||||
_4 = reader.readInt32()
|
||||
var _5: Buffer?
|
||||
_5 = parseBytes(reader)
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||
return Api.upload.WebFile.webFile(size: _1!, mimeType: _2!, fileType: _3!, mtime: _4!, bytes: _5!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.users {
|
||||
enum UserFull: TypeConstructorDescription {
|
||||
case userFull(fullUser: Api.UserFull, chats: [Api.Chat], users: [Api.User])
|
||||
|
@ -2383,12 +2383,11 @@ public extension Api.functions.bots {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.bots {
|
||||
static func getBotRecommendations(flags: Int32, bot: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.users.Users>) {
|
||||
static func getBotRecommendations(bot: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.users.Users>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(676707937)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(-1581840363)
|
||||
bot.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "bots.getBotRecommendations", parameters: [("flags", String(describing: flags)), ("bot", String(describing: bot))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.users.Users? in
|
||||
return (FunctionDescription(name: "bots.getBotRecommendations", parameters: [("bot", String(describing: bot))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.users.Users? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.users.Users?
|
||||
if let signature = reader.readInt32() {
|
||||
@ -7063,9 +7062,9 @@ public extension Api.functions.messages {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.messages {
|
||||
static func getWebPagePreview(flags: Int32, message: String, entities: [Api.MessageEntity]?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.MessageMedia>) {
|
||||
static func getWebPagePreview(flags: Int32, message: String, entities: [Api.MessageEntity]?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.WebPagePreview>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-1956073268)
|
||||
buffer.appendInt32(1460498287)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeString(message, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
|
||||
@ -7073,11 +7072,11 @@ public extension Api.functions.messages {
|
||||
for item in entities! {
|
||||
item.serialize(buffer, true)
|
||||
}}
|
||||
return (FunctionDescription(name: "messages.getWebPagePreview", parameters: [("flags", String(describing: flags)), ("message", String(describing: message)), ("entities", String(describing: entities))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.MessageMedia? in
|
||||
return (FunctionDescription(name: "messages.getWebPagePreview", parameters: [("flags", String(describing: flags)), ("message", String(describing: message)), ("entities", String(describing: entities))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.WebPagePreview? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.MessageMedia?
|
||||
var result: Api.messages.WebPagePreview?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.MessageMedia
|
||||
result = Api.parse(reader, signature: signature) as? Api.messages.WebPagePreview
|
||||
}
|
||||
return result
|
||||
})
|
||||
@ -9479,6 +9478,21 @@ public extension Api.functions.payments {
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.payments {
|
||||
static func getUniqueStarGift(slug: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.UniqueStarGift>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-1583919758)
|
||||
serializeString(slug, buffer: buffer, boxed: false)
|
||||
return (FunctionDescription(name: "payments.getUniqueStarGift", parameters: [("slug", String(describing: slug))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.UniqueStarGift? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.payments.UniqueStarGift?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.payments.UniqueStarGift
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.payments {
|
||||
static func getUserStarGift(msgId: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.UserStarGifts>) {
|
||||
let buffer = Buffer()
|
||||
|
@ -542,6 +542,8 @@ func mediaAreaFromApiMediaArea(_ mediaArea: Api.MediaArea) -> MediaArea? {
|
||||
return .channelMessage(coordinates: coodinatesFromApiMediaAreaCoordinates(coordinates), messageId: EngineMessage.Id(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), namespace: Namespaces.Message.Cloud, id: messageId))
|
||||
case let .mediaAreaWeather(coordinates, emoji, temperatureC, color):
|
||||
return .weather(coordinates: coodinatesFromApiMediaAreaCoordinates(coordinates), emoji: emoji, temperature: temperatureC, color: color)
|
||||
case let .mediaAreaStarGift(coordinates, slug):
|
||||
return .starGift(coordinates: coodinatesFromApiMediaAreaCoordinates(coordinates), slug: slug)
|
||||
}
|
||||
}
|
||||
|
||||
@ -596,6 +598,8 @@ func apiMediaAreasFromMediaAreas(_ mediaAreas: [MediaArea], transaction: Transac
|
||||
apiMediaAreas.append(.mediaAreaUrl(coordinates: inputCoordinates, url: url))
|
||||
case let .weather(_, emoji, temperature, color):
|
||||
apiMediaAreas.append(.mediaAreaWeather(coordinates: inputCoordinates, emoji: emoji, temperatureC: temperature, color: color))
|
||||
case let .starGift(_, slug):
|
||||
apiMediaAreas.append(.mediaAreaStarGift(coordinates: inputCoordinates, slug: slug))
|
||||
}
|
||||
}
|
||||
return apiMediaAreas
|
||||
|
@ -23,6 +23,11 @@ func telegramMediaWebpageAttributeFromApiWebpageAttribute(_ attribute: Api.WebPa
|
||||
var files: [TelegramMediaFile] = []
|
||||
files = stickers.compactMap { telegramMediaFileFromApiDocument($0, altDocuments: []) }
|
||||
return .stickerPack(TelegramMediaWebpageStickerPackAttribute(flags: flags, files: files))
|
||||
case let .webPageAttributeUniqueStarGift(gift):
|
||||
if let starGift = StarGift(apiStarGift: gift) {
|
||||
return .starGift(TelegramMediaWebpageStarGiftAttribute(gift: starGift))
|
||||
}
|
||||
return nil
|
||||
case .webPageAttributeStory:
|
||||
return nil
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
|
||||
|
||||
public class Serialization: NSObject, MTSerialization {
|
||||
public func currentLayer() -> UInt {
|
||||
return 196
|
||||
return 197
|
||||
}
|
||||
|
||||
public func parseMessage(_ data: Data!) -> Any! {
|
||||
|
@ -4,12 +4,14 @@ private enum TelegramMediaWebpageAttributeTypes: Int32 {
|
||||
case unsupported
|
||||
case theme
|
||||
case stickerPack
|
||||
case starGift
|
||||
}
|
||||
|
||||
public enum TelegramMediaWebpageAttribute: PostboxCoding, Equatable {
|
||||
case unsupported
|
||||
case theme(TelegraMediaWebpageThemeAttribute)
|
||||
case stickerPack(TelegramMediaWebpageStickerPackAttribute)
|
||||
case starGift(TelegramMediaWebpageStarGiftAttribute)
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
switch decoder.decodeInt32ForKey("r", orElse: 0) {
|
||||
@ -17,6 +19,8 @@ public enum TelegramMediaWebpageAttribute: PostboxCoding, Equatable {
|
||||
self = .theme(decoder.decodeObjectForKey("a", decoder: { TelegraMediaWebpageThemeAttribute(decoder: $0) }) as! TelegraMediaWebpageThemeAttribute)
|
||||
case TelegramMediaWebpageAttributeTypes.stickerPack.rawValue:
|
||||
self = .stickerPack(decoder.decodeObjectForKey("a", decoder: { TelegramMediaWebpageStickerPackAttribute(decoder: $0) }) as! TelegramMediaWebpageStickerPackAttribute)
|
||||
case TelegramMediaWebpageAttributeTypes.starGift.rawValue:
|
||||
self = .starGift(decoder.decodeObjectForKey("a", decoder: { TelegramMediaWebpageStarGiftAttribute(decoder: $0) }) as! TelegramMediaWebpageStarGiftAttribute)
|
||||
default:
|
||||
self = .unsupported
|
||||
}
|
||||
@ -32,6 +36,9 @@ public enum TelegramMediaWebpageAttribute: PostboxCoding, Equatable {
|
||||
case let .stickerPack(attribute):
|
||||
encoder.encodeInt32(TelegramMediaWebpageAttributeTypes.stickerPack.rawValue, forKey: "r")
|
||||
encoder.encodeObject(attribute, forKey: "a")
|
||||
case let .starGift(attribute):
|
||||
encoder.encodeInt32(TelegramMediaWebpageAttributeTypes.starGift.rawValue, forKey: "r")
|
||||
encoder.encodeObject(attribute, forKey: "a")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -127,6 +134,29 @@ public final class TelegramMediaWebpageStickerPackAttribute: PostboxCoding, Equa
|
||||
}
|
||||
}
|
||||
|
||||
public final class TelegramMediaWebpageStarGiftAttribute: PostboxCoding, Equatable {
|
||||
public static func == (lhs: TelegramMediaWebpageStarGiftAttribute, rhs: TelegramMediaWebpageStarGiftAttribute) -> Bool {
|
||||
if lhs.gift != rhs.gift {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public let gift: StarGift
|
||||
|
||||
public init(gift: StarGift) {
|
||||
self.gift = gift
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.gift = decoder.decodeObjectForKey("gift", decoder: { StarGift(decoder: $0) }) as! StarGift
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeObject(self.gift, forKey: "gift")
|
||||
}
|
||||
}
|
||||
|
||||
public final class TelegramMediaWebpageLoadedContent: PostboxCoding, Equatable {
|
||||
public let url: String
|
||||
public let displayUrl: String
|
||||
|
@ -152,6 +152,7 @@ public enum MediaArea: Codable, Equatable {
|
||||
case channelMessage(coordinates: Coordinates, messageId: EngineMessage.Id)
|
||||
case link(coordinates: Coordinates, url: String)
|
||||
case weather(coordinates: Coordinates, emoji: String, temperature: Double, color: Int32)
|
||||
case starGift(coordinates: Coordinates, slug: String)
|
||||
|
||||
public struct ReactionFlags: OptionSet {
|
||||
public var rawValue: Int32
|
||||
@ -174,6 +175,7 @@ public enum MediaArea: Codable, Equatable {
|
||||
case channelMessage
|
||||
case link
|
||||
case weather
|
||||
case starGift
|
||||
}
|
||||
|
||||
public enum DecodingError: Error {
|
||||
@ -210,6 +212,10 @@ public enum MediaArea: Codable, Equatable {
|
||||
let temperature = try container.decode(Double.self, forKey: .temperature)
|
||||
let color = try container.decodeIfPresent(Int32.self, forKey: .color) ?? 0
|
||||
self = .weather(coordinates: coordinates, emoji: emoji, temperature: temperature, color: color)
|
||||
case .starGift:
|
||||
let coordinates = try container.decode(MediaArea.Coordinates.self, forKey: .coordinates)
|
||||
let slug = try container.decode(String.self, forKey: .value)
|
||||
self = .starGift(coordinates: coordinates, slug: slug)
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,6 +246,10 @@ public enum MediaArea: Codable, Equatable {
|
||||
try container.encode(emoji, forKey: .value)
|
||||
try container.encode(temperature, forKey: .temperature)
|
||||
try container.encode(color, forKey: .color)
|
||||
case let .starGift(coordinates, slug):
|
||||
try container.encode(MediaAreaType.starGift.rawValue, forKey: .type)
|
||||
try container.encode(coordinates, forKey: .coordinates)
|
||||
try container.encode(slug, forKey: .value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -257,6 +267,8 @@ public extension MediaArea {
|
||||
return coordinates
|
||||
case let .weather(coordinates, _, _, _):
|
||||
return coordinates
|
||||
case let .starGift(coordinates, _):
|
||||
return coordinates
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -204,7 +204,9 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
case id
|
||||
case title
|
||||
case number
|
||||
case slug
|
||||
case ownerPeerId
|
||||
case ownerName
|
||||
case attributes
|
||||
case availability
|
||||
}
|
||||
@ -428,6 +430,11 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
encoder.encodeInt32(self.total, forKey: CodingKeys.total.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
public enum Owner: Equatable {
|
||||
case peerId(EnginePeer.Id)
|
||||
case name(String)
|
||||
}
|
||||
|
||||
public enum DecodingError: Error {
|
||||
case generic
|
||||
@ -436,15 +443,17 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
public let id: Int64
|
||||
public let title: String
|
||||
public let number: Int32
|
||||
public let ownerPeerId: EnginePeer.Id
|
||||
public let slug: String
|
||||
public let owner: Owner
|
||||
public let attributes: [Attribute]
|
||||
public let availability: Availability
|
||||
|
||||
public init(id: Int64, title: String, number: Int32, ownerPeerId: EnginePeer.Id, attributes: [Attribute], availability: Availability) {
|
||||
public init(id: Int64, title: String, number: Int32, slug: String, owner: Owner, attributes: [Attribute], availability: Availability) {
|
||||
self.id = id
|
||||
self.title = title
|
||||
self.number = number
|
||||
self.ownerPeerId = ownerPeerId
|
||||
self.slug = slug
|
||||
self.owner = owner
|
||||
self.attributes = attributes
|
||||
self.availability = availability
|
||||
}
|
||||
@ -454,7 +463,14 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
self.id = try container.decode(Int64.self, forKey: .id)
|
||||
self.title = try container.decode(String.self, forKey: .title)
|
||||
self.number = try container.decode(Int32.self, forKey: .number)
|
||||
self.ownerPeerId = EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(try container.decode(Int64.self, forKey: .ownerPeerId)))
|
||||
self.slug = try container.decodeIfPresent(String.self, forKey: .slug) ?? ""
|
||||
if let ownerId = try container.decodeIfPresent(Int64.self, forKey: .ownerPeerId) {
|
||||
self.owner = .peerId(EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(ownerId)))
|
||||
} else if let ownerName = try container.decodeIfPresent(String.self, forKey: .ownerName) {
|
||||
self.owner = .name(ownerName)
|
||||
} else {
|
||||
self.owner = .name("Unknown")
|
||||
}
|
||||
self.attributes = try container.decode([UniqueGift.Attribute].self, forKey: .attributes)
|
||||
self.availability = try container.decode(UniqueGift.Availability.self, forKey: .availability)
|
||||
}
|
||||
@ -463,7 +479,14 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
self.id = decoder.decodeInt64ForKey(CodingKeys.id.rawValue, orElse: 0)
|
||||
self.title = decoder.decodeStringForKey(CodingKeys.title.rawValue, orElse: "")
|
||||
self.number = decoder.decodeInt32ForKey(CodingKeys.number.rawValue, orElse: 0)
|
||||
self.ownerPeerId = EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(decoder.decodeInt64ForKey(CodingKeys.ownerPeerId.rawValue, orElse: 0)))
|
||||
self.slug = decoder.decodeStringForKey(CodingKeys.slug.rawValue, orElse: "")
|
||||
if let ownerId = decoder.decodeOptionalInt64ForKey(CodingKeys.ownerPeerId.rawValue) {
|
||||
self.owner = .peerId(EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(ownerId)))
|
||||
} else if let ownerName = decoder.decodeOptionalStringForKey(CodingKeys.ownerName.rawValue) {
|
||||
self.owner = .name(ownerName)
|
||||
} else {
|
||||
self.owner = .name("Unknown")
|
||||
}
|
||||
self.attributes = (try? decoder.decodeObjectArrayWithCustomDecoderForKey(CodingKeys.attributes.rawValue, decoder: { UniqueGift.Attribute(decoder: $0) })) ?? []
|
||||
self.availability = decoder.decodeObjectForKey(CodingKeys.availability.rawValue, decoder: { UniqueGift.Availability(decoder: $0) }) as! UniqueGift.Availability
|
||||
}
|
||||
@ -473,7 +496,13 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
try container.encode(self.id, forKey: .id)
|
||||
try container.encode(self.title, forKey: .title)
|
||||
try container.encode(self.number, forKey: .number)
|
||||
try container.encode(self.ownerPeerId.id._internalGetInt64Value(), forKey: .ownerPeerId)
|
||||
try container.encode(self.slug, forKey: .slug)
|
||||
switch self.owner {
|
||||
case let .peerId(peerId):
|
||||
try container.encode(peerId.id._internalGetInt64Value(), forKey: .ownerPeerId)
|
||||
case let .name(name):
|
||||
try container.encode(name, forKey: .ownerName)
|
||||
}
|
||||
try container.encode(self.attributes, forKey: .attributes)
|
||||
try container.encode(self.availability, forKey: .availability)
|
||||
}
|
||||
@ -482,7 +511,13 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
encoder.encodeInt64(self.id, forKey: CodingKeys.id.rawValue)
|
||||
encoder.encodeString(self.title, forKey: CodingKeys.title.rawValue)
|
||||
encoder.encodeInt32(self.number, forKey: CodingKeys.number.rawValue)
|
||||
encoder.encodeInt64(self.ownerPeerId.id._internalGetInt64Value(), forKey: CodingKeys.ownerPeerId.rawValue)
|
||||
encoder.encodeString(self.slug, forKey: CodingKeys.slug.rawValue)
|
||||
switch self.owner {
|
||||
case let .peerId(peerId):
|
||||
encoder.encodeInt64(peerId.id._internalGetInt64Value(), forKey: CodingKeys.ownerPeerId.rawValue)
|
||||
case let .name(name):
|
||||
encoder.encodeString(name, forKey: CodingKeys.ownerName.rawValue)
|
||||
}
|
||||
encoder.encodeObjectArray(self.attributes, forKey: CodingKeys.attributes.rawValue)
|
||||
encoder.encodeObject(self.availability, forKey: CodingKeys.availability.rawValue)
|
||||
}
|
||||
@ -570,8 +605,16 @@ extension StarGift {
|
||||
return nil
|
||||
}
|
||||
self = .generic(StarGift.Gift(id: id, file: file, price: stars, convertStars: convertStars, availability: availability, soldOut: soldOut, flags: flags, upgradeStars: upgradeStars))
|
||||
case let .starGiftUnique(id, title, num, ownerId, attributes, availabilityIssued, availabilityTotal):
|
||||
self = .unique(StarGift.UniqueGift(id: id, title: title, number: num, ownerPeerId: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(ownerId)), attributes: attributes.compactMap { UniqueGift.Attribute(apiAttribute: $0) }, availability: UniqueGift.Availability(issued: availabilityIssued, total: availabilityTotal)))
|
||||
case let .starGiftUnique(_, id, title, slug, num, ownerId, ownerName, attributes, availabilityIssued, availabilityTotal):
|
||||
let owner: StarGift.UniqueGift.Owner
|
||||
if let ownerId {
|
||||
owner = .peerId(EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(ownerId)))
|
||||
} else if let ownerName {
|
||||
owner = .name(ownerName)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
self = .unique(StarGift.UniqueGift(id: id, title: title, number: num, slug: slug, owner: owner, attributes: attributes.compactMap { UniqueGift.Attribute(apiAttribute: $0) }, availability: UniqueGift.Availability(issued: availabilityIssued, total: availabilityTotal)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1311,3 +1354,29 @@ extension StarGift.UniqueGift.Attribute {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func _internal_getUniqueStarGift(account: Account, slug: String) -> Signal<StarGift.UniqueGift?, NoError> {
|
||||
return account.network.request(Api.functions.payments.getUniqueStarGift(slug: slug))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.payments.UniqueStarGift?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<StarGift.UniqueGift?, NoError> in
|
||||
if let result = result {
|
||||
switch result {
|
||||
case let .uniqueStarGift(gift, users):
|
||||
return account.postbox.transaction { transaction in
|
||||
let parsedPeers = AccumulatedPeers(users: users)
|
||||
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: parsedPeers)
|
||||
guard case let .unique(uniqueGift) = StarGift(apiStarGift: gift) else {
|
||||
return nil
|
||||
}
|
||||
return uniqueGift
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -132,5 +132,9 @@ public extension TelegramEngine {
|
||||
public func starGiftUpgradePreview(giftId: Int64) -> Signal<[StarGift.UniqueGift.Attribute], NoError> {
|
||||
return _internal_starGiftUpgradePreview(account: self.account, giftId: giftId)
|
||||
}
|
||||
|
||||
public func getUniqueStarGift(slug: String) -> Signal<StarGift.UniqueGift?, NoError> {
|
||||
return _internal_getUniqueStarGift(account: self.account, slug: slug)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -155,8 +155,8 @@ public func webpagePreviewWithProgress(account: Account, urls: [String], webpage
|
||||
}
|
||||
|
||||
return account.network.requestWithAdditionalInfo(Api.functions.messages.getWebPagePreview(flags: 0, message: urls.joined(separator: " "), entities: nil), info: .progress)
|
||||
|> `catch` { _ -> Signal<NetworkRequestResult<Api.MessageMedia>, NoError> in
|
||||
return .single(.result(.messageMediaEmpty))
|
||||
|> `catch` { _ -> Signal<NetworkRequestResult<Api.messages.WebPagePreview>, NoError> in
|
||||
return .single(.result(.webPagePreview(media: .messageMediaEmpty, users: [])))
|
||||
}
|
||||
|> mapToSignal { result -> Signal<WebpagePreviewWithProgressResult, NoError> in
|
||||
switch result {
|
||||
@ -169,36 +169,44 @@ public func webpagePreviewWithProgress(account: Account, urls: [String], webpage
|
||||
return .complete()
|
||||
}
|
||||
case let .result(result):
|
||||
if let preCachedResources = result.preCachedResources {
|
||||
if case let .webPagePreview(result, _) = result, let preCachedResources = result.preCachedResources {
|
||||
for (resource, data) in preCachedResources {
|
||||
account.postbox.mediaBox.storeResourceData(resource.id, data: data)
|
||||
}
|
||||
}
|
||||
switch result {
|
||||
case let .messageMediaWebPage(flags, webpage):
|
||||
let _ = flags
|
||||
if let media = telegramMediaWebpageFromApiWebpage(webpage), let url = media.content.url {
|
||||
if case .Loaded = media.content {
|
||||
return .single(.result(WebpagePreviewResult.Result(webpage: media, sourceUrl: url)))
|
||||
} else {
|
||||
return .single(.result(WebpagePreviewResult.Result(webpage: media, sourceUrl: url)))
|
||||
|> then(
|
||||
account.stateManager.updatedWebpage(media.webpageId)
|
||||
|> take(1)
|
||||
|> map { next -> WebpagePreviewWithProgressResult in
|
||||
if let url = next.content.url {
|
||||
return .result(WebpagePreviewResult.Result(webpage: next, sourceUrl: url))
|
||||
} else {
|
||||
return .result(nil)
|
||||
}
|
||||
case let .webPagePreview(media, users):
|
||||
switch media {
|
||||
case let .messageMediaWebPage(_, webpage):
|
||||
return account.postbox.transaction { transaction -> Signal<WebpagePreviewWithProgressResult, NoError> in
|
||||
let peers = AccumulatedPeers(users: users)
|
||||
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: peers)
|
||||
|
||||
if let media = telegramMediaWebpageFromApiWebpage(webpage), let url = media.content.url {
|
||||
if case .Loaded = media.content {
|
||||
return .single(.result(WebpagePreviewResult.Result(webpage: media, sourceUrl: url)))
|
||||
} else {
|
||||
return .single(.result(WebpagePreviewResult.Result(webpage: media, sourceUrl: url)))
|
||||
|> then(
|
||||
account.stateManager.updatedWebpage(media.webpageId)
|
||||
|> take(1)
|
||||
|> map { next -> WebpagePreviewWithProgressResult in
|
||||
if let url = next.content.url {
|
||||
return .result(WebpagePreviewResult.Result(webpage: next, sourceUrl: url))
|
||||
} else {
|
||||
return .result(nil)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
return .single(.result(nil))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|> switchToLatest
|
||||
default:
|
||||
return .single(.result(nil))
|
||||
}
|
||||
default:
|
||||
return .single(.result(nil))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -189,8 +189,7 @@ final class CameraCodeResultComponent: Component {
|
||||
view.frame = CGRect(origin: CGPoint(x: 54.0, y: 9.0), size: titleSize)
|
||||
}
|
||||
|
||||
//TODO:localize
|
||||
let subtitleString = NSMutableAttributedString(string: "Open Chat >", font: Font.regular(15.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.7))
|
||||
let subtitleString = NSMutableAttributedString(string: "\(presentationData.strings.Camera_OpenChat) >", font: Font.regular(15.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.7))
|
||||
if let range = subtitleString.string.range(of: ">"), let arrowImage = UIImage(bundleImageName: "Item List/InlineTextRightArrow") {
|
||||
subtitleString.addAttribute(.attachment, value: arrowImage, range: NSRange(range, in: subtitleString.string))
|
||||
subtitleString.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: subtitleString.string))
|
||||
|
@ -366,7 +366,6 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
var buttonTitle = item.presentationData.strings.Notification_PremiumGift_View
|
||||
var buttonIcon: String?
|
||||
var ribbonTitle = ""
|
||||
var hasServiceMessage = true
|
||||
var textSpacing: CGFloat = 0.0
|
||||
var isStarGift = false
|
||||
|
||||
@ -381,6 +380,9 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
var uniquePatternColor: UIColor?
|
||||
var uniquePatternFile: TelegramMediaFile?
|
||||
|
||||
let isStoryEntity = item.message.id.id == -1
|
||||
var hasServiceMessage = !isStoryEntity
|
||||
|
||||
for media in item.message.media {
|
||||
if let action = media as? TelegramMediaAction {
|
||||
switch action.action {
|
||||
@ -560,10 +562,10 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
} else {
|
||||
authorName = item.message.author.flatMap { EnginePeer($0) }?.compactDisplayTitle ?? ""
|
||||
}
|
||||
title = item.presentationData.strings.Notification_StarGift_Title(authorName).string
|
||||
text = "**\(uniqueGift.title) #\(uniqueGift.number)**"
|
||||
ribbonTitle = item.presentationData.strings.Notification_StarGift_Gift
|
||||
buttonTitle = item.presentationData.strings.Notification_StarGift_View
|
||||
title = isStoryEntity ? uniqueGift.title : item.presentationData.strings.Notification_StarGift_Title(authorName).string
|
||||
text = isStoryEntity ? "**Collectible #\(uniqueGift.number)**" : "**\(uniqueGift.title) #\(uniqueGift.number)**"
|
||||
ribbonTitle = isStoryEntity ? "" : item.presentationData.strings.Notification_StarGift_Gift
|
||||
buttonTitle = isStoryEntity ? "" : item.presentationData.strings.Notification_StarGift_View
|
||||
modelTitle = item.presentationData.strings.Notification_StarGift_Model
|
||||
backdropTitle = item.presentationData.strings.Notification_StarGift_Backdrop
|
||||
symbolTitle = item.presentationData.strings.Notification_StarGift_Symbol
|
||||
@ -697,6 +699,8 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
if !buttonTitle.isEmpty {
|
||||
giftSize.height += 48.0
|
||||
} else if isStoryEntity {
|
||||
giftSize.height += 12.0
|
||||
}
|
||||
|
||||
var labelRects = labelLayout.linesRects()
|
||||
@ -754,7 +758,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
let overlayColor = item.presentationData.theme.theme.overallDarkAppearance ? UIColor(rgb: 0xffffff, alpha: 0.12) : UIColor(rgb: 0x000000, alpha: 0.12)
|
||||
let overlayColor = item.presentationData.theme.theme.overallDarkAppearance && uniquePatternFile == nil ? UIColor(rgb: 0xffffff, alpha: 0.12) : UIColor(rgb: 0x000000, alpha: 0.12)
|
||||
|
||||
let imageFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - giftSize.width) / 2.0), y: hasServiceMessage ? labelLayout.size.height + 12.0 : 0.0), size: giftSize)
|
||||
let mediaBackgroundFrame = imageFrame.insetBy(dx: -2.0, dy: -2.0)
|
||||
@ -767,11 +771,12 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
let animationFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - iconSize.width) / 2.0), y: mediaBackgroundFrame.minY - 16.0 + iconOffset), size: iconSize)
|
||||
strongSelf.animationNode.frame = animationFrame
|
||||
strongSelf.animationNode.isHidden = isStoryEntity
|
||||
|
||||
strongSelf.buttonNode.isHidden = buttonTitle.isEmpty
|
||||
strongSelf.buttonTitleNode.isHidden = buttonTitle.isEmpty
|
||||
|
||||
if strongSelf.item == nil {
|
||||
if strongSelf.item == nil && !isStoryEntity {
|
||||
strongSelf.animationNode.started = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let current = CACurrentMediaTime()
|
||||
@ -883,63 +888,78 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
strongSelf.dustNode = nil
|
||||
}
|
||||
|
||||
var middleX = mediaBackgroundFrame.width / 2.0
|
||||
if let (modelValueLayout, _) = modelValueLayoutAndApply, let (backdropValueLayout, _) = backdropValueLayoutAndApply, let (symbolValueLayout, _) = symbolValueLayoutAndApply {
|
||||
let maxWidth = max(modelValueLayout.size.width, max(backdropValueLayout.size.width, symbolValueLayout.size.width))
|
||||
middleX = min(mediaBackgroundFrame.width - maxWidth - 16.0, middleX)
|
||||
let attributeSpacing: CGFloat = 6.0
|
||||
let attributeVerticalSpacing: CGFloat = 22.0
|
||||
var attributeMidpoints: [CGFloat] = []
|
||||
|
||||
func appendAttributeMidpoint(titleLayout: TextNodeLayout?, valueLayout: TextNodeLayout?) {
|
||||
if let titleLayout, let valueLayout {
|
||||
let totalWidth = titleLayout.size.width + attributeSpacing + valueLayout.size.width
|
||||
let titleOffset = titleLayout.size.width + attributeSpacing / 2.0
|
||||
let midpoint = (mediaBackgroundFrame.width - totalWidth) / 2.0 + titleOffset
|
||||
attributeMidpoints.append(midpoint)
|
||||
}
|
||||
}
|
||||
|
||||
let titleMaxX: CGFloat = mediaBackgroundFrame.minX + middleX - 2.0
|
||||
let valueMinX: CGFloat = mediaBackgroundFrame.minX + middleX + 3.0
|
||||
appendAttributeMidpoint(titleLayout: modelTitleLayoutAndApply?.0, valueLayout: modelValueLayoutAndApply?.0)
|
||||
appendAttributeMidpoint(titleLayout: backdropTitleLayoutAndApply?.0, valueLayout: backdropValueLayoutAndApply?.0)
|
||||
appendAttributeMidpoint(titleLayout: symbolTitleLayoutAndApply?.0, valueLayout: symbolValueLayoutAndApply?.0)
|
||||
|
||||
let middleX = attributeMidpoints.isEmpty ? mediaBackgroundFrame.width / 2.0 : attributeMidpoints.reduce(0, +) / CGFloat(attributeMidpoints.count)
|
||||
|
||||
let titleMaxX: CGFloat = mediaBackgroundFrame.minX + middleX - attributeSpacing / 2.0
|
||||
let valueMinX: CGFloat = mediaBackgroundFrame.minX + middleX + attributeSpacing / 2.0
|
||||
|
||||
if let (modelTitleLayout, modelTitleApply) = modelTitleLayoutAndApply {
|
||||
if strongSelf.modelTitleTextNode.supernode == nil {
|
||||
strongSelf.addSubnode(strongSelf.modelTitleTextNode)
|
||||
func positionAttributeNodes(
|
||||
titleTextNode: TextNode,
|
||||
valueTextNode: TextNode,
|
||||
titleLayoutAndApply: (TextNodeLayout, () -> TextNode)?,
|
||||
valueLayoutAndApply: (TextNodeLayout, () -> TextNode)?,
|
||||
yOffset: CGFloat
|
||||
) {
|
||||
if let (titleLayout, titleApply) = titleLayoutAndApply {
|
||||
if titleTextNode.supernode == nil {
|
||||
strongSelf.addSubnode(titleTextNode)
|
||||
}
|
||||
let _ = titleApply()
|
||||
titleTextNode.frame = CGRect(
|
||||
origin: CGPoint(x: titleMaxX - titleLayout.size.width, y: clippingTextFrame.maxY + yOffset),
|
||||
size: titleLayout.size
|
||||
)
|
||||
}
|
||||
if let (valueLayout, valueApply) = valueLayoutAndApply {
|
||||
if valueTextNode.supernode == nil {
|
||||
strongSelf.addSubnode(valueTextNode)
|
||||
}
|
||||
let _ = valueApply()
|
||||
valueTextNode.frame = CGRect(
|
||||
origin: CGPoint(x: valueMinX, y: clippingTextFrame.maxY + yOffset),
|
||||
size: valueLayout.size
|
||||
)
|
||||
}
|
||||
let _ = modelTitleApply()
|
||||
strongSelf.modelTitleTextNode.frame = CGRect(origin: CGPoint(x: titleMaxX - modelTitleLayout.size.width, y: clippingTextFrame.maxY + 10.0), size: modelTitleLayout.size)
|
||||
}
|
||||
|
||||
if let (modelValueLayout, modelValueApply) = modelValueLayoutAndApply {
|
||||
if strongSelf.modelValueTextNode.supernode == nil {
|
||||
strongSelf.addSubnode(strongSelf.modelValueTextNode)
|
||||
}
|
||||
let _ = modelValueApply()
|
||||
strongSelf.modelValueTextNode.frame = CGRect(origin: CGPoint(x: valueMinX, y: clippingTextFrame.maxY + 10.0), size: modelValueLayout.size)
|
||||
}
|
||||
|
||||
if let (backdropTitleLayout, backdropTitleApply) = backdropTitleLayoutAndApply {
|
||||
if strongSelf.backdropTitleTextNode.supernode == nil {
|
||||
strongSelf.addSubnode(strongSelf.backdropTitleTextNode)
|
||||
}
|
||||
let _ = backdropTitleApply()
|
||||
strongSelf.backdropTitleTextNode.frame = CGRect(origin: CGPoint(x: titleMaxX - backdropTitleLayout.size.width, y: clippingTextFrame.maxY + 32.0), size: backdropTitleLayout.size)
|
||||
}
|
||||
|
||||
if let (backdropValueLayout, backdropValueApply) = backdropValueLayoutAndApply {
|
||||
if strongSelf.backdropValueTextNode.supernode == nil {
|
||||
strongSelf.addSubnode(strongSelf.backdropValueTextNode)
|
||||
}
|
||||
let _ = backdropValueApply()
|
||||
strongSelf.backdropValueTextNode.frame = CGRect(origin: CGPoint(x: valueMinX, y: clippingTextFrame.maxY + 32.0), size: backdropValueLayout.size)
|
||||
}
|
||||
|
||||
if let (symbolTitleLayout, symbolTitleApply) = symbolTitleLayoutAndApply {
|
||||
if strongSelf.symbolTitleTextNode.supernode == nil {
|
||||
strongSelf.addSubnode(strongSelf.symbolTitleTextNode)
|
||||
}
|
||||
let _ = symbolTitleApply()
|
||||
strongSelf.symbolTitleTextNode.frame = CGRect(origin: CGPoint(x: titleMaxX - symbolTitleLayout.size.width, y: clippingTextFrame.maxY + 54.0), size: symbolTitleLayout.size)
|
||||
}
|
||||
|
||||
if let (symbolValueLayout, symbolValueApply) = symbolValueLayoutAndApply {
|
||||
if strongSelf.symbolValueTextNode.supernode == nil {
|
||||
strongSelf.addSubnode(strongSelf.symbolValueTextNode)
|
||||
}
|
||||
let _ = symbolValueApply()
|
||||
strongSelf.symbolValueTextNode.frame = CGRect(origin: CGPoint(x: valueMinX, y: clippingTextFrame.maxY + 54.0), size: symbolValueLayout.size)
|
||||
}
|
||||
|
||||
positionAttributeNodes(
|
||||
titleTextNode: strongSelf.modelTitleTextNode,
|
||||
valueTextNode: strongSelf.modelValueTextNode,
|
||||
titleLayoutAndApply: modelTitleLayoutAndApply,
|
||||
valueLayoutAndApply: modelValueLayoutAndApply,
|
||||
yOffset: 10.0
|
||||
)
|
||||
positionAttributeNodes(
|
||||
titleTextNode: strongSelf.backdropTitleTextNode,
|
||||
valueTextNode: strongSelf.backdropValueTextNode,
|
||||
titleLayoutAndApply: backdropTitleLayoutAndApply,
|
||||
valueLayoutAndApply: backdropValueLayoutAndApply,
|
||||
yOffset: 10.0 + attributeVerticalSpacing
|
||||
)
|
||||
positionAttributeNodes(
|
||||
titleTextNode: strongSelf.symbolTitleTextNode,
|
||||
valueTextNode: strongSelf.symbolValueTextNode,
|
||||
titleLayoutAndApply: symbolTitleLayoutAndApply,
|
||||
valueLayoutAndApply: symbolValueLayoutAndApply,
|
||||
yOffset: 10.0 + attributeVerticalSpacing * 2
|
||||
)
|
||||
|
||||
var buttonSize = CGSize(width: buttonTitleLayout.size.width + 38.0, height: 34.0)
|
||||
var buttonOriginY = clippingTextFrame.maxY + 10.0
|
||||
if modelTitleLayoutAndApply != nil {
|
||||
|
@ -457,6 +457,8 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
|
||||
}
|
||||
}
|
||||
actionTitle = isEmoji ? item.presentationData.strings.Conversation_ViewEmojis : item.presentationData.strings.Conversation_ViewStickers
|
||||
case "telegram_nft":
|
||||
actionTitle = item.presentationData.strings.Conversation_ViewStarGift
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
@ -1381,6 +1381,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
break
|
||||
case .premiumMultiGift:
|
||||
break
|
||||
case .collectible:
|
||||
break
|
||||
case .messageLink:
|
||||
break
|
||||
}
|
||||
|
@ -431,10 +431,9 @@ public final class GiftItemComponent: Component {
|
||||
}
|
||||
price = priceValue
|
||||
case .uniqueGift:
|
||||
//TODO:localize
|
||||
buttonColor = UIColor.white
|
||||
starsColor = UIColor.white
|
||||
price = "Unique"
|
||||
price = ""
|
||||
}
|
||||
|
||||
let buttonSize = self.button.update(
|
||||
|
@ -42,6 +42,7 @@ swift_library(
|
||||
"//submodules/ConfettiEffect",
|
||||
"//submodules/TooltipUI",
|
||||
"//submodules/TelegramUI/Components/Gifts/GiftItemComponent",
|
||||
"//submodules/MoreButtonNode",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -0,0 +1,143 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import ComponentFlow
|
||||
import BundleIconComponent
|
||||
import MultilineTextComponent
|
||||
import MoreButtonNode
|
||||
import AccountContext
|
||||
import TelegramPresentationData
|
||||
|
||||
final class ButtonsComponent: Component {
|
||||
let theme: PresentationTheme
|
||||
let isOverlay: Bool
|
||||
let showMoreButton: Bool
|
||||
let closePressed: () -> Void
|
||||
let morePressed: (ASDisplayNode, ContextGesture?) -> Void
|
||||
|
||||
init(
|
||||
theme: PresentationTheme,
|
||||
isOverlay: Bool,
|
||||
showMoreButton: Bool,
|
||||
closePressed: @escaping () -> Void,
|
||||
morePressed: @escaping (ASDisplayNode, ContextGesture?) -> Void
|
||||
) {
|
||||
self.theme = theme
|
||||
self.isOverlay = isOverlay
|
||||
self.showMoreButton = showMoreButton
|
||||
self.closePressed = closePressed
|
||||
self.morePressed = morePressed
|
||||
}
|
||||
|
||||
static func ==(lhs: ButtonsComponent, rhs: ButtonsComponent) -> Bool {
|
||||
return lhs.theme === rhs.theme && lhs.isOverlay == rhs.isOverlay && lhs.showMoreButton == rhs.showMoreButton
|
||||
}
|
||||
|
||||
final class View: UIView {
|
||||
private let backgroundView = UIView()
|
||||
|
||||
private let closeButton = HighlightTrackingButton()
|
||||
private let closeIcon = UIImageView()
|
||||
private let moreNode = MoreButtonNode(theme: defaultPresentationTheme, size: CGSize(width: 36.0, height: 36.0), encircled: false)
|
||||
|
||||
private var component: ButtonsComponent?
|
||||
private weak var state: EmptyComponentState?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
self.backgroundView.clipsToBounds = true
|
||||
self.addSubview(self.backgroundView)
|
||||
|
||||
self.closeIcon.image = generateCloseButtonImage()
|
||||
self.moreNode.updateColor(.white, transition: .immediate)
|
||||
|
||||
self.backgroundView.addSubview(self.moreNode.view)
|
||||
self.backgroundView.addSubview(self.closeButton)
|
||||
self.backgroundView.addSubview(self.closeIcon)
|
||||
|
||||
self.closeButton.highligthedChanged = { [weak self] highlighted in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if highlighted {
|
||||
self.closeIcon.layer.removeAnimation(forKey: "opacity")
|
||||
self.closeIcon.alpha = 0.6
|
||||
} else {
|
||||
self.closeIcon.alpha = 1.0
|
||||
self.closeIcon.layer.animateAlpha(from: 0.6, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
self.closeButton.addTarget(self, action: #selector(self.closePressed), for: .touchUpInside)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@objc private func closePressed() {
|
||||
guard let component = self.component else {
|
||||
return
|
||||
}
|
||||
component.closePressed()
|
||||
}
|
||||
|
||||
func update(component: ButtonsComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
||||
self.component = component
|
||||
self.state = state
|
||||
|
||||
let backgroundSize = CGSize(width: component.showMoreButton ? 70.0 : 30.0, height: 30.0)
|
||||
self.backgroundView.layer.cornerRadius = backgroundSize.height / 2.0
|
||||
|
||||
let backgroundColor: UIColor = component.isOverlay ? UIColor(rgb: 0xffffff, alpha: 0.1) : UIColor(rgb: 0x808084, alpha: 0.1)
|
||||
let foregroundColor: UIColor = component.isOverlay ? .white : component.theme.actionSheet.inputClearButtonColor
|
||||
transition.setBackgroundColor(view: self.backgroundView, color: backgroundColor)
|
||||
transition.setTintColor(view: self.closeIcon, color: foregroundColor)
|
||||
|
||||
let backgroundFrame = CGRect(origin: .zero, size: backgroundSize)
|
||||
transition.setFrame(view: self.backgroundView, frame: backgroundFrame)
|
||||
|
||||
transition.setFrame(view: self.moreNode.view, frame: CGRect(origin: CGPoint(x: -7.0, y: -4.0), size: CGSize(width: 36.0, height: 36.0)))
|
||||
transition.setAlpha(view: self.moreNode.view, alpha: component.showMoreButton ? 1.0 : 0.0)
|
||||
self.moreNode.action = { [weak self] node, gesture in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
component.morePressed(node, gesture)
|
||||
}
|
||||
|
||||
let closeFrame = CGRect(origin: CGPoint(x: backgroundSize.width - 30.0 - (component.showMoreButton ? 3.0 : 0.0), y: 0.0), size: CGSize(width: 30.0, height: 30.0))
|
||||
transition.setFrame(view: self.closeIcon, frame: closeFrame)
|
||||
transition.setFrame(view: self.closeButton, frame: closeFrame)
|
||||
|
||||
return backgroundSize
|
||||
}
|
||||
}
|
||||
|
||||
func makeView() -> View {
|
||||
return View(frame: CGRect())
|
||||
}
|
||||
|
||||
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
||||
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
private func generateCloseButtonImage() -> UIImage? {
|
||||
return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.setLineWidth(2.0)
|
||||
context.setLineCap(.round)
|
||||
context.setStrokeColor(UIColor.white.cgColor)
|
||||
|
||||
context.move(to: CGPoint(x: 10.0, y: 10.0))
|
||||
context.addLine(to: CGPoint(x: 20.0, y: 20.0))
|
||||
context.strokePath()
|
||||
|
||||
context.move(to: CGPoint(x: 20.0, y: 10.0))
|
||||
context.addLine(to: CGPoint(x: 10.0, y: 20.0))
|
||||
context.strokePath()
|
||||
})?.withRenderingMode(.alwaysTemplate)
|
||||
}
|
@ -29,6 +29,7 @@ import CheckComponent
|
||||
import TooltipUI
|
||||
import GiftAnimationComponent
|
||||
import LottieComponent
|
||||
import ContextUI
|
||||
|
||||
private let modelButtonTag = GenericComponentViewTag()
|
||||
private let backdropButtonTag = GenericComponentViewTag()
|
||||
@ -50,6 +51,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
let upgradeGift: ((Int64?, Bool) -> Signal<ProfileGiftsContext.State.StarGift, UpgradeStarGiftError>)
|
||||
let showAttributeInfo: (Any, Float) -> Void
|
||||
let viewUpgraded: (EngineMessage.Id) -> Void
|
||||
let openMore: (ASDisplayNode, ContextGesture?) -> Void
|
||||
let getController: () -> ViewController?
|
||||
|
||||
init(
|
||||
@ -66,6 +68,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
upgradeGift: @escaping ((Int64?, Bool) -> Signal<ProfileGiftsContext.State.StarGift, UpgradeStarGiftError>),
|
||||
showAttributeInfo: @escaping (Any, Float) -> Void,
|
||||
viewUpgraded: @escaping (EngineMessage.Id) -> Void,
|
||||
openMore: @escaping (ASDisplayNode, ContextGesture?) -> Void,
|
||||
getController: @escaping () -> ViewController?
|
||||
) {
|
||||
self.context = context
|
||||
@ -81,6 +84,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
self.upgradeGift = upgradeGift
|
||||
self.showAttributeInfo = showAttributeInfo
|
||||
self.viewUpgraded = viewUpgraded
|
||||
self.openMore = openMore
|
||||
self.getController = getController
|
||||
}
|
||||
|
||||
@ -108,8 +112,6 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
|
||||
var cachedCircleImage: UIImage?
|
||||
var cachedStarImage: (UIImage, PresentationTheme)?
|
||||
var cachedCloseImage: (UIImage, PresentationTheme)?
|
||||
var cachedOverlayCloseImage: UIImage?
|
||||
|
||||
var cachedChevronImage: (UIImage, PresentationTheme)?
|
||||
var cachedSmallChevronImage: (UIImage, PresentationTheme)?
|
||||
@ -158,12 +160,17 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
self.keepOriginalInfo = true
|
||||
}
|
||||
|
||||
var peerIds: [EnginePeer.Id] = [arguments.peerId, context.account.peerId]
|
||||
var peerIds: [EnginePeer.Id] = [context.account.peerId]
|
||||
if let peerId = arguments.peerId {
|
||||
peerIds.append(peerId)
|
||||
}
|
||||
if let fromPeerId = arguments.fromPeerId, !peerIds.contains(fromPeerId) {
|
||||
peerIds.append(fromPeerId)
|
||||
}
|
||||
if case let .unique(gift) = arguments.gift {
|
||||
peerIds.append(gift.ownerPeerId)
|
||||
if case let .peerId(peerId) = gift.owner {
|
||||
peerIds.append(peerId)
|
||||
}
|
||||
for attribute in gift.attributes {
|
||||
if case let .originalInfo(senderPeerId, recipientPeerId, _, _, _) = attribute {
|
||||
if let senderPeerId {
|
||||
@ -272,10 +279,10 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
}
|
||||
|
||||
func commitUpgrade() {
|
||||
guard let arguments = self.subject.arguments, let starsContext = self.context.starsContext, let starsState = starsContext.currentState else {
|
||||
guard let arguments = self.subject.arguments, let peerId = arguments.peerId, let starsContext = self.context.starsContext, let starsState = starsContext.currentState else {
|
||||
return
|
||||
}
|
||||
let peerId = arguments.peerId
|
||||
|
||||
let proceed: (Int64?) -> Void = { formId in
|
||||
self.inProgress = true
|
||||
self.updated()
|
||||
@ -332,7 +339,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
}
|
||||
|
||||
static var body: Body {
|
||||
let closeButton = Child(Button.self)
|
||||
let buttons = Child(ButtonsComponent.self)
|
||||
let animation = Child(GiftCompositionComponent.self)
|
||||
let title = Child(MultilineTextComponent.self)
|
||||
let description = Child(MultilineTextComponent.self)
|
||||
@ -436,22 +443,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
convertStars = nil
|
||||
titleString = ""
|
||||
}
|
||||
|
||||
let closeImage: UIImage
|
||||
let closeOverlayImage: UIImage
|
||||
if let (image, theme) = state.cachedCloseImage, theme === environment.theme {
|
||||
closeImage = image
|
||||
} else {
|
||||
closeImage = generateCloseButtonImage(backgroundColor: UIColor(rgb: 0x808084, alpha: 0.1), foregroundColor: theme.actionSheet.inputClearButtonColor)!
|
||||
state.cachedCloseImage = (closeImage, theme)
|
||||
}
|
||||
if let image = state.cachedOverlayCloseImage {
|
||||
closeOverlayImage = image
|
||||
} else {
|
||||
closeOverlayImage = generateCloseButtonImage(backgroundColor: UIColor(rgb: 0xffffff, alpha: 0.1), foregroundColor: .white)!
|
||||
state.cachedOverlayCloseImage = closeOverlayImage
|
||||
}
|
||||
|
||||
|
||||
var showUpgradePreview = false
|
||||
if state.inUpgradePreview, let _ = state.sampleGiftAttributes {
|
||||
showUpgradePreview = true
|
||||
@ -460,10 +452,12 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
}
|
||||
|
||||
let cancel = component.cancel
|
||||
let closeButton = closeButton.update(
|
||||
component: Button(
|
||||
content: AnyComponent(Image(image: showUpgradePreview || uniqueGift != nil ? closeOverlayImage : closeImage)),
|
||||
action: { [weak state] in
|
||||
let buttons = buttons.update(
|
||||
component: ButtonsComponent(
|
||||
theme: theme,
|
||||
isOverlay: showUpgradePreview || uniqueGift != nil,
|
||||
showMoreButton: uniqueGift != nil,
|
||||
closePressed: { [weak state] in
|
||||
guard let state else {
|
||||
return
|
||||
}
|
||||
@ -473,10 +467,13 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
} else {
|
||||
cancel(true)
|
||||
}
|
||||
},
|
||||
morePressed: { node, gesture in
|
||||
component.openMore(node, gesture)
|
||||
}
|
||||
),
|
||||
availableSize: CGSize(width: 30.0, height: 30.0),
|
||||
transition: .immediate
|
||||
transition: context.transition
|
||||
)
|
||||
|
||||
var originY: CGFloat = 0.0
|
||||
@ -888,70 +885,81 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
|
||||
if !soldOut {
|
||||
if let uniqueGift {
|
||||
if let peer = state.peerMap[uniqueGift.ownerPeerId] {
|
||||
let ownerComponent: AnyComponent<Empty>
|
||||
if let _ = subject.arguments?.transferStars {
|
||||
ownerComponent = AnyComponent(
|
||||
HStack([
|
||||
AnyComponentWithIdentity(
|
||||
id: AnyHashable(0),
|
||||
component: AnyComponent(Button(
|
||||
content: AnyComponent(
|
||||
PeerCellComponent(
|
||||
switch uniqueGift.owner {
|
||||
case let .peerId(peerId):
|
||||
if let peer = state.peerMap[peerId] {
|
||||
let ownerComponent: AnyComponent<Empty>
|
||||
if let _ = subject.arguments?.transferStars {
|
||||
ownerComponent = AnyComponent(
|
||||
HStack([
|
||||
AnyComponentWithIdentity(
|
||||
id: AnyHashable(0),
|
||||
component: AnyComponent(Button(
|
||||
content: AnyComponent(
|
||||
PeerCellComponent(
|
||||
context: component.context,
|
||||
theme: theme,
|
||||
strings: strings,
|
||||
peer: peer
|
||||
)
|
||||
),
|
||||
action: {
|
||||
component.openPeer(peer)
|
||||
Queue.mainQueue().after(1.0, {
|
||||
component.cancel(false)
|
||||
})
|
||||
}
|
||||
))
|
||||
),
|
||||
AnyComponentWithIdentity(
|
||||
id: AnyHashable(1),
|
||||
component: AnyComponent(Button(
|
||||
content: AnyComponent(ButtonContentComponent(
|
||||
context: component.context,
|
||||
theme: theme,
|
||||
strings: strings,
|
||||
peer: peer
|
||||
)
|
||||
),
|
||||
action: {
|
||||
component.openPeer(peer)
|
||||
Queue.mainQueue().after(1.0, {
|
||||
component.cancel(false)
|
||||
})
|
||||
}
|
||||
))
|
||||
text: strings.Gift_Unique_Transfer,
|
||||
color: theme.list.itemAccentColor
|
||||
)),
|
||||
action: {
|
||||
component.transferGift()
|
||||
Queue.mainQueue().after(1.0, {
|
||||
component.cancel(false)
|
||||
})
|
||||
}
|
||||
))
|
||||
)
|
||||
], spacing: 4.0)
|
||||
)
|
||||
} else {
|
||||
ownerComponent = AnyComponent(Button(
|
||||
content: AnyComponent(
|
||||
PeerCellComponent(
|
||||
context: component.context,
|
||||
theme: theme,
|
||||
strings: strings,
|
||||
peer: peer
|
||||
)
|
||||
),
|
||||
AnyComponentWithIdentity(
|
||||
id: AnyHashable(1),
|
||||
component: AnyComponent(Button(
|
||||
content: AnyComponent(ButtonContentComponent(
|
||||
context: component.context,
|
||||
text: strings.Gift_Unique_Transfer,
|
||||
color: theme.list.itemAccentColor
|
||||
)),
|
||||
action: {
|
||||
component.transferGift()
|
||||
Queue.mainQueue().after(1.0, {
|
||||
component.cancel(false)
|
||||
})
|
||||
}
|
||||
))
|
||||
)
|
||||
], spacing: 4.0)
|
||||
)
|
||||
} else {
|
||||
ownerComponent = AnyComponent(Button(
|
||||
content: AnyComponent(
|
||||
PeerCellComponent(
|
||||
context: component.context,
|
||||
theme: theme,
|
||||
strings: strings,
|
||||
peer: peer
|
||||
)
|
||||
),
|
||||
action: {
|
||||
component.openPeer(peer)
|
||||
Queue.mainQueue().after(1.0, {
|
||||
component.cancel(false)
|
||||
})
|
||||
}
|
||||
action: {
|
||||
component.openPeer(peer)
|
||||
Queue.mainQueue().after(1.0, {
|
||||
component.cancel(false)
|
||||
})
|
||||
}
|
||||
))
|
||||
}
|
||||
tableItems.append(.init(
|
||||
id: "owner",
|
||||
title: strings.Gift_Unique_Owner,
|
||||
component: ownerComponent
|
||||
))
|
||||
}
|
||||
case let .name(name):
|
||||
tableItems.append(.init(
|
||||
id: "owner",
|
||||
id: "anon_owner",
|
||||
title: strings.Gift_Unique_Owner,
|
||||
component: ownerComponent
|
||||
component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: name, font: tableFont, textColor: tableTextColor)))
|
||||
)
|
||||
))
|
||||
}
|
||||
} else if let peerId = subject.arguments?.fromPeerId, let peer = state.peerMap[peerId] {
|
||||
@ -1593,8 +1601,8 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
originY += buttonChild.size.height
|
||||
originY += 7.0
|
||||
|
||||
context.add(closeButton
|
||||
.position(CGPoint(x: context.availableSize.width - environment.safeInsets.left - closeButton.size.width, y: 28.0))
|
||||
context.add(buttons
|
||||
.position(CGPoint(x: context.availableSize.width - environment.safeInsets.left - 16.0 - buttons.size.width / 2.0, y: 28.0))
|
||||
)
|
||||
|
||||
let contentSize = CGSize(width: context.availableSize.width, height: originY + 5.0 + environment.safeInsets.bottom)
|
||||
@ -1618,6 +1626,7 @@ private final class GiftViewSheetComponent: CombinedComponent {
|
||||
let transferGift: () -> Void
|
||||
let upgradeGift: ((Int64?, Bool) -> Signal<ProfileGiftsContext.State.StarGift, UpgradeStarGiftError>)
|
||||
let viewUpgraded: (EngineMessage.Id) -> Void
|
||||
let openMore: (ASDisplayNode, ContextGesture?) -> Void
|
||||
let showAttributeInfo: (Any, Float) -> Void
|
||||
|
||||
init(
|
||||
@ -1632,6 +1641,7 @@ private final class GiftViewSheetComponent: CombinedComponent {
|
||||
transferGift: @escaping () -> Void,
|
||||
upgradeGift: @escaping ((Int64?, Bool) -> Signal<ProfileGiftsContext.State.StarGift, UpgradeStarGiftError>),
|
||||
viewUpgraded: @escaping (EngineMessage.Id) -> Void,
|
||||
openMore: @escaping (ASDisplayNode, ContextGesture?) -> Void,
|
||||
showAttributeInfo: @escaping (Any, Float) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
@ -1645,6 +1655,7 @@ private final class GiftViewSheetComponent: CombinedComponent {
|
||||
self.transferGift = transferGift
|
||||
self.upgradeGift = upgradeGift
|
||||
self.viewUpgraded = viewUpgraded
|
||||
self.openMore = openMore
|
||||
self.showAttributeInfo = showAttributeInfo
|
||||
}
|
||||
|
||||
@ -1695,6 +1706,7 @@ private final class GiftViewSheetComponent: CombinedComponent {
|
||||
upgradeGift: context.component.upgradeGift,
|
||||
showAttributeInfo: context.component.showAttributeInfo,
|
||||
viewUpgraded: context.component.viewUpgraded,
|
||||
openMore: context.component.openMore,
|
||||
getController: controller
|
||||
)),
|
||||
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
|
||||
@ -1764,11 +1776,12 @@ private final class GiftViewSheetComponent: CombinedComponent {
|
||||
public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
public enum Subject: Equatable {
|
||||
case message(EngineMessage)
|
||||
case uniqueGift(StarGift.UniqueGift)
|
||||
case profileGift(EnginePeer.Id, ProfileGiftsContext.State.StarGift)
|
||||
case soldOutGift(StarGift.Gift)
|
||||
case upgradePreview([StarGift.UniqueGift.Attribute], String)
|
||||
|
||||
var arguments: (peerId: EnginePeer.Id, fromPeerId: EnginePeer.Id?, fromPeerName: String?, messageId: EngineMessage.Id?, incoming: Bool, gift: StarGift, date: Int32, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool, upgraded: Bool, canUpgrade: Bool, upgradeStars: Int64?, transferStars: Int64?, canExportDate: Int32?, upgradeMessageId: Int32?)? {
|
||||
var arguments: (peerId: EnginePeer.Id?, fromPeerId: EnginePeer.Id?, fromPeerName: String?, messageId: EngineMessage.Id?, incoming: Bool, gift: StarGift, date: Int32, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool, upgraded: Bool, canUpgrade: Bool, upgradeStars: Int64?, transferStars: Int64?, canExportDate: Int32?, upgradeMessageId: Int32?)? {
|
||||
switch self {
|
||||
case let .message(message):
|
||||
if let action = message.media.first(where: { $0 is TelegramMediaAction }) as? TelegramMediaAction {
|
||||
@ -1793,6 +1806,8 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
case let .uniqueGift(gift):
|
||||
return (nil, nil, nil, nil, false, .unique(gift), 0, nil, nil, nil, false, false, false, false, false, nil, nil, nil, nil)
|
||||
case let .profileGift(peerId, gift):
|
||||
return (peerId, gift.fromPeer?.id, gift.fromPeer?.compactDisplayTitle, gift.messageId, false, gift.gift, gift.date, gift.convertStars, gift.text, gift.entities, gift.nameHidden, gift.savedToProfile, false, false, gift.canUpgrade, gift.upgradeStars, gift.transferStars, gift.canExportDate, nil)
|
||||
case .soldOutGift:
|
||||
@ -1817,7 +1832,8 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
updateSavedToProfile: ((EngineMessage.Id, Bool) -> Void)? = nil,
|
||||
convertToStars: (() -> Void)? = nil,
|
||||
transferGift: ((Bool, EnginePeer.Id) -> Void)? = nil,
|
||||
upgradeGift: ((Int64?, Bool) -> Signal<ProfileGiftsContext.State.StarGift, UpgradeStarGiftError>)? = nil
|
||||
upgradeGift: ((Int64?, Bool) -> Signal<ProfileGiftsContext.State.StarGift, UpgradeStarGiftError>)? = nil,
|
||||
shareStory: (() -> Void)? = nil
|
||||
) {
|
||||
self.context = context
|
||||
self.subject = subject
|
||||
@ -1831,6 +1847,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
var transferGiftImpl: (() -> Void)?
|
||||
var showAttributeInfoImpl: ((Any, Float) -> Void)?
|
||||
var upgradeGiftImpl: ((Int64?, Bool) -> Signal<ProfileGiftsContext.State.StarGift, UpgradeStarGiftError>)?
|
||||
var openMoreImpl: ((ASDisplayNode, ContextGesture?) -> Void)?
|
||||
var viewUpgradedImpl: ((EngineMessage.Id) -> Void)?
|
||||
|
||||
super.init(
|
||||
@ -1865,6 +1882,9 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
viewUpgraded: { messageId in
|
||||
viewUpgradedImpl?(messageId)
|
||||
},
|
||||
openMore: { node, gesture in
|
||||
openMoreImpl?(node, gesture)
|
||||
},
|
||||
showAttributeInfo: { tag, rarity in
|
||||
showAttributeInfoImpl?(tag, rarity)
|
||||
}
|
||||
@ -2151,6 +2171,66 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
})
|
||||
self.present(controller, in: .current)
|
||||
}
|
||||
|
||||
openMoreImpl = { [weak self] node, gesture in
|
||||
guard let self, let arguments = self.subject.arguments, case let .unique(gift) = arguments.gift else {
|
||||
return
|
||||
}
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
//TODO:localize
|
||||
let link = "https://t.me/nft/\(gift.slug)"
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: "Copy Link", icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c?.dismiss(completion: nil)
|
||||
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
UIPasteboard.general.string = link
|
||||
|
||||
self.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
||||
})))
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: "Share", icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c?.dismiss(completion: nil)
|
||||
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let shareController = context.sharedContext.makeShareController(
|
||||
context: context,
|
||||
subject: .url(link),
|
||||
forceExternal: false,
|
||||
shareStory: shareStory,
|
||||
actionCompleted: { [weak self] in
|
||||
self?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
||||
}
|
||||
)
|
||||
self.present(shareController, in: .window(.root))
|
||||
})))
|
||||
|
||||
if let _ = arguments.transferStars {
|
||||
items.append(.action(ContextMenuActionItem(text: "Transfer", icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Replace"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, _ in
|
||||
c?.dismiss(completion: nil)
|
||||
|
||||
transferGiftImpl?()
|
||||
})))
|
||||
}
|
||||
|
||||
let contextController = ContextController(presentationData: presentationData, source: .reference(GiftViewContextReferenceContentSource(controller: self, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
self.presentInGlobalOverlay(contextController)
|
||||
}
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
@ -2298,6 +2378,7 @@ private final class TableComponent: CombinedComponent {
|
||||
|
||||
let backgroundColor = context.component.theme.actionSheet.opaqueItemBackgroundColor
|
||||
let borderColor = backgroundColor.mixedWith(context.component.theme.list.itemBlocksSeparatorColor, alpha: 0.6)
|
||||
let secondaryBackgroundColor = context.component.theme.overallDarkAppearance ? context.component.theme.list.itemModalBlocksBackgroundColor : context.component.theme.list.itemInputField.backgroundColor
|
||||
|
||||
var leftColumnWidth: CGFloat = 0.0
|
||||
|
||||
@ -2388,7 +2469,7 @@ private final class TableComponent: CombinedComponent {
|
||||
if hasLastBackground {
|
||||
let lastRowHeight = rowHeights[i - 1] ?? 0
|
||||
let lastBackground = lastBackground.update(
|
||||
component: Rectangle(color: context.component.theme.list.itemInputField.backgroundColor),
|
||||
component: Rectangle(color: secondaryBackgroundColor),
|
||||
availableSize: CGSize(width: context.availableSize.width, height: lastRowHeight),
|
||||
transition: context.transition
|
||||
)
|
||||
@ -2399,7 +2480,7 @@ private final class TableComponent: CombinedComponent {
|
||||
}
|
||||
|
||||
let leftColumnBackground = leftColumnBackground.update(
|
||||
component: Rectangle(color: context.component.theme.list.itemInputField.backgroundColor),
|
||||
component: Rectangle(color: secondaryBackgroundColor),
|
||||
availableSize: CGSize(width: leftColumnWidth, height: innerTotalHeight),
|
||||
transition: context.transition
|
||||
)
|
||||
@ -2597,27 +2678,6 @@ private final class PeerCellComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
private func generateCloseButtonImage(backgroundColor: UIColor, foregroundColor: UIColor) -> UIImage? {
|
||||
return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.setFillColor(backgroundColor.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.setLineWidth(2.0)
|
||||
context.setLineCap(.round)
|
||||
context.setStrokeColor(foregroundColor.cgColor)
|
||||
|
||||
context.move(to: CGPoint(x: 10.0, y: 10.0))
|
||||
context.addLine(to: CGPoint(x: 20.0, y: 20.0))
|
||||
context.strokePath()
|
||||
|
||||
context.move(to: CGPoint(x: 20.0, y: 10.0))
|
||||
context.addLine(to: CGPoint(x: 10.0, y: 20.0))
|
||||
context.strokePath()
|
||||
})
|
||||
}
|
||||
|
||||
private final class ButtonContentComponent: Component {
|
||||
let context: AccountContext
|
||||
let text: String
|
||||
@ -2914,3 +2974,17 @@ private final class ParagraphComponent: CombinedComponent {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class GiftViewContextReferenceContentSource: ContextReferenceContentSource {
|
||||
private let controller: ViewController
|
||||
private let sourceNode: ASDisplayNode
|
||||
|
||||
init(controller: ViewController, sourceNode: ASDisplayNode) {
|
||||
self.controller = controller
|
||||
self.sourceNode = sourceNode
|
||||
}
|
||||
|
||||
func transitionInfo() -> ContextControllerReferenceViewInfo? {
|
||||
return ContextControllerReferenceViewInfo(referenceView: self.sourceNode.view, contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||
}
|
||||
}
|
||||
|
@ -180,6 +180,11 @@ public enum CodableDrawingEntity: Equatable {
|
||||
coordinates: coordinates,
|
||||
messageId: messageId
|
||||
)
|
||||
} else if case let .gift(gift, _) = entity.content {
|
||||
return .starGift(
|
||||
coordinates: coordinates,
|
||||
slug: gift.slug
|
||||
)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ public final class DrawingStickerEntity: DrawingEntity, Codable {
|
||||
case video(TelegramMediaFile)
|
||||
case dualVideoReference(Bool)
|
||||
case message([MessageId], CGSize, TelegramMediaFile?, CGRect?, CGFloat?)
|
||||
case gift(StarGift.UniqueGift, CGSize)
|
||||
|
||||
public static func == (lhs: Content, rhs: Content) -> Bool {
|
||||
switch lhs {
|
||||
@ -78,6 +79,12 @@ public final class DrawingStickerEntity: DrawingEntity, Codable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .gift(lhsGift, lhsSize):
|
||||
if case let .gift(rhsGift, rhsSize) = rhs {
|
||||
return lhsGift == rhsGift && lhsSize == rhsSize
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -98,6 +105,9 @@ public final class DrawingStickerEntity: DrawingEntity, Codable {
|
||||
case messageSize
|
||||
case messageMediaRect
|
||||
case messageMediaCornerRadius
|
||||
|
||||
case gift
|
||||
|
||||
case referenceDrawingSize
|
||||
case position
|
||||
case scale
|
||||
@ -120,6 +130,8 @@ public final class DrawingStickerEntity: DrawingEntity, Codable {
|
||||
self.scale = max(0.59, min(1.77, self.scale))
|
||||
} else if case .message = self.content {
|
||||
self.scale = max(2.5, self.scale)
|
||||
} else if case .gift = self.content {
|
||||
self.scale = max(2.5, self.scale)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -164,6 +176,8 @@ public final class DrawingStickerEntity: DrawingEntity, Codable {
|
||||
dimensions = CGSize(width: 512.0, height: 512.0)
|
||||
case let .message(_, size, _, _, _):
|
||||
dimensions = size
|
||||
case let .gift(_, size):
|
||||
dimensions = size
|
||||
}
|
||||
|
||||
let boundingSize = CGSize(width: size, height: size)
|
||||
@ -191,7 +205,7 @@ public final class DrawingStickerEntity: DrawingEntity, Codable {
|
||||
return true
|
||||
case .dualVideoReference:
|
||||
return true
|
||||
case .message:
|
||||
case .message, .gift:
|
||||
return !(self.renderSubEntities ?? []).isEmpty
|
||||
}
|
||||
}
|
||||
@ -202,7 +216,7 @@ public final class DrawingStickerEntity: DrawingEntity, Codable {
|
||||
return imageType == .rectangle
|
||||
case .video:
|
||||
return true
|
||||
case .message:
|
||||
case .message, .gift:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
@ -232,7 +246,10 @@ public final class DrawingStickerEntity: DrawingEntity, Codable {
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
self.uuid = try container.decode(UUID.self, forKey: .uuid)
|
||||
if let messageIds = try container.decodeIfPresent([MessageId].self, forKey: .messageIds) {
|
||||
if let gift = try container.decodeIfPresent(StarGift.UniqueGift.self, forKey: .gift) {
|
||||
let size = try container.decodeIfPresent(CGSize.self, forKey: .messageSize) ?? .zero
|
||||
self.content = .gift(gift, size)
|
||||
} else if let messageIds = try container.decodeIfPresent([MessageId].self, forKey: .messageIds) {
|
||||
let size = try container.decodeIfPresent(CGSize.self, forKey: .messageSize) ?? .zero
|
||||
let file = try container.decodeIfPresent(TelegramMediaFile.self, forKey: .messageFile)
|
||||
let mediaRect = try container.decodeIfPresent(CGRect.self, forKey: .messageMediaRect)
|
||||
@ -343,6 +360,9 @@ public final class DrawingStickerEntity: DrawingEntity, Codable {
|
||||
try container.encodeIfPresent(file, forKey: .messageFile)
|
||||
try container.encodeIfPresent(mediaRect, forKey: .messageMediaRect)
|
||||
try container.encodeIfPresent(mediaCornerRadius, forKey: .messageMediaCornerRadius)
|
||||
case let .gift(gift, size):
|
||||
try container.encode(gift, forKey: .gift)
|
||||
try container.encode(size, forKey: .messageSize)
|
||||
}
|
||||
try container.encode(self.referenceDrawingSize, forKey: .referenceDrawingSize)
|
||||
try container.encode(self.position, forKey: .position)
|
||||
|
@ -87,17 +87,26 @@ public final class DrawingMessageRenderer {
|
||||
private let isNight: Bool
|
||||
private let isOverlay: Bool
|
||||
private let isLink: Bool
|
||||
private let isGift: Bool
|
||||
|
||||
private let messagesContainerNode: ASDisplayNode
|
||||
private var avatarHeaderNode: ListViewItemHeaderNode?
|
||||
private var messageNodes: [ListViewItemNode]?
|
||||
|
||||
init(context: AccountContext, messages: [Message], isNight: Bool = false, isOverlay: Bool = false, isLink: Bool = false) {
|
||||
init(
|
||||
context: AccountContext,
|
||||
messages: [Message],
|
||||
isNight: Bool = false,
|
||||
isOverlay: Bool = false,
|
||||
isLink: Bool = false,
|
||||
isGift: Bool = false
|
||||
) {
|
||||
self.context = context
|
||||
self.messages = messages
|
||||
self.isNight = isNight
|
||||
self.isOverlay = isOverlay
|
||||
self.isLink = isLink
|
||||
self.isGift = isGift
|
||||
|
||||
self.messagesContainerNode = ASDisplayNode()
|
||||
self.messagesContainerNode.clipsToBounds = true
|
||||
@ -198,7 +207,13 @@ public final class DrawingMessageRenderer {
|
||||
|
||||
let avatarHeaderItem: ListViewItemHeader?
|
||||
if let author = self.messages.first?.author {
|
||||
avatarHeaderItem = self.context.sharedContext.makeChatMessageAvatarHeaderItem(context: self.context, timestamp: self.messages.first?.timestamp ?? 0, peer: self.messages.first!.peers[author.id]!, message: self.messages.first!, theme: theme, strings: presentationData.strings, wallpaper: presentationData.chatWallpaper, fontSize: presentationData.chatFontSize, chatBubbleCorners: chatBubbleCorners, dateTimeFormat: presentationData.dateTimeFormat, nameOrder: presentationData.nameDisplayOrder)
|
||||
let avatarPeer: Peer
|
||||
if let peer = self.messages.first!.peers[author.id] {
|
||||
avatarPeer = peer
|
||||
} else {
|
||||
avatarPeer = author
|
||||
}
|
||||
avatarHeaderItem = self.context.sharedContext.makeChatMessageAvatarHeaderItem(context: self.context, timestamp: self.messages.first?.timestamp ?? 0, peer: avatarPeer, message: self.messages.first!, theme: theme, strings: presentationData.strings, wallpaper: presentationData.chatWallpaper, fontSize: presentationData.chatFontSize, chatBubbleCorners: chatBubbleCorners, dateTimeFormat: presentationData.dateTimeFormat, nameOrder: presentationData.nameDisplayOrder)
|
||||
} else {
|
||||
avatarHeaderItem = nil
|
||||
}
|
||||
@ -208,6 +223,8 @@ public final class DrawingMessageRenderer {
|
||||
var leftInset: CGFloat = 37.0
|
||||
if self.isLink {
|
||||
leftInset = -6.0
|
||||
} else if self.isGift {
|
||||
leftInset = -50.0
|
||||
}
|
||||
let containerWidth = layout.size.width - inset * 2.0
|
||||
let params = ListViewItemLayoutParams(width: containerWidth, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
||||
@ -329,13 +346,19 @@ public final class DrawingMessageRenderer {
|
||||
private let nightContainerNode: ContainerNode
|
||||
private let overlayContainerNode: ContainerNode
|
||||
|
||||
public init(context: AccountContext, messages: [Message], parentView: UIView, isLink: Bool = false) {
|
||||
public init(
|
||||
context: AccountContext,
|
||||
messages: [Message],
|
||||
parentView: UIView,
|
||||
isLink: Bool = false,
|
||||
isGift: Bool = false
|
||||
) {
|
||||
self.context = context
|
||||
self.messages = messages
|
||||
|
||||
self.dayContainerNode = ContainerNode(context: context, messages: messages, isLink: isLink)
|
||||
self.nightContainerNode = ContainerNode(context: context, messages: messages, isNight: true, isLink: isLink)
|
||||
self.overlayContainerNode = ContainerNode(context: context, messages: messages, isOverlay: true, isLink: isLink)
|
||||
self.dayContainerNode = ContainerNode(context: context, messages: messages, isLink: isLink, isGift: isGift)
|
||||
self.nightContainerNode = ContainerNode(context: context, messages: messages, isNight: true, isLink: isLink, isGift: isGift)
|
||||
self.overlayContainerNode = ContainerNode(context: context, messages: messages, isOverlay: true, isLink: isLink, isGift: isGift)
|
||||
|
||||
parentView.addSubview(self.dayContainerNode.view)
|
||||
parentView.addSubview(self.nightContainerNode.view)
|
||||
|
@ -168,6 +168,7 @@ public final class MediaEditor {
|
||||
case asset(PHAsset)
|
||||
case draft(MediaEditorDraft)
|
||||
case message(MessageId)
|
||||
case gift(StarGift.UniqueGift)
|
||||
case sticker(TelegramMediaFile)
|
||||
|
||||
var dimensions: PixelDimensions {
|
||||
@ -178,7 +179,7 @@ public final class MediaEditor {
|
||||
return PixelDimensions(width: Int32(asset.pixelWidth), height: Int32(asset.pixelHeight))
|
||||
case let .draft(draft):
|
||||
return draft.dimensions
|
||||
case .message, .sticker, .videoCollage:
|
||||
case .message, .gift, .sticker, .videoCollage:
|
||||
return PixelDimensions(width: 1080, height: 1920)
|
||||
}
|
||||
}
|
||||
@ -817,7 +818,7 @@ public final class MediaEditor {
|
||||
player = self.makePlayer(asset: asset)
|
||||
}
|
||||
}
|
||||
return getChatWallpaperImage(context: self.context, messageId: messageId)
|
||||
return getChatWallpaperImage(context: self.context, peerId: messageId.peerId)
|
||||
|> map { _, image, nightImage in
|
||||
return TextureSourceResult(
|
||||
image: image,
|
||||
@ -828,6 +829,17 @@ public final class MediaEditor {
|
||||
)
|
||||
}
|
||||
}
|
||||
case .gift:
|
||||
textureSource = getChatWallpaperImage(context: self.context, peerId: self.context.account.peerId)
|
||||
|> map { _, image, nightImage in
|
||||
return TextureSourceResult(
|
||||
image: image,
|
||||
nightImage: nightImage,
|
||||
player: nil,
|
||||
playerIsReference: true,
|
||||
gradientColors: GradientColors(top: .black, bottom: .black)
|
||||
)
|
||||
}
|
||||
case let .sticker(file):
|
||||
let entity = MediaEditorComposerStickerEntity(
|
||||
postbox: self.context.account.postbox,
|
||||
|
@ -94,7 +94,7 @@ func composerEntitiesForDrawingEntity(postbox: Postbox, textScale: CGFloat, enti
|
||||
content = .video(file)
|
||||
case .dualVideoReference:
|
||||
return []
|
||||
case .message:
|
||||
case .message, .gift:
|
||||
if let renderImage = entity.renderImage, let image = CIImage(image: renderImage, options: [.colorSpace: colorSpace]) {
|
||||
var entities: [MediaEditorComposerEntity] = []
|
||||
entities.append(MediaEditorComposerStaticEntity(image: image, position: entity.position, scale: entity.scale, rotation: entity.rotation, baseSize: entity.baseSize, mirrored: false))
|
||||
|
@ -135,7 +135,7 @@ func getTextureImage(device: MTLDevice, texture: MTLTexture, mirror: Bool = fals
|
||||
return UIImage(cgImage: cgImage)
|
||||
}
|
||||
|
||||
public func getChatWallpaperImage(context: AccountContext, messageId: EngineMessage.Id) -> Signal<(CGSize, UIImage?, UIImage?), NoError> {
|
||||
public func getChatWallpaperImage(context: AccountContext, peerId: EnginePeer.Id) -> Signal<(CGSize, UIImage?, UIImage?), NoError> {
|
||||
let themeSettings = context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings])
|
||||
|> map { sharedData -> PresentationThemeSettings in
|
||||
let themeSettings: PresentationThemeSettings
|
||||
@ -148,7 +148,7 @@ public func getChatWallpaperImage(context: AccountContext, messageId: EngineMess
|
||||
}
|
||||
|
||||
let peerWallpaper = context.account.postbox.transaction { transaction -> TelegramWallpaper? in
|
||||
return (transaction.getPeerCachedData(peerId: messageId.peerId) as? CachedChannelData)?.wallpaper
|
||||
return (transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData)?.wallpaper
|
||||
}
|
||||
|
||||
return combineLatest(themeSettings, peerWallpaper)
|
||||
|
@ -203,7 +203,7 @@ extension MediaEditorScreenImpl {
|
||||
} else if let image = UIImage(contentsOfFile: draft.fullPath(engine: context.engine)) {
|
||||
innerSaveDraft(media: .image(image: image, dimensions: draft.dimensions))
|
||||
}
|
||||
case .message:
|
||||
case .message, .gift:
|
||||
if let pixel = generateSingleColorImage(size: CGSize(width: 1, height: 1), color: .black) {
|
||||
innerSaveDraft(media: .image(image: pixel, dimensions: PixelDimensions(width: 1080, height: 1920)))
|
||||
}
|
||||
|
@ -433,7 +433,6 @@ final class MediaEditorScreenComponent: Component {
|
||||
}
|
||||
},
|
||||
dismissTextInput: {
|
||||
|
||||
},
|
||||
insertText: { [weak self] text in
|
||||
if let self {
|
||||
@ -1661,7 +1660,17 @@ final class MediaEditorScreenComponent: Component {
|
||||
var topButtonOffsetX: CGFloat = 0.0
|
||||
var topButtonOffsetY: CGFloat = 0.0
|
||||
|
||||
if let subject = controller.node.subject, case .message = subject {
|
||||
var hasDayNightSelection = false
|
||||
if let subject = controller.node.subject {
|
||||
switch subject {
|
||||
case .message, .gift:
|
||||
hasDayNightSelection = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if hasDayNightSelection {
|
||||
let isNightTheme = mediaEditor?.values.nightTheme == true
|
||||
|
||||
let dayNightContentComponent: AnyComponentWithIdentity<Empty>
|
||||
@ -3145,6 +3154,8 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
isSavingAvailable = true
|
||||
case .message:
|
||||
isSavingAvailable = true
|
||||
case .gift:
|
||||
isSavingAvailable = true
|
||||
default:
|
||||
isSavingAvailable = false
|
||||
}
|
||||
@ -3237,8 +3248,13 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
mediaEditor.seek(initialVideoPosition, andPlay: true)
|
||||
}
|
||||
}
|
||||
if case .message = subject, self.context.sharedContext.currentPresentationData.with({$0}).autoNightModeTriggered {
|
||||
mediaEditor.setNightTheme(true)
|
||||
if self.context.sharedContext.currentPresentationData.with({$0}).autoNightModeTriggered {
|
||||
switch subject {
|
||||
case .message, .gift:
|
||||
mediaEditor.setNightTheme(true)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
mediaEditor.valuesUpdated = { [weak self] values in
|
||||
if let self, let controller = self.controller, values.gradientColors != nil, controller.previousSavedValues != values {
|
||||
@ -3284,28 +3300,33 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
self.stickerMaskDrawingView?.clearWithEmptyColor()
|
||||
}
|
||||
|
||||
if case .message = effectiveSubject {
|
||||
} else {
|
||||
switch effectiveSubject {
|
||||
case .message, .gift:
|
||||
break
|
||||
default:
|
||||
self.readyValue.set(.single(true))
|
||||
}
|
||||
|
||||
if case let .image(_, _, additionalImage, position) = effectiveSubject, let additionalImage {
|
||||
let image = generateImage(CGSize(width: additionalImage.size.width, height: additionalImage.size.width), contextGenerator: { size, context in
|
||||
let bounds = CGRect(origin: .zero, size: size)
|
||||
context.clear(bounds)
|
||||
context.addEllipse(in: bounds)
|
||||
context.clip()
|
||||
|
||||
if let cgImage = additionalImage.cgImage {
|
||||
context.draw(cgImage, in: CGRect(origin: CGPoint(x: (size.width - additionalImage.size.width) / 2.0, y: (size.height - additionalImage.size.height) / 2.0), size: additionalImage.size))
|
||||
}
|
||||
}, scale: 1.0)
|
||||
let imageEntity = DrawingStickerEntity(content: .image(image ?? additionalImage, .dualPhoto))
|
||||
imageEntity.referenceDrawingSize = storyDimensions
|
||||
imageEntity.scale = 1.625
|
||||
imageEntity.position = position.getPosition(storyDimensions)
|
||||
self.entitiesView.add(imageEntity, announce: false)
|
||||
} else if case let .video(_, _, mirror, additionalVideoPath, _, _, _, changes, position) = effectiveSubject {
|
||||
switch effectiveSubject {
|
||||
case let .image(_, _, additionalImage, position):
|
||||
if let additionalImage {
|
||||
let image = generateImage(CGSize(width: additionalImage.size.width, height: additionalImage.size.width), contextGenerator: { size, context in
|
||||
let bounds = CGRect(origin: .zero, size: size)
|
||||
context.clear(bounds)
|
||||
context.addEllipse(in: bounds)
|
||||
context.clip()
|
||||
|
||||
if let cgImage = additionalImage.cgImage {
|
||||
context.draw(cgImage, in: CGRect(origin: CGPoint(x: (size.width - additionalImage.size.width) / 2.0, y: (size.height - additionalImage.size.height) / 2.0), size: additionalImage.size))
|
||||
}
|
||||
}, scale: 1.0)
|
||||
let imageEntity = DrawingStickerEntity(content: .image(image ?? additionalImage, .dualPhoto))
|
||||
imageEntity.referenceDrawingSize = storyDimensions
|
||||
imageEntity.scale = 1.625
|
||||
imageEntity.position = position.getPosition(storyDimensions)
|
||||
self.entitiesView.add(imageEntity, announce: false)
|
||||
}
|
||||
case let .video(_, _, mirror, additionalVideoPath, _, _, _, changes, position):
|
||||
mediaEditor.setVideoIsMirrored(mirror)
|
||||
if let additionalVideoPath {
|
||||
let videoEntity = DrawingStickerEntity(content: .dualVideoReference(false))
|
||||
@ -3324,24 +3345,41 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if case let .videoCollage(items) = effectiveSubject {
|
||||
case let .videoCollage(items):
|
||||
mediaEditor.setupCollage(items.map { $0.editorItem })
|
||||
} else if case let .message(messageIds) = effectiveSubject {
|
||||
case let .sticker(_, emoji):
|
||||
controller.stickerSelectedEmoji = emoji
|
||||
case .message, .gift:
|
||||
var isGift = false
|
||||
let messages: Signal<[Message], NoError>
|
||||
if case let .message(messageIds) = effectiveSubject {
|
||||
messages = self.context.engine.data.get(
|
||||
EngineDataMap(messageIds.map(TelegramEngine.EngineData.Item.Messages.Message.init(id:)))
|
||||
)
|
||||
|> map { result in
|
||||
var messages: [Message] = []
|
||||
for id in messageIds {
|
||||
if let maybeMessage = result[id], let message = maybeMessage {
|
||||
messages.append(message._asMessage())
|
||||
}
|
||||
}
|
||||
return messages
|
||||
}
|
||||
} else if case let .gift(gift) = effectiveSubject {
|
||||
isGift = true
|
||||
let media: [Media] = [TelegramMediaAction(action: .starGiftUnique(gift: .unique(gift), isUpgrade: false, isTransferred: false, savedToProfile: false, canExportDate: nil, transferStars: nil, isRefunded: false))]
|
||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: self.context.account.peerId, namespace: Namespaces.Message.Cloud, id: -1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: nil, text: "", attributes: [], media: media, peers: SimpleDictionary(), associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
messages = .single([message])
|
||||
} else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
let isNightTheme = mediaEditor.values.nightTheme
|
||||
let _ = ((self.context.engine.data.get(
|
||||
EngineDataMap(messageIds.map(TelegramEngine.EngineData.Item.Messages.Message.init(id:)))
|
||||
))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
let _ = (messages
|
||||
|> deliverOnMainQueue).start(next: { [weak self] messages in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
var messages: [Message] = []
|
||||
for id in messageIds {
|
||||
if let maybeMessage = result[id], let message = maybeMessage {
|
||||
messages.append(message._asMessage())
|
||||
}
|
||||
}
|
||||
|
||||
var messageFile: TelegramMediaFile?
|
||||
if let maybeFile = messages.first?.media.first(where: { $0 is TelegramMediaFile }) as? TelegramMediaFile, maybeFile.isVideo, let _ = self.context.account.postbox.mediaBox.completedResourcePath(maybeFile.resource, pathExtension: nil) {
|
||||
messageFile = maybeFile
|
||||
@ -3350,7 +3388,7 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
messageFile = nil
|
||||
}
|
||||
|
||||
let renderer = DrawingMessageRenderer(context: self.context, messages: messages, parentView: self.view)
|
||||
let renderer = DrawingMessageRenderer(context: self.context, messages: messages, parentView: self.view, isGift: isGift)
|
||||
renderer.render(completion: { result in
|
||||
if case .draft = subject, let existingEntityView = self.entitiesView.getView(where: { entityView in
|
||||
if let stickerEntityView = entityView as? DrawingStickerEntityView, case .message = (stickerEntityView.entity as! DrawingStickerEntity).content {
|
||||
@ -3366,12 +3404,25 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
messageEntity.overlayRenderImage = result.overlayImage
|
||||
existingEntityView.update(animated: false)
|
||||
} else {
|
||||
let messageEntity = DrawingStickerEntity(content: .message(messageIds, result.size, messageFile, result.mediaFrame?.rect, result.mediaFrame?.cornerRadius))
|
||||
var content: DrawingStickerEntity.Content
|
||||
var position: CGPoint
|
||||
switch effectiveSubject {
|
||||
case let .message(messageIds):
|
||||
content = .message(messageIds, result.size, messageFile, result.mediaFrame?.rect, result.mediaFrame?.cornerRadius)
|
||||
position = CGPoint(x: storyDimensions.width / 2.0 - 54.0, y: storyDimensions.height / 2.0)
|
||||
case let .gift(gift):
|
||||
content = .gift(gift, result.size)
|
||||
position = CGPoint(x: storyDimensions.width / 2.0, y: storyDimensions.height / 2.0)
|
||||
default:
|
||||
fatalError()
|
||||
}
|
||||
|
||||
let messageEntity = DrawingStickerEntity(content: content)
|
||||
messageEntity.renderImage = result.dayImage
|
||||
messageEntity.secondaryRenderImage = result.nightImage
|
||||
messageEntity.overlayRenderImage = result.overlayImage
|
||||
messageEntity.referenceDrawingSize = storyDimensions
|
||||
messageEntity.position = CGPoint(x: storyDimensions.width / 2.0 - 54.0, y: storyDimensions.height / 2.0)
|
||||
messageEntity.position = position
|
||||
|
||||
let fraction = max(result.size.width, result.size.height) / 353.0
|
||||
messageEntity.scale = min(6.0, 3.3 * fraction)
|
||||
@ -3386,10 +3437,10 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
self.readyValue.set(.single(true))
|
||||
})
|
||||
})
|
||||
} else if case let .sticker(_, emoji) = effectiveSubject {
|
||||
controller.stickerSelectedEmoji = emoji
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
self.gradientColorsDisposable = mediaEditor.gradientColors.start(next: { [weak self] colors in
|
||||
if let self, let colors {
|
||||
let gradientImage = generateGradientImage(size: CGSize(width: 5.0, height: 640.0), colors: colors.array, locations: [0.0, 1.0])
|
||||
@ -3749,10 +3800,12 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
}
|
||||
|
||||
private var canEnhance: Bool {
|
||||
if case .message = self.subject {
|
||||
switch self.subject {
|
||||
case .message, .gift:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private var enhanceInitialTranslation: Float?
|
||||
@ -3856,8 +3909,13 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
guard !self.isCollageTimelineOpen else {
|
||||
return
|
||||
}
|
||||
if gestureRecognizer.numberOfTouches == 2, let subject = self.subject, case .message = subject, !self.entitiesView.hasSelection {
|
||||
return
|
||||
if gestureRecognizer.numberOfTouches == 2, let subject = self.subject, !self.entitiesView.hasSelection {
|
||||
switch subject {
|
||||
case .message, .gift:
|
||||
return
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
let currentTimestamp = CACurrentMediaTime()
|
||||
if let previousPanTimestamp = self.previousPanTimestamp, currentTimestamp - previousPanTimestamp < 0.016, case .changed = gestureRecognizer.state {
|
||||
@ -3871,8 +3929,13 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
guard !self.isCollageTimelineOpen else {
|
||||
return
|
||||
}
|
||||
if gestureRecognizer.numberOfTouches == 2, let subject = self.subject, case .message = subject, !self.entitiesView.hasSelection {
|
||||
return
|
||||
if gestureRecognizer.numberOfTouches == 2, let subject = self.subject, !self.entitiesView.hasSelection {
|
||||
switch subject {
|
||||
case .message, .gift:
|
||||
return
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
let currentTimestamp = CACurrentMediaTime()
|
||||
if let previousPinchTimestamp = self.previousPinchTimestamp, currentTimestamp - previousPinchTimestamp < 0.016, case .changed = gestureRecognizer.state {
|
||||
@ -3886,8 +3949,13 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
guard !self.isCollageTimelineOpen else {
|
||||
return
|
||||
}
|
||||
if gestureRecognizer.numberOfTouches == 2, let subject = self.subject, case .message = subject, !self.entitiesView.hasSelection {
|
||||
return
|
||||
if gestureRecognizer.numberOfTouches == 2, let subject = self.subject, !self.entitiesView.hasSelection {
|
||||
switch subject {
|
||||
case .message, .gift:
|
||||
return
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
let currentTimestamp = CACurrentMediaTime()
|
||||
if let previousRotateTimestamp = self.previousRotateTimestamp, currentTimestamp - previousRotateTimestamp < 0.016, case .changed = gestureRecognizer.state {
|
||||
@ -4072,7 +4140,7 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
var animateIn = false
|
||||
if let subject {
|
||||
switch subject {
|
||||
case .empty, .message, .sticker, .image:
|
||||
case .empty, .message, .gift, .sticker, .image:
|
||||
animateIn = true
|
||||
default:
|
||||
break
|
||||
@ -5924,6 +5992,7 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
case asset(PHAsset)
|
||||
case draft(MediaEditorDraft, Int64?)
|
||||
case message([MessageId])
|
||||
case gift(StarGift.UniqueGift)
|
||||
case sticker(TelegramMediaFile, [String])
|
||||
|
||||
var dimensions: PixelDimensions {
|
||||
@ -5936,7 +6005,7 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
return PixelDimensions(width: Int32(asset.pixelWidth), height: Int32(asset.pixelHeight))
|
||||
case let .draft(draft, _):
|
||||
return draft.dimensions
|
||||
case .message, .sticker, .videoCollage:
|
||||
case .message, .gift, .sticker, .videoCollage:
|
||||
return PixelDimensions(width: 1080, height: 1920)
|
||||
}
|
||||
}
|
||||
@ -5960,6 +6029,8 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
return .draft(draft)
|
||||
case let .message(messageIds):
|
||||
return .message(messageIds.first!)
|
||||
case let .gift(gift):
|
||||
return .gift(gift)
|
||||
case let .sticker(sticker, _):
|
||||
return .sticker(sticker)
|
||||
}
|
||||
@ -5985,6 +6056,8 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
return draft.isVideo
|
||||
case .message:
|
||||
return false
|
||||
case .gift:
|
||||
return false
|
||||
case .sticker:
|
||||
return false
|
||||
}
|
||||
@ -6189,9 +6262,12 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
if self.isEditingStory {
|
||||
needsAudioSession = true
|
||||
}
|
||||
if case .message = subject {
|
||||
switch subject {
|
||||
case .message, .gift:
|
||||
needsAudioSession = true
|
||||
checkPostingAvailability = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
if needsAudioSession {
|
||||
self.audioSessionDisposable = self.context.sharedContext.mediaManager.audioSession.push(audioSessionType: .record(speaker: false, video: true, withOthers: true), activate: { _ in
|
||||
@ -7195,9 +7271,16 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
firstFrame = .single((UIImage(), nil))
|
||||
}
|
||||
}
|
||||
case let .message(messages):
|
||||
case .message, .gift:
|
||||
let peerId: EnginePeer.Id
|
||||
if case let .message(messageIds) = subject {
|
||||
peerId = messageIds.first!.peerId
|
||||
} else {
|
||||
peerId = self.context.account.peerId
|
||||
}
|
||||
|
||||
let isNightTheme = mediaEditor.values.nightTheme
|
||||
let wallpaper = getChatWallpaperImage(context: self.context, messageId: messages.first!)
|
||||
let wallpaper = getChatWallpaperImage(context: self.context, peerId: peerId)
|
||||
|> map { _, image, nightImage -> UIImage? in
|
||||
if isNightTheme {
|
||||
return nightImage ?? image
|
||||
@ -8055,7 +8138,18 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
||||
}
|
||||
case let .message(messages):
|
||||
let isNightTheme = mediaEditor.values.nightTheme
|
||||
exportSubject = getChatWallpaperImage(context: self.context, messageId: messages.first!)
|
||||
exportSubject = getChatWallpaperImage(context: self.context, peerId: messages.first!.peerId)
|
||||
|> mapToSignal { _, image, nightImage -> Signal<MediaEditorVideoExport.Subject, NoError> in
|
||||
if isNightTheme {
|
||||
let effectiveImage = nightImage ?? image
|
||||
return effectiveImage.flatMap({ .single(.image(image: $0)) }) ?? .complete()
|
||||
} else {
|
||||
return image.flatMap({ .single(.image(image: $0)) }) ?? .complete()
|
||||
}
|
||||
}
|
||||
case .gift:
|
||||
let isNightTheme = mediaEditor.values.nightTheme
|
||||
exportSubject = getChatWallpaperImage(context: self.context, peerId: self.context.account.peerId)
|
||||
|> mapToSignal { _, image, nightImage -> Signal<MediaEditorVideoExport.Subject, NoError> in
|
||||
if isNightTheme {
|
||||
let effectiveImage = nightImage ?? image
|
||||
|
@ -3342,14 +3342,14 @@ final class StoryItemSetContainerSendMessage {
|
||||
useGesturePosition = true
|
||||
let action = { [weak self, weak view, weak controller] in
|
||||
let _ = ((context.engine.messages.getMessagesLoadIfNecessary([messageId], strategy: .cloud(skipLocal: true))
|
||||
|> mapToSignal { result -> Signal<Message?, GetMessagesError> in
|
||||
|> mapToSignal { result -> Signal<Message?, GetMessagesError> in
|
||||
if case let .result(messages) = result {
|
||||
return .single(messages.first)
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
})
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self, weak view, weak controller] message in
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self, weak view, weak controller] message in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
@ -3365,7 +3365,7 @@ final class StoryItemSetContainerSendMessage {
|
||||
switch error {
|
||||
case .privateChannel:
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: messageId.peerId))
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self, weak view] peer in
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self, weak view] peer in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
@ -3416,6 +3416,31 @@ final class StoryItemSetContainerSendMessage {
|
||||
}))
|
||||
case .weather:
|
||||
return
|
||||
case let .starGift(_, slug):
|
||||
useGesturePosition = true
|
||||
let action = {
|
||||
let _ = openUserGeneratedUrl(context: component.context, peerId: nil, url: "https://t.me/nft/\(slug)", concealed: false, skipUrlAuth: false, skipConcealedAlert: false, forceDark: true, present: { [weak controller] c in
|
||||
controller?.present(c, in: .window(.root))
|
||||
}, openResolved: { [weak self, weak view] resolved in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
self.openResolved(view: view, result: resolved, forceExternal: false, concealed: false)
|
||||
}, alertDisplayUpdated: { [weak self, weak view] alertController in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
self.statusController = alertController
|
||||
view.updateIsProgressPaused()
|
||||
})
|
||||
}
|
||||
if immediate {
|
||||
action()
|
||||
return
|
||||
}
|
||||
actions.append(ContextMenuAction(content: .textWithIcon(title: updatedPresentationData.initial.strings.Story_ViewGift, icon: generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: .white)), action: {
|
||||
action()
|
||||
}))
|
||||
}
|
||||
|
||||
self.selectedMediaArea = mediaArea
|
||||
|
@ -27,10 +27,21 @@ import StoryContainerScreen
|
||||
import SaveToCameraRoll
|
||||
import MediaEditorScreen
|
||||
|
||||
enum StorySharingSubject {
|
||||
case messages([Message])
|
||||
case gift(StarGift.UniqueGift)
|
||||
}
|
||||
|
||||
extension ChatControllerImpl {
|
||||
func openStorySharing(messages: [Message]) {
|
||||
func openStorySharing(subject: StorySharingSubject) {
|
||||
let context = self.context
|
||||
let subject: Signal<MediaEditorScreenImpl.Subject?, NoError> = .single(.message(messages.map { $0.id }))
|
||||
let editorSubject: Signal<MediaEditorScreenImpl.Subject?, NoError>
|
||||
switch subject {
|
||||
case let .messages(messages):
|
||||
editorSubject = .single(.message(messages.map { $0.id }))
|
||||
case let .gift(gift):
|
||||
editorSubject = .single(.gift(gift))
|
||||
}
|
||||
|
||||
let externalState = MediaEditorTransitionOutExternalState(
|
||||
storyTarget: nil,
|
||||
@ -42,7 +53,7 @@ extension ChatControllerImpl {
|
||||
let controller = MediaEditorScreenImpl(
|
||||
context: context,
|
||||
mode: .storyEditor,
|
||||
subject: subject,
|
||||
subject: editorSubject,
|
||||
transitionIn: nil,
|
||||
transitionOut: { _, _ in
|
||||
return nil
|
||||
|
@ -1198,7 +1198,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
strongSelf.push(controller)
|
||||
return true
|
||||
case .starGift, .starGiftUnique:
|
||||
let controller = strongSelf.context.sharedContext.makeGiftViewScreen(context: strongSelf.context, message: EngineMessage(message))
|
||||
let controller = strongSelf.context.sharedContext.makeGiftViewScreen(context: strongSelf.context, message: EngineMessage(message), shareStory: { [weak self] in
|
||||
if let self, case let .starGiftUnique(gift, _, _, _, _, _, _) = action.action, case let .unique(uniqueGift) = gift {
|
||||
Queue.mainQueue().after(0.15) {
|
||||
self.openStorySharing(subject: .gift(uniqueGift))
|
||||
}
|
||||
}
|
||||
})
|
||||
strongSelf.push(controller)
|
||||
return true
|
||||
case .giftStars:
|
||||
|
@ -134,7 +134,7 @@ extension ChatControllerImpl {
|
||||
return
|
||||
}
|
||||
Queue.mainQueue().after(0.15) {
|
||||
self.openStorySharing(messages: messages)
|
||||
self.openStorySharing(subject: .messages(messages))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1211,6 +1211,13 @@ func openResolvedUrlImpl(
|
||||
present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
}
|
||||
})
|
||||
case let .collectible(gift):
|
||||
if let gift {
|
||||
let controller = context.sharedContext.makeGiftViewScreen(context: context, gift: gift, shareStory: nil)
|
||||
navigationController?.pushViewController(controller)
|
||||
} else {
|
||||
present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
}
|
||||
case let .messageLink(link):
|
||||
if let link {
|
||||
if let navigationController = navigationController {
|
||||
|
@ -655,6 +655,22 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
||||
convertedUrl = "https://t.me/addtheme/\(parameter)"
|
||||
}
|
||||
}
|
||||
} else if parsedUrl.host == "nft" {
|
||||
if let components = URLComponents(string: "/?" + query) {
|
||||
var slug: String?
|
||||
if let queryItems = components.queryItems {
|
||||
for queryItem in queryItems {
|
||||
if let value = queryItem.value {
|
||||
if queryItem.name == "slug" {
|
||||
slug = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let slug {
|
||||
convertedUrl = "https://t.me/nft/\(slug)"
|
||||
}
|
||||
}
|
||||
} else if parsedUrl.host == "privatepost" {
|
||||
if let components = URLComponents(string: "/?" + query) {
|
||||
var channelId: Int64?
|
||||
|
@ -76,6 +76,7 @@ import StarsIntroScreen
|
||||
import ContentReportScreen
|
||||
import AffiliateProgramSetupScreen
|
||||
import GalleryUI
|
||||
import ShareController
|
||||
|
||||
private final class AccountUserInterfaceInUseContext {
|
||||
let subscribers = Bag<(Bool) -> Void>()
|
||||
@ -2922,8 +2923,12 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
return StarsIntroScreen(context: context)
|
||||
}
|
||||
|
||||
public func makeGiftViewScreen(context: AccountContext, message: EngineMessage) -> ViewController {
|
||||
return GiftViewScreen(context: context, subject: .message(message))
|
||||
public func makeGiftViewScreen(context: AccountContext, message: EngineMessage, shareStory: (() -> Void)?) -> ViewController {
|
||||
return GiftViewScreen(context: context, subject: .message(message), shareStory: shareStory)
|
||||
}
|
||||
|
||||
public func makeGiftViewScreen(context: AccountContext, gift: StarGift.UniqueGift, shareStory: (() -> Void)?) -> ViewController {
|
||||
return GiftViewScreen(context: context, subject: .uniqueGift(gift), shareStory: shareStory)
|
||||
}
|
||||
|
||||
public func makeContentReportScreen(context: AccountContext, subject: ReportContentSubject, forceDark: Bool, present: @escaping (ViewController) -> Void, completion: @escaping () -> Void, requestSelectMessages: ((String, Data, String?) -> Void)?) {
|
||||
@ -2935,6 +2940,13 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
})
|
||||
}
|
||||
|
||||
public func makeShareController(context: AccountContext, subject: ShareControllerSubject, forceExternal: Bool, shareStory: (() -> Void)?, actionCompleted: (() -> Void)?) -> ViewController {
|
||||
let controller = ShareController(context: context, subject: subject, externalShare: forceExternal)
|
||||
controller.shareStory = shareStory
|
||||
controller.actionCompleted = actionCompleted
|
||||
return controller
|
||||
}
|
||||
|
||||
public func makeMiniAppListScreenInitialData(context: AccountContext) -> Signal<MiniAppListScreenInitialData, NoError> {
|
||||
return MiniAppListScreen.initialData(context: context)
|
||||
}
|
||||
|
@ -105,6 +105,7 @@ public enum ParsedInternalUrl {
|
||||
case chatFolder(slug: String)
|
||||
case premiumGiftCode(slug: String)
|
||||
case messageLink(slug: String)
|
||||
case collectible(slug: String)
|
||||
case externalUrl(url: String)
|
||||
}
|
||||
|
||||
@ -523,6 +524,8 @@ public func parseInternalUrl(sharedContext: SharedAccountContext, context: Accou
|
||||
return .wallpaper(parameter)
|
||||
} else if pathComponents[0] == "addtheme" {
|
||||
return .theme(pathComponents[1])
|
||||
} else if pathComponents[0] == "nft" {
|
||||
return .collectible(slug: pathComponents[1])
|
||||
} else if pathComponents[0] == "addlist" || pathComponents[0] == "folder" || pathComponents[0] == "list" {
|
||||
return .chatFolder(slug: pathComponents[1])
|
||||
} else if pathComponents[0] == "boost", pathComponents.count == 2 {
|
||||
@ -1086,6 +1089,11 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
|
||||
}
|
||||
case let .premiumGiftCode(slug):
|
||||
return .single(.result(.premiumGiftCode(slug: slug)))
|
||||
case let .collectible(slug):
|
||||
return .single(.progress) |> then(context.engine.payments.getUniqueStarGift(slug: slug)
|
||||
|> map { gift -> ResolveInternalUrlResult in
|
||||
return .result(.collectible(gift: gift))
|
||||
})
|
||||
case let .messageLink(slug):
|
||||
return .single(.progress)
|
||||
|> then(context.engine.peers.resolveMessageLink(slug: slug)
|
||||
|
Loading…
x
Reference in New Issue
Block a user