Various improvements

This commit is contained in:
Ilya Laktyushin 2025-07-29 17:39:46 +02:00
parent 74cdd1816f
commit 3c87b308f8
20 changed files with 270 additions and 95 deletions

View File

@ -329,8 +329,10 @@ public enum ResolvedUrl {
case collectible(gift: StarGift.UniqueGift?) case collectible(gift: StarGift.UniqueGift?)
case messageLink(link: TelegramResolvedMessageLink?) case messageLink(link: TelegramResolvedMessageLink?)
case stars case stars
case ton
case shareStory(Int64) case shareStory(Int64)
case storyFolder(peerId: PeerId, id: Int64) case storyFolder(peerId: PeerId, id: Int64)
case giftCollection(peerId: PeerId, id: Int64)
} }
public enum ResolveUrlResult { public enum ResolveUrlResult {
@ -669,6 +671,7 @@ public enum PeerInfoControllerMode {
case groupsInCommon case groupsInCommon
case monoforum(EnginePeer.Id) case monoforum(EnginePeer.Id)
case storyAlbum(id: Int64) case storyAlbum(id: Int64)
case giftCollection(id: Int64)
} }
public enum ContactListActionItemInlineIconPosition { public enum ContactListActionItemInlineIconPosition {

View File

@ -1204,6 +1204,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[555358088] = { return Api.WebPage.parse_webPageEmpty($0) } dict[555358088] = { return Api.WebPage.parse_webPageEmpty($0) }
dict[1930545681] = { return Api.WebPage.parse_webPageNotModified($0) } dict[1930545681] = { return Api.WebPage.parse_webPageNotModified($0) }
dict[-1328464313] = { return Api.WebPage.parse_webPagePending($0) } dict[-1328464313] = { return Api.WebPage.parse_webPagePending($0) }
dict[835375875] = { return Api.WebPageAttribute.parse_webPageAttributeStarGiftCollection($0) }
dict[1355547603] = { return Api.WebPageAttribute.parse_webPageAttributeStickerSet($0) } dict[1355547603] = { return Api.WebPageAttribute.parse_webPageAttributeStickerSet($0) }
dict[781501415] = { return Api.WebPageAttribute.parse_webPageAttributeStory($0) } dict[781501415] = { return Api.WebPageAttribute.parse_webPageAttributeStory($0) }
dict[1421174295] = { return Api.WebPageAttribute.parse_webPageAttributeTheme($0) } dict[1421174295] = { return Api.WebPageAttribute.parse_webPageAttributeTheme($0) }

View File

@ -1,5 +1,6 @@
public extension Api { public extension Api {
indirect enum WebPageAttribute: TypeConstructorDescription { indirect enum WebPageAttribute: TypeConstructorDescription {
case webPageAttributeStarGiftCollection(icons: [Api.Document])
case webPageAttributeStickerSet(flags: Int32, stickers: [Api.Document]) case webPageAttributeStickerSet(flags: Int32, stickers: [Api.Document])
case webPageAttributeStory(flags: Int32, peer: Api.Peer, id: Int32, story: Api.StoryItem?) case webPageAttributeStory(flags: Int32, peer: Api.Peer, id: Int32, story: Api.StoryItem?)
case webPageAttributeTheme(flags: Int32, documents: [Api.Document]?, settings: Api.ThemeSettings?) case webPageAttributeTheme(flags: Int32, documents: [Api.Document]?, settings: Api.ThemeSettings?)
@ -7,6 +8,16 @@ public extension Api {
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .webPageAttributeStarGiftCollection(let icons):
if boxed {
buffer.appendInt32(835375875)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(icons.count))
for item in icons {
item.serialize(buffer, true)
}
break
case .webPageAttributeStickerSet(let flags, let stickers): case .webPageAttributeStickerSet(let flags, let stickers):
if boxed { if boxed {
buffer.appendInt32(1355547603) buffer.appendInt32(1355547603)
@ -50,6 +61,8 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .webPageAttributeStarGiftCollection(let icons):
return ("webPageAttributeStarGiftCollection", [("icons", icons as Any)])
case .webPageAttributeStickerSet(let flags, let stickers): case .webPageAttributeStickerSet(let flags, let stickers):
return ("webPageAttributeStickerSet", [("flags", flags as Any), ("stickers", stickers as Any)]) return ("webPageAttributeStickerSet", [("flags", flags as Any), ("stickers", stickers as Any)])
case .webPageAttributeStory(let flags, let peer, let id, let story): case .webPageAttributeStory(let flags, let peer, let id, let story):
@ -61,6 +74,19 @@ public extension Api {
} }
} }
public static func parse_webPageAttributeStarGiftCollection(_ reader: BufferReader) -> WebPageAttribute? {
var _1: [Api.Document]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self)
}
let _c1 = _1 != nil
if _c1 {
return Api.WebPageAttribute.webPageAttributeStarGiftCollection(icons: _1!)
}
else {
return nil
}
}
public static func parse_webPageAttributeStickerSet(_ reader: BufferReader) -> WebPageAttribute? { public static func parse_webPageAttributeStickerSet(_ reader: BufferReader) -> WebPageAttribute? {
var _1: Int32? var _1: Int32?
_1 = reader.readInt32() _1 = reader.readInt32()
@ -1328,39 +1354,3 @@ public extension Api.account {
} }
} }
public extension Api.account {
enum Takeout: TypeConstructorDescription {
case takeout(id: Int64)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .takeout(let id):
if boxed {
buffer.appendInt32(1304052993)
}
serializeInt64(id, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .takeout(let id):
return ("takeout", [("id", id as Any)])
}
}
public static func parse_takeout(_ reader: BufferReader) -> Takeout? {
var _1: Int64?
_1 = reader.readInt64()
let _c1 = _1 != nil
if _c1 {
return Api.account.Takeout.takeout(id: _1!)
}
else {
return nil
}
}
}
}

View File

@ -1,3 +1,39 @@
public extension Api.account {
enum Takeout: TypeConstructorDescription {
case takeout(id: Int64)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .takeout(let id):
if boxed {
buffer.appendInt32(1304052993)
}
serializeInt64(id, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .takeout(let id):
return ("takeout", [("id", id as Any)])
}
}
public static func parse_takeout(_ reader: BufferReader) -> Takeout? {
var _1: Int64?
_1 = reader.readInt64()
let _c1 = _1 != nil
if _c1 {
return Api.account.Takeout.takeout(id: _1!)
}
else {
return nil
}
}
}
}
public extension Api.account { public extension Api.account {
enum Themes: TypeConstructorDescription { enum Themes: TypeConstructorDescription {
case themes(hash: Int64, themes: [Api.Theme]) case themes(hash: Int64, themes: [Api.Theme])

View File

@ -28,6 +28,10 @@ func telegramMediaWebpageAttributeFromApiWebpageAttribute(_ attribute: Api.WebPa
return .starGift(TelegramMediaWebpageStarGiftAttribute(gift: starGift)) return .starGift(TelegramMediaWebpageStarGiftAttribute(gift: starGift))
} }
return nil return nil
case let .webPageAttributeStarGiftCollection(icons):
var files: [TelegramMediaFile] = []
files = icons.compactMap { telegramMediaFileFromApiDocument($0, altDocuments: []) }
return .giftCollection(TelegramMediaWebpageGiftCollectionAttribute(files: files))
case .webPageAttributeStory: case .webPageAttributeStory:
return nil return nil
} }

View File

@ -7,6 +7,7 @@ private enum TelegramMediaWebpageAttributeTypes: Int32 {
case theme case theme
case stickerPack case stickerPack
case starGift case starGift
case giftCollection
} }
public enum TelegramMediaWebpageAttribute: PostboxCoding, Equatable { public enum TelegramMediaWebpageAttribute: PostboxCoding, Equatable {
@ -14,33 +15,39 @@ public enum TelegramMediaWebpageAttribute: PostboxCoding, Equatable {
case theme(TelegraMediaWebpageThemeAttribute) case theme(TelegraMediaWebpageThemeAttribute)
case stickerPack(TelegramMediaWebpageStickerPackAttribute) case stickerPack(TelegramMediaWebpageStickerPackAttribute)
case starGift(TelegramMediaWebpageStarGiftAttribute) case starGift(TelegramMediaWebpageStarGiftAttribute)
case giftCollection(TelegramMediaWebpageGiftCollectionAttribute)
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
switch decoder.decodeInt32ForKey("r", orElse: 0) { switch decoder.decodeInt32ForKey("r", orElse: 0) {
case TelegramMediaWebpageAttributeTypes.theme.rawValue: case TelegramMediaWebpageAttributeTypes.theme.rawValue:
self = .theme(decoder.decodeObjectForKey("a", decoder: { TelegraMediaWebpageThemeAttribute(decoder: $0) }) as! TelegraMediaWebpageThemeAttribute) self = .theme(decoder.decodeObjectForKey("a", decoder: { TelegraMediaWebpageThemeAttribute(decoder: $0) }) as! TelegraMediaWebpageThemeAttribute)
case TelegramMediaWebpageAttributeTypes.stickerPack.rawValue: case TelegramMediaWebpageAttributeTypes.stickerPack.rawValue:
self = .stickerPack(decoder.decodeObjectForKey("a", decoder: { TelegramMediaWebpageStickerPackAttribute(decoder: $0) }) as! TelegramMediaWebpageStickerPackAttribute) self = .stickerPack(decoder.decodeObjectForKey("a", decoder: { TelegramMediaWebpageStickerPackAttribute(decoder: $0) }) as! TelegramMediaWebpageStickerPackAttribute)
case TelegramMediaWebpageAttributeTypes.starGift.rawValue: case TelegramMediaWebpageAttributeTypes.starGift.rawValue:
self = .starGift(decoder.decodeObjectForKey("a", decoder: { TelegramMediaWebpageStarGiftAttribute(decoder: $0) }) as! TelegramMediaWebpageStarGiftAttribute) self = .starGift(decoder.decodeObjectForKey("a", decoder: { TelegramMediaWebpageStarGiftAttribute(decoder: $0) }) as! TelegramMediaWebpageStarGiftAttribute)
default: case TelegramMediaWebpageAttributeTypes.giftCollection.rawValue:
self = .unsupported self = .giftCollection(decoder.decodeObjectForKey("a", decoder: { TelegramMediaWebpageGiftCollectionAttribute(decoder: $0) }) as! TelegramMediaWebpageGiftCollectionAttribute)
default:
self = .unsupported
} }
} }
public func encode(_ encoder: PostboxEncoder) { public func encode(_ encoder: PostboxEncoder) {
switch self { switch self {
case .unsupported: case .unsupported:
encoder.encodeInt32(TelegramMediaWebpageAttributeTypes.unsupported.rawValue, forKey: "r") encoder.encodeInt32(TelegramMediaWebpageAttributeTypes.unsupported.rawValue, forKey: "r")
case let .theme(attribute): case let .theme(attribute):
encoder.encodeInt32(TelegramMediaWebpageAttributeTypes.theme.rawValue, forKey: "r") encoder.encodeInt32(TelegramMediaWebpageAttributeTypes.theme.rawValue, forKey: "r")
encoder.encodeObject(attribute, forKey: "a") encoder.encodeObject(attribute, forKey: "a")
case let .stickerPack(attribute): case let .stickerPack(attribute):
encoder.encodeInt32(TelegramMediaWebpageAttributeTypes.stickerPack.rawValue, forKey: "r") encoder.encodeInt32(TelegramMediaWebpageAttributeTypes.stickerPack.rawValue, forKey: "r")
encoder.encodeObject(attribute, forKey: "a") encoder.encodeObject(attribute, forKey: "a")
case let .starGift(attribute): case let .starGift(attribute):
encoder.encodeInt32(TelegramMediaWebpageAttributeTypes.starGift.rawValue, forKey: "r") encoder.encodeInt32(TelegramMediaWebpageAttributeTypes.starGift.rawValue, forKey: "r")
encoder.encodeObject(attribute, forKey: "a") encoder.encodeObject(attribute, forKey: "a")
case let .giftCollection(attribute):
encoder.encodeInt32(TelegramMediaWebpageAttributeTypes.giftCollection.rawValue, forKey: "r")
encoder.encodeObject(attribute, forKey: "a")
} }
} }
} }
@ -159,6 +166,35 @@ public final class TelegramMediaWebpageStarGiftAttribute: PostboxCoding, Equatab
} }
} }
public final class TelegramMediaWebpageGiftCollectionAttribute: PostboxCoding, Equatable {
public static func == (lhs: TelegramMediaWebpageGiftCollectionAttribute, rhs: TelegramMediaWebpageGiftCollectionAttribute) -> Bool {
if lhs.files.count != rhs.files.count {
return false
} else {
for i in 0 ..< lhs.files.count {
if !lhs.files[i].isEqual(to: rhs.files[i]) {
return false
}
}
}
return true
}
public let files: [TelegramMediaFile]
public init(files: [TelegramMediaFile]) {
self.files = files
}
public init(decoder: PostboxDecoder) {
self.files = decoder.decodeObjectArrayForKey("files")
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeObjectArray(self.files, forKey: "files")
}
}
public final class TelegramMediaWebpageLoadedContent: PostboxCoding, Equatable { public final class TelegramMediaWebpageLoadedContent: PostboxCoding, Equatable {
public let url: String public let url: String
public let displayUrl: String public let displayUrl: String

View File

@ -1838,11 +1838,11 @@ private final class ProfileGiftsContextImpl {
return true return true
} }
switch gift.gift { switch gift.gift {
case .generic(let gift): case let .generic(gift):
if gift.id == id { if gift.id == id {
return true return true
} }
case .unique(let uniqueGift): case let .unique(uniqueGift):
if uniqueGift.id == id { if uniqueGift.id == id {
return true return true
} }
@ -1861,11 +1861,11 @@ private final class ProfileGiftsContextImpl {
return true return true
} }
switch gift.gift { switch gift.gift {
case .generic(let gift): case let .generic(gift):
if gift.id == id { if gift.id == id {
return true return true
} }
case .unique(let uniqueGift): case let .unique(uniqueGift):
if uniqueGift.id == id { if uniqueGift.id == id {
return true return true
} }

View File

@ -11,6 +11,20 @@ public func formatTonAddress(_ address: String) -> String {
return address return address
} }
public func convertStarsToTon(_ amount: StarsAmount, tonUsdRate: Double, starsUsdRate: Double) -> Int64 {
let usdRate = starsUsdRate / 1000.0 / 100.0
let usdValue = Double(amount.value) * usdRate
let tonValue = usdValue / tonUsdRate * 1000000000.0
return Int64(tonValue)
}
public func convertTonToStars(_ amount: StarsAmount, tonUsdRate: Double, starsUsdRate: Double) -> Int64 {
let usdRate = starsUsdRate / 1000.0 / 100.0
let usdValue = Double(amount.value) / 1000000000 * tonUsdRate
let starsValue = usdValue / usdRate
return Int64(starsValue)
}
public func formatTonUsdValue(_ value: Int64, divide: Bool = true, rate: Double = 1.0, dateTimeFormat: PresentationDateTimeFormat) -> String { public func formatTonUsdValue(_ value: Int64, divide: Bool = true, rate: Double = 1.0, dateTimeFormat: PresentationDateTimeFormat) -> String {
let decimalSeparator = dateTimeFormat.decimalSeparator let decimalSeparator = dateTimeFormat.decimalSeparator
let normalizedValue: Double = divide ? Double(value) / 1000000000 : Double(value) let normalizedValue: Double = divide ? Double(value) / 1000000000 : Double(value)

View File

@ -476,6 +476,9 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
entities = nil entities = nil
case "telegram_call": case "telegram_call":
actionTitle = item.presentationData.strings.Chat_ViewGroupCall actionTitle = item.presentationData.strings.Chat_ViewGroupCall
case "telegram_collection":
//TODO:localize
actionTitle = "VIEW COLLECTION"
default: default:
break break
} }
@ -484,6 +487,9 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
if case let .stickerPack(stickerPack) = attribute, !stickerPack.files.isEmpty { if case let .stickerPack(stickerPack) = attribute, !stickerPack.files.isEmpty {
mediaAndFlags = (stickerPack.files, [.preferMediaInline, .stickerPack]) mediaAndFlags = (stickerPack.files, [.preferMediaInline, .stickerPack])
break break
} else if case let .giftCollection(giftCollection) = attribute, !giftCollection.files.isEmpty {
mediaAndFlags = (giftCollection.files, [.preferMediaInline, .stickerPack])
break
} }
} }

View File

@ -1454,10 +1454,14 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
break break
case .stars: case .stars:
break break
case .ton:
break
case .shareStory: case .shareStory:
break break
case .storyFolder: case .storyFolder:
break break
case .giftCollection:
break
} }
} }
})) }))

View File

@ -843,9 +843,9 @@ private final class GiftViewSheetContent: CombinedComponent {
} }
switch self.subject { switch self.subject {
case let .profileGift(peerId, currentSubject): case let .profileGift(peerId, currentSubject):
self.subject = .profileGift(peerId, currentSubject.withGift(.unique(gift.withResellAmounts(nil)))) self.subject = .profileGift(peerId, currentSubject.withGift(.unique(gift.withResellAmounts(nil).withResellForTonOnly(false))))
case let .uniqueGift(_, recipientPeerId): case let .uniqueGift(_, recipientPeerId):
self.subject = .uniqueGift(gift.withResellAmounts(nil), recipientPeerId) self.subject = .uniqueGift(gift.withResellAmounts(nil).withResellForTonOnly(false), recipientPeerId)
default: default:
break break
} }
@ -919,9 +919,9 @@ private final class GiftViewSheetContent: CombinedComponent {
switch self.subject { switch self.subject {
case let .profileGift(peerId, currentSubject): case let .profileGift(peerId, currentSubject):
self.subject = .profileGift(peerId, currentSubject.withGift(.unique(gift.withResellAmounts([price])))) self.subject = .profileGift(peerId, currentSubject.withGift(.unique(gift.withResellAmounts([price]).withResellForTonOnly(price.currency == .ton))))
case let .uniqueGift(_, recipientPeerId): case let .uniqueGift(_, recipientPeerId):
self.subject = .uniqueGift(gift.withResellAmounts([price]), recipientPeerId) self.subject = .uniqueGift(gift.withResellAmounts([price]).withResellForTonOnly(price.currency == .ton), recipientPeerId)
default: default:
break break
} }

View File

@ -528,6 +528,7 @@ private final class PeerInfoPendingPane {
chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>,
sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?, sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?,
initialStoryFolderId: Int64?, initialStoryFolderId: Int64?,
initialGiftCollectionId: Int64?,
key: PeerInfoPaneKey, key: PeerInfoPaneKey,
hasBecomeReady: @escaping (PeerInfoPaneKey) -> Void, hasBecomeReady: @escaping (PeerInfoPaneKey) -> Void,
parentController: ViewController?, parentController: ViewController?,
@ -577,7 +578,7 @@ private final class PeerInfoPendingPane {
} }
} }
} }
paneNode = PeerInfoGiftsPaneNode(context: context, peerId: peerId, chatControllerInteraction: chatControllerInteraction, profileGiftsCollections: data.profileGiftsCollectionsContext!, profileGifts: data.profileGiftsContext!, canManage: canManage, canGift: canGift) paneNode = PeerInfoGiftsPaneNode(context: context, peerId: peerId, chatControllerInteraction: chatControllerInteraction, profileGiftsCollections: data.profileGiftsCollectionsContext!, profileGifts: data.profileGiftsContext!, canManage: canManage, canGift: canGift, initialGiftCollectionId: initialGiftCollectionId)
case .stories, .storyArchive, .botPreview: case .stories, .storyArchive, .botPreview:
var canManage = false var canManage = false
if let peer = data.peer { if let peer = data.peer {
@ -730,6 +731,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
private var pendingPanes: [PeerInfoPaneKey: PeerInfoPendingPane] = [:] private var pendingPanes: [PeerInfoPaneKey: PeerInfoPendingPane] = [:]
private var shouldFadeIn = false private var shouldFadeIn = false
private var initialStoryFolderId: Int64? private var initialStoryFolderId: Int64?
private var initialGiftCollectionId: Int64?
private var transitionFraction: CGFloat = 0.0 private var transitionFraction: CGFloat = 0.0
@ -755,7 +757,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
private let initialPaneKey: PeerInfoPaneKey? private let initialPaneKey: PeerInfoPaneKey?
init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: PeerId, chatLocation: ChatLocation, sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, isMediaOnly: Bool, initialPaneKey: PeerInfoPaneKey?, initialStoryFolderId: Int64?) { init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: PeerId, chatLocation: ChatLocation, sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, isMediaOnly: Bool, initialPaneKey: PeerInfoPaneKey?, initialStoryFolderId: Int64?, initialGiftCollectionId: Int64?) {
self.context = context self.context = context
self.updatedPresentationData = updatedPresentationData self.updatedPresentationData = updatedPresentationData
self.peerId = peerId self.peerId = peerId
@ -765,6 +767,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
self.isMediaOnly = isMediaOnly self.isMediaOnly = isMediaOnly
self.initialPaneKey = initialPaneKey self.initialPaneKey = initialPaneKey
self.initialStoryFolderId = initialStoryFolderId self.initialStoryFolderId = initialStoryFolderId
self.initialGiftCollectionId = initialGiftCollectionId
self.additionalBackgroundNode = ASDisplayNode() self.additionalBackgroundNode = ASDisplayNode()
@ -1103,12 +1106,19 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
if self.pendingPanes[key] == nil, let data { if self.pendingPanes[key] == nil, let data {
var leftScope = false var leftScope = false
var initialStoryFolderId: Int64? var initialStoryFolderId: Int64?
var initialGiftCollectionId: Int64?
if case .stories = key { if case .stories = key {
if let initialStoryFolderIdValue = self.initialStoryFolderId { if let initialStoryFolderIdValue = self.initialStoryFolderId {
self.initialStoryFolderId = nil self.initialStoryFolderId = nil
initialStoryFolderId = initialStoryFolderIdValue initialStoryFolderId = initialStoryFolderIdValue
} }
} }
if case .gifts = key {
if let initialGiftCollectionIdValue = self.initialGiftCollectionId {
self.initialGiftCollectionId = nil
initialGiftCollectionId = initialGiftCollectionIdValue
}
}
let pane = PeerInfoPendingPane( let pane = PeerInfoPendingPane(
context: self.context, context: self.context,
updatedPresentationData: self.updatedPresentationData, updatedPresentationData: self.updatedPresentationData,
@ -1128,6 +1138,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
chatLocationContextHolder: self.chatLocationContextHolder, chatLocationContextHolder: self.chatLocationContextHolder,
sharedMediaFromForumTopic: self.sharedMediaFromForumTopic, sharedMediaFromForumTopic: self.sharedMediaFromForumTopic,
initialStoryFolderId: initialStoryFolderId, initialStoryFolderId: initialStoryFolderId,
initialGiftCollectionId: initialGiftCollectionId,
key: key, key: key,
hasBecomeReady: { [weak self] key in hasBecomeReady: { [weak self] key in
let apply: () -> Void = { let apply: () -> Void = {

View File

@ -2908,6 +2908,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
private let chatLocation: ChatLocation private let chatLocation: ChatLocation
private let chatLocationContextHolder: Atomic<ChatLocationContextHolder?> private let chatLocationContextHolder: Atomic<ChatLocationContextHolder?>
private let switchToStoryFolder: Int64? private let switchToStoryFolder: Int64?
private let switchToGiftCollection: Int64?
private let sharedMediaFromForumTopic: (EnginePeer.Id, Int64)? private let sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?
let isSettings: Bool let isSettings: Bool
@ -3032,7 +3033,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
} }
private var didSetReady = false private var didSetReady = false
init(controller: PeerInfoScreenImpl, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool, isMyProfile: Bool, hintGroupInCommon: PeerId?, requestsContext: PeerInvitationImportersContext?, profileGiftsContext: ProfileGiftsContext?, starsContext: StarsContext?, tonContext: StarsContext?, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, switchToStoryFolder: Int64?, initialPaneKey: PeerInfoPaneKey?, sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?) { init(controller: PeerInfoScreenImpl, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool, isMyProfile: Bool, hintGroupInCommon: PeerId?, requestsContext: PeerInvitationImportersContext?, profileGiftsContext: ProfileGiftsContext?, starsContext: StarsContext?, tonContext: StarsContext?, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, switchToStoryFolder: Int64?, switchToGiftCollection: Int64?, initialPaneKey: PeerInfoPaneKey?, sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?) {
self.controller = controller self.controller = controller
self.context = context self.context = context
self.peerId = peerId self.peerId = peerId
@ -3049,6 +3050,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
self.isMediaOnly = context.account.peerId == peerId && !isSettings && !isMyProfile self.isMediaOnly = context.account.peerId == peerId && !isSettings && !isMyProfile
self.initialExpandPanes = initialPaneKey != nil self.initialExpandPanes = initialPaneKey != nil
self.switchToStoryFolder = switchToStoryFolder self.switchToStoryFolder = switchToStoryFolder
self.switchToGiftCollection = switchToGiftCollection
self.sharedMediaFromForumTopic = sharedMediaFromForumTopic self.sharedMediaFromForumTopic = sharedMediaFromForumTopic
self.scrollNode = ASScrollNode() self.scrollNode = ASScrollNode()
@ -3060,7 +3062,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
forumTopicThreadId = message.threadId forumTopicThreadId = message.threadId
} }
self.headerNode = PeerInfoHeaderNode(context: context, controller: controller, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, isMediaOnly: self.isMediaOnly, isSettings: isSettings, isMyProfile: isMyProfile, forumTopicThreadId: forumTopicThreadId, chatLocation: self.chatLocation) self.headerNode = PeerInfoHeaderNode(context: context, controller: controller, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, isMediaOnly: self.isMediaOnly, isSettings: isSettings, isMyProfile: isMyProfile, forumTopicThreadId: forumTopicThreadId, chatLocation: self.chatLocation)
self.paneContainerNode = PeerInfoPaneContainerNode(context: context, updatedPresentationData: controller.updatedPresentationData, peerId: peerId, chatLocation: chatLocation, sharedMediaFromForumTopic: sharedMediaFromForumTopic, chatLocationContextHolder: chatLocationContextHolder, isMediaOnly: self.isMediaOnly, initialPaneKey: initialPaneKey, initialStoryFolderId: switchToStoryFolder) self.paneContainerNode = PeerInfoPaneContainerNode(context: context, updatedPresentationData: controller.updatedPresentationData, peerId: peerId, chatLocation: chatLocation, sharedMediaFromForumTopic: sharedMediaFromForumTopic, chatLocationContextHolder: chatLocationContextHolder, isMediaOnly: self.isMediaOnly, initialPaneKey: initialPaneKey, initialStoryFolderId: switchToStoryFolder, initialGiftCollectionId: switchToGiftCollection)
super.init() super.init()
@ -11391,12 +11393,16 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
} }
}))) })))
// items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_ShareCollection, icon: { theme in if let addressName = data.peer?.addressName, !addressName.isEmpty {
// return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_ShareCollection, icon: { theme in
// }, action: { [weak self] _, f in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor)
// f(.default) }, action: { [weak self] _, f in
// self?.openShareLink(url: "https://t.me/") f(.default)
// }))) if let pane, case let .collection(id) = pane.currentCollection {
self?.openShareLink(url: "https://t.me/\(addressName)/c/\(id)")
}
})))
}
} }
if canReorder { if canReorder {
@ -13103,6 +13109,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
private let switchToGifts: Bool private let switchToGifts: Bool
private let switchToGroupsInCommon: Bool private let switchToGroupsInCommon: Bool
private let switchToStoryFolder: Int64? private let switchToStoryFolder: Int64?
private let switchToGiftCollection: Int64?
private let sharedMediaFromForumTopic: (EnginePeer.Id, Int64)? private let sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?
let chatLocation: ChatLocation let chatLocation: ChatLocation
private let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil) private let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
@ -13179,7 +13186,8 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
switchToRecommendedChannels: Bool = false, switchToRecommendedChannels: Bool = false,
switchToGifts: Bool = false, switchToGifts: Bool = false,
switchToGroupsInCommon: Bool = false, switchToGroupsInCommon: Bool = false,
switchToStoryFolder: Int64? = nil switchToStoryFolder: Int64? = nil,
switchToGiftCollection: Int64? = nil
) { ) {
self.context = context self.context = context
self.updatedPresentationData = updatedPresentationData self.updatedPresentationData = updatedPresentationData
@ -13198,6 +13206,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
self.switchToGifts = switchToGifts self.switchToGifts = switchToGifts
self.switchToGroupsInCommon = switchToGroupsInCommon self.switchToGroupsInCommon = switchToGroupsInCommon
self.switchToStoryFolder = switchToStoryFolder self.switchToStoryFolder = switchToStoryFolder
self.switchToGiftCollection = switchToGiftCollection
self.sharedMediaFromForumTopic = sharedMediaFromForumTopic self.sharedMediaFromForumTopic = sharedMediaFromForumTopic
if let forumTopicThread = forumTopicThread { if let forumTopicThread = forumTopicThread {
@ -13565,8 +13574,10 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
initialPaneKey = .groupsInCommon initialPaneKey = .groupsInCommon
} else if self.switchToStoryFolder != nil { } else if self.switchToStoryFolder != nil {
initialPaneKey = .stories initialPaneKey = .stories
} else if self .switchToGiftCollection != nil {
initialPaneKey = .gifts
} }
self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, isSettings: self.isSettings, isMyProfile: self.isMyProfile, hintGroupInCommon: self.hintGroupInCommon, requestsContext: self.requestsContext, profileGiftsContext: self.profileGiftsContext, starsContext: self.starsContext, tonContext: self.tonContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, switchToStoryFolder: self.switchToStoryFolder, initialPaneKey: initialPaneKey, sharedMediaFromForumTopic: self.sharedMediaFromForumTopic) self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, isSettings: self.isSettings, isMyProfile: self.isMyProfile, hintGroupInCommon: self.hintGroupInCommon, requestsContext: self.requestsContext, profileGiftsContext: self.profileGiftsContext, starsContext: self.starsContext, tonContext: self.tonContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, switchToStoryFolder: self.switchToStoryFolder, switchToGiftCollection: self.switchToGiftCollection, initialPaneKey: initialPaneKey, sharedMediaFromForumTopic: self.sharedMediaFromForumTopic)
self.controllerNode.accountsAndPeers.set(self.accountsAndPeers.get() |> map { $0.1 }) self.controllerNode.accountsAndPeers.set(self.accountsAndPeers.get() |> map { $0.1 })
self.controllerNode.activeSessionsContextAndCount.set(self.activeSessionsContextAndCount.get()) self.controllerNode.activeSessionsContextAndCount.set(self.activeSessionsContextAndCount.get())
self.cachedDataPromise.set(self.controllerNode.cachedDataPromise.get()) self.cachedDataPromise.set(self.controllerNode.cachedDataPromise.get())

View File

@ -80,6 +80,8 @@ final class GiftsListView: UIView {
private var selectedItemsMap: [AnyHashable: ProfileGiftsContext.State.StarGift] = [:] private var selectedItemsMap: [AnyHashable: ProfileGiftsContext.State.StarGift] = [:]
var selectionUpdated: () -> Void = { } var selectionUpdated: () -> Void = { }
var displayUnpinScreen: ((ProfileGiftsContext.State.StarGift, (() -> Void)?) -> Void)?
var selectedItems: [ProfileGiftsContext.State.StarGift] { var selectedItems: [ProfileGiftsContext.State.StarGift] {
var gifts: [ProfileGiftsContext.State.StarGift] = [] var gifts: [ProfileGiftsContext.State.StarGift] = []
var existingIds = Set<AnyHashable>() var existingIds = Set<AnyHashable>()
@ -645,9 +647,9 @@ final class GiftsListView: UIView {
} }
if let reference = product.reference { if let reference = product.reference {
if pinnedToTop && self.pinnedReferences.count >= self.maxPinnedCount { if pinnedToTop && self.pinnedReferences.count >= self.maxPinnedCount {
// self.displayUnpinScreen(gift: product, completion: { self.displayUnpinScreen?(product, {
dismissImpl?() dismissImpl?()
// }) })
return false return false
} }
self.profileGifts.updateStarGiftPinnedToTop(reference: reference, pinnedToTop: pinnedToTop) self.profileGifts.updateStarGiftPinnedToTop(reference: reference, pinnedToTop: pinnedToTop)

View File

@ -70,6 +70,8 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
private let profileGifts: ProfileGiftsContext private let profileGifts: ProfileGiftsContext
private let canManage: Bool private let canManage: Bool
private let canGift: Bool private let canGift: Bool
private let initialGiftCollectionId: Int64?
private var resultsAreEmpty = false private var resultsAreEmpty = false
private let chatControllerInteraction: ChatControllerInteraction private let chatControllerInteraction: ChatControllerInteraction
@ -130,7 +132,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
private let collectionsMaxCount: Int private let collectionsMaxCount: Int
public init(context: AccountContext, peerId: PeerId, chatControllerInteraction: ChatControllerInteraction, profileGiftsCollections: ProfileGiftsCollectionsContext, profileGifts: ProfileGiftsContext, canManage: Bool, canGift: Bool) { public init(context: AccountContext, peerId: PeerId, chatControllerInteraction: ChatControllerInteraction, profileGiftsCollections: ProfileGiftsCollectionsContext, profileGifts: ProfileGiftsContext, canManage: Bool, canGift: Bool, initialGiftCollectionId: Int64?) {
self.context = context self.context = context
self.peerId = peerId self.peerId = peerId
self.chatControllerInteraction = chatControllerInteraction self.chatControllerInteraction = chatControllerInteraction
@ -138,6 +140,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
self.profileGifts = profileGifts self.profileGifts = profileGifts
self.canManage = canManage self.canManage = canManage
self.canGift = canGift self.canGift = canGift
self.initialGiftCollectionId = initialGiftCollectionId
if let value = context.currentAppConfiguration.with({ $0 }).data?["stargifts_collections_limit"] as? Double { if let value = context.currentAppConfiguration.with({ $0 }).data?["stargifts_collections_limit"] as? Double {
self.collectionsMaxCount = Int(value) self.collectionsMaxCount = Int(value)
@ -150,6 +153,12 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
self.giftsListView = GiftsListView(context: context, peerId: peerId, profileGifts: profileGifts, giftsCollections: profileGiftsCollections, canSelect: false) self.giftsListView = GiftsListView(context: context, peerId: peerId, profileGifts: profileGifts, giftsCollections: profileGiftsCollections, canSelect: false)
super.init() super.init()
self.addSubnode(self.backgroundNode)
self.addSubnode(self.scrollNode)
self.statusPromise.set(self.giftsListView.status)
self.ready.set(self.giftsListView.isReady)
self.giftsListView.onContentUpdated = { [weak self] in self.giftsListView.onContentUpdated = { [weak self] in
guard let self else { guard let self else {
@ -159,19 +168,18 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
self.update(size: params.size, topInset: params.topInset, sideInset: params.sideInset, bottomInset: params.bottomInset, deviceMetrics: params.deviceMetrics, visibleHeight: params.visibleHeight, isScrollingLockedAtTop: params.isScrollingLockedAtTop, expandProgress: params.expandProgress, navigationHeight: params.navigationHeight, presentationData: params.presentationData, synchronous: true, transition: .immediate) self.update(size: params.size, topInset: params.topInset, sideInset: params.sideInset, bottomInset: params.bottomInset, deviceMetrics: params.deviceMetrics, visibleHeight: params.visibleHeight, isScrollingLockedAtTop: params.isScrollingLockedAtTop, expandProgress: params.expandProgress, navigationHeight: params.navigationHeight, presentationData: params.presentationData, synchronous: true, transition: .immediate)
} }
} }
self.addSubnode(self.backgroundNode)
self.addSubnode(self.scrollNode)
self.statusPromise.set(self.giftsListView.status)
self.ready.set(self.giftsListView.isReady)
self.giftsListView.contextAction = { [weak self] gift, view, gesture in self.giftsListView.contextAction = { [weak self] gift, view, gesture in
guard let self else { guard let self else {
return return
} }
self.contextAction(gift: gift, view: view, gesture: gesture) self.contextAction(gift: gift, view: view, gesture: gesture)
} }
self.giftsListView.displayUnpinScreen = { [weak self] gift, completion in
guard let self else {
return
}
self.displayUnpinScreen(gift: gift, completion: completion)
}
self.collectionsDisposable = (profileGiftsCollections.state self.collectionsDisposable = (profileGiftsCollections.state
|> deliverOnMainQueue).start(next: { [weak self] state in |> deliverOnMainQueue).start(next: { [weak self] state in
@ -181,6 +189,10 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
self.collections = state.collections self.collections = state.collections
self.updateScrolling(transition: .easeInOut(duration: 0.2)) self.updateScrolling(transition: .easeInOut(duration: 0.2))
}) })
if let initialGiftCollectionId {
self.setCurrentCollection(collection: .collection(Int32(initialGiftCollectionId)))
}
} }
deinit { deinit {
@ -435,13 +447,19 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
self.update(size: params.size, topInset: params.topInset, sideInset: params.sideInset, bottomInset: params.bottomInset, deviceMetrics: params.deviceMetrics, visibleHeight: params.visibleHeight, isScrollingLockedAtTop: params.isScrollingLockedAtTop, expandProgress: params.expandProgress, navigationHeight: params.navigationHeight, presentationData: params.presentationData, synchronous: true, transition: .immediate) self.update(size: params.size, topInset: params.topInset, sideInset: params.sideInset, bottomInset: params.bottomInset, deviceMetrics: params.deviceMetrics, visibleHeight: params.visibleHeight, isScrollingLockedAtTop: params.isScrollingLockedAtTop, expandProgress: params.expandProgress, navigationHeight: params.navigationHeight, presentationData: params.presentationData, synchronous: true, transition: .immediate)
} }
} }
self.giftsListView.parentController = self.parentController self.giftsListView.displayUnpinScreen = { [weak self] gift, completion in
guard let self else {
return
}
self.displayUnpinScreen(gift: gift, completion: completion)
}
self.giftsListView.contextAction = { [weak self] gift, view, gesture in self.giftsListView.contextAction = { [weak self] gift, view, gesture in
guard let self else { guard let self else {
return return
} }
self.contextAction(gift: gift, view: view, gesture: gesture) self.contextAction(gift: gift, view: view, gesture: gesture)
} }
self.giftsListView.parentController = self.parentController
self.giftsListView.frame = previousGiftsListView.frame self.giftsListView.frame = previousGiftsListView.frame
self.scrollNode.view.insertSubview(self.giftsListView, aboveSubview: previousGiftsListView) self.scrollNode.view.insertSubview(self.giftsListView, aboveSubview: previousGiftsListView)
@ -494,6 +512,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
} }
}))) })))
// items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_ShareCollection, icon: { theme in // items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_ShareCollection, icon: { theme in
// return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.actionSheet.primaryTextColor) // return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.actionSheet.primaryTextColor)
// }, action: { [weak self] _, f in // }, action: { [weak self] _, f in

View File

@ -627,20 +627,14 @@ private final class SheetContent: CombinedComponent {
} }
if state.currency == .stars { if state.currency == .stars {
if let amount = state.amount, let tonUsdRate = withdrawConfiguration.tonUsdRate, let usdWithdrawRate = withdrawConfiguration.usdWithdrawRate { if let amount = state.amount, let tonUsdRate = withdrawConfiguration.tonUsdRate, let usdWithdrawRate = withdrawConfiguration.usdWithdrawRate {
let usdRate = usdWithdrawRate / 1000.0 / 100.0 state.amount = StarsAmount(value: max(min(convertStarsToTon(amount, tonUsdRate: tonUsdRate, starsUsdRate: usdWithdrawRate), resaleConfiguration.starGiftResaleMaxTonAmount), resaleConfiguration.starGiftResaleMinTonAmount), nanos: 0)
let usdValue = Double(amount.value) * usdRate
let tonValue = usdValue / tonUsdRate * 1000000000.0
state.amount = StarsAmount(value: max(min(Int64(tonValue), resaleConfiguration.starGiftResaleMaxTonAmount), resaleConfiguration.starGiftResaleMinTonAmount), nanos: 0)
} else { } else {
state.amount = StarsAmount(value: 0, nanos: 0) state.amount = StarsAmount(value: 0, nanos: 0)
} }
state.currency = .ton state.currency = .ton
} else { } else {
if let amount = state.amount, let tonUsdRate = withdrawConfiguration.tonUsdRate, let usdWithdrawRate = withdrawConfiguration.usdWithdrawRate { if let amount = state.amount, let tonUsdRate = withdrawConfiguration.tonUsdRate, let usdWithdrawRate = withdrawConfiguration.usdWithdrawRate {
let usdRate = usdWithdrawRate / 1000.0 / 100.0 state.amount = StarsAmount(value: max(min(convertTonToStars(amount, tonUsdRate: tonUsdRate, starsUsdRate: usdWithdrawRate), resaleConfiguration.starGiftResaleMaxStarsAmount), resaleConfiguration.starGiftResaleMinStarsAmount), nanos: 0)
let usdValue = Double(amount.value) / 1000000000 * tonUsdRate
let starsValue = usdValue / usdRate
state.amount = StarsAmount(value: max(min(Int64(starsValue), resaleConfiguration.starGiftResaleMaxStarsAmount), resaleConfiguration.starGiftResaleMinStarsAmount), nanos: 0)
} else { } else {
state.amount = StarsAmount(value: 0, nanos: 0) state.amount = StarsAmount(value: 0, nanos: 0)
} }

View File

@ -883,6 +883,15 @@ func openResolvedUrlImpl(
navigationController.pushViewController(controller, animated: true) navigationController.pushViewController(controller, animated: true)
} }
} }
case .ton:
dismissInput()
if let tonContext = context.tonContext {
let controller = context.sharedContext.makeStarsTransactionsScreen(context: context, starsContext: tonContext)
controller.navigationPresentation = .modal
if let navigationController {
navigationController.pushViewController(controller, animated: true)
}
}
case let .joinVoiceChat(peerId, invite): case let .joinVoiceChat(peerId, invite):
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|> deliverOnMainQueue).start(next: { peer in |> deliverOnMainQueue).start(next: { peer in
@ -1519,5 +1528,26 @@ func openResolvedUrlImpl(
} }
navigationController?.pushViewController(controller) navigationController?.pushViewController(controller)
} }
case let .giftCollection(peerId, id):
Task { @MainActor [weak navigationController] in
guard let peer = await context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)
).get() else {
return
}
guard let controller = context.sharedContext.makePeerInfoController(
context: context,
updatedPresentationData: updatedPresentationData,
peer: peer._asPeer(),
mode: .giftCollection(id: id),
avatarInitiallyExpanded: false,
fromChat: false,
requestsContext: nil
) else {
return
}
navigationController?.pushViewController(controller)
}
} }
} }

View File

@ -1031,6 +1031,8 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
} else { } else {
if parsedUrl.host == "stars" { if parsedUrl.host == "stars" {
handleResolvedUrl(.stars) handleResolvedUrl(.stars)
} else if parsedUrl.host == "ton" {
handleResolvedUrl(.ton)
} else if parsedUrl.host == "importStickers" { } else if parsedUrl.host == "importStickers" {
handleResolvedUrl(.importStickers) handleResolvedUrl(.importStickers)
} else if parsedUrl.host == "settings" { } else if parsedUrl.host == "settings" {

View File

@ -3965,6 +3965,7 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation
var switchToGifts = false var switchToGifts = false
var switchToGroupsInCommon = false var switchToGroupsInCommon = false
var switchToStoryFolder: Int64? var switchToStoryFolder: Int64?
var switchToGiftCollection: Int64?
switch mode { switch mode {
case let .nearbyPeer(distance): case let .nearbyPeer(distance):
@ -3992,10 +3993,12 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation
sharedMediaFromForumTopic = (peerId, peer.id.toInt64()) sharedMediaFromForumTopic = (peerId, peer.id.toInt64())
case let .storyAlbum(id): case let .storyAlbum(id):
switchToStoryFolder = id switchToStoryFolder = id
case let .giftCollection(id):
switchToGiftCollection = id
default: default:
break break
} }
return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nearbyPeerDistance, reactionSourceMessageId: reactionSourceMessageId, callMessages: callMessages, isMyProfile: isMyProfile, hintGroupInCommon: hintGroupInCommon, forumTopicThread: forumTopicThread, sharedMediaFromForumTopic: sharedMediaFromForumTopic, switchToGifts: switchToGifts, switchToGroupsInCommon: switchToGroupsInCommon, switchToStoryFolder: switchToStoryFolder) return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nearbyPeerDistance, reactionSourceMessageId: reactionSourceMessageId, callMessages: callMessages, isMyProfile: isMyProfile, hintGroupInCommon: hintGroupInCommon, forumTopicThread: forumTopicThread, sharedMediaFromForumTopic: sharedMediaFromForumTopic, switchToGifts: switchToGifts, switchToGroupsInCommon: switchToGroupsInCommon, switchToStoryFolder: switchToStoryFolder, switchToGiftCollection: switchToGiftCollection)
} else if peer is TelegramSecretChat { } else if peer is TelegramSecretChat {
return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: []) return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [])
} }

View File

@ -82,6 +82,7 @@ public enum ParsedInternalPeerUrlParameter {
case profile case profile
case referrer(String) case referrer(String)
case storyFolder(Int64) case storyFolder(Int64)
case giftCollection(Int64)
} }
public enum ParsedInternalUrl { public enum ParsedInternalUrl {
@ -603,6 +604,12 @@ public func parseInternalUrl(sharedContext: SharedAccountContext, context: Accou
} else { } else {
return nil return nil
} }
} else if pathComponents.count >= 3 && pathComponents[1] == "c" {
if let collectionId = Int64(pathComponents[2]) {
return .peer(.name(pathComponents[0]), .giftCollection(collectionId))
} else {
return nil
}
} else if pathComponents.count == 4 && pathComponents[0] == "c" { } else if pathComponents.count == 4 && pathComponents[0] == "c" {
if let channelId = Int64(pathComponents[1]), let threadId = Int32(pathComponents[2]), let messageId = Int32(pathComponents[3]), channelId > 0 { if let channelId = Int64(pathComponents[1]), let threadId = Int32(pathComponents[2]), let messageId = Int32(pathComponents[3]), channelId > 0 {
var timecode: Double? var timecode: Double?
@ -946,6 +953,8 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
return .single(.result(.peer(peer._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil)))) return .single(.result(.peer(peer._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil))))
case let .storyFolder(folderId): case let .storyFolder(folderId):
return .single(.result(.storyFolder(peerId: peer.id, id: folderId))) return .single(.result(.storyFolder(peerId: peer.id, id: folderId)))
case let .giftCollection(collectionId):
return .single(.result(.giftCollection(peerId: peer.id, id: collectionId)))
} }
} else { } else {
return .single(.result(.peer(peer._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil)))) return .single(.result(.peer(peer._asPeer(), .chat(textInputState: nil, subject: nil, peekData: nil))))