Various improvements

This commit is contained in:
Ilya Laktyushin 2025-01-21 01:15:01 +04:00
parent c73f24f5f2
commit d6964efa67
32 changed files with 488 additions and 101 deletions

View File

@ -13753,3 +13753,11 @@ Sorry for the inconvenience.";
"Gift.Withdraw.EnterPassword.Title" = "Enter Password";
"Gift.Withdraw.EnterPassword.Text" = "Please enter your Two-Step Verification password to complete this action.";
"Gift.Withdraw.EnterPassword.Done" = "Proceed";
"PeerInfo.Gifts.SortByValue" = "Sort by Value";
"PeerInfo.Gifts.SortByDate" = "Sort by Date";
"PeerInfo.Gifts.Unlimited" = "Unlimited";
"PeerInfo.Gifts.Limited" = "Limited";
"PeerInfo.Gifts.Unique" = "Unique";
"PeerInfo.Gifts.Displayed" = "Displayed";
"PeerInfo.Gifts.Hidden" = "Hidden";

View File

@ -389,8 +389,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1710230755] = { return Api.InputInvoice.parse_inputInvoiceStars($0) }
dict[-122978821] = { return Api.InputMedia.parse_inputMediaContact($0) }
dict[-428884101] = { return Api.InputMedia.parse_inputMediaDice($0) }
dict[1946579745] = { return Api.InputMedia.parse_inputMediaDocument($0) }
dict[-149933938] = { return Api.InputMedia.parse_inputMediaDocumentExternal($0) }
dict[-1468646731] = { return Api.InputMedia.parse_inputMediaDocument($0) }
dict[2006319353] = { return Api.InputMedia.parse_inputMediaDocumentExternal($0) }
dict[-1771768449] = { return Api.InputMedia.parse_inputMediaEmpty($0) }
dict[-750828557] = { return Api.InputMedia.parse_inputMediaGame($0) }
dict[-1759532989] = { return Api.InputMedia.parse_inputMediaGeoLive($0) }
@ -401,7 +401,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-440664550] = { return Api.InputMedia.parse_inputMediaPhotoExternal($0) }
dict[261416433] = { return Api.InputMedia.parse_inputMediaPoll($0) }
dict[-1979852936] = { return Api.InputMedia.parse_inputMediaStory($0) }
dict[-264125395] = { return Api.InputMedia.parse_inputMediaUploadedDocument($0) }
dict[58495792] = { return Api.InputMedia.parse_inputMediaUploadedDocument($0) }
dict[505969924] = { return Api.InputMedia.parse_inputMediaUploadedPhoto($0) }
dict[-1052959727] = { return Api.InputMedia.parse_inputMediaVenue($0) }
dict[-1038383031] = { return Api.InputMedia.parse_inputMediaWebPage($0) }
@ -620,7 +620,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1313731771] = { return Api.MessageFwdHeader.parse_messageFwdHeader($0) }
dict[1882335561] = { return Api.MessageMedia.parse_messageMediaContact($0) }
dict[1065280907] = { return Api.MessageMedia.parse_messageMediaDice($0) }
dict[-608307692] = { return Api.MessageMedia.parse_messageMediaDocument($0) }
dict[1389939929] = { return Api.MessageMedia.parse_messageMediaDocument($0) }
dict[1038967584] = { return Api.MessageMedia.parse_messageMediaEmpty($0) }
dict[-38694904] = { return Api.MessageMedia.parse_messageMediaGame($0) }
dict[1457575028] = { return Api.MessageMedia.parse_messageMediaGeo($0) }

View File

@ -432,8 +432,8 @@ public extension Api {
indirect enum InputMedia: TypeConstructorDescription {
case inputMediaContact(phoneNumber: String, firstName: String, lastName: String, vcard: String)
case inputMediaDice(emoticon: String)
case inputMediaDocument(flags: Int32, id: Api.InputDocument, videoCover: Api.InputPhoto?, ttlSeconds: Int32?, query: String?)
case inputMediaDocumentExternal(flags: Int32, url: String, ttlSeconds: Int32?, videoCover: Api.InputPhoto?)
case inputMediaDocument(flags: Int32, id: Api.InputDocument, videoCover: Api.InputPhoto?, videoTimestamp: Int32?, ttlSeconds: Int32?, query: String?)
case inputMediaDocumentExternal(flags: Int32, url: String, ttlSeconds: Int32?, videoCover: Api.InputPhoto?, videoTimestamp: Int32?)
case inputMediaEmpty
case inputMediaGame(id: Api.InputGame)
case inputMediaGeoLive(flags: Int32, geoPoint: Api.InputGeoPoint, heading: Int32?, period: Int32?, proximityNotificationRadius: Int32?)
@ -444,7 +444,7 @@ public extension Api {
case inputMediaPhotoExternal(flags: Int32, url: String, ttlSeconds: Int32?)
case inputMediaPoll(flags: Int32, poll: Api.Poll, correctAnswers: [Buffer]?, solution: String?, solutionEntities: [Api.MessageEntity]?)
case inputMediaStory(peer: Api.InputPeer, id: Int32)
case inputMediaUploadedDocument(flags: Int32, file: Api.InputFile, thumb: Api.InputFile?, mimeType: String, attributes: [Api.DocumentAttribute], stickers: [Api.InputDocument]?, videoCover: Api.InputPhoto?, ttlSeconds: Int32?)
case inputMediaUploadedDocument(flags: Int32, file: Api.InputFile, thumb: Api.InputFile?, mimeType: String, attributes: [Api.DocumentAttribute], stickers: [Api.InputDocument]?, videoCover: Api.InputPhoto?, videoTimestamp: Int32?, ttlSeconds: Int32?)
case inputMediaUploadedPhoto(flags: Int32, file: Api.InputFile, stickers: [Api.InputDocument]?, ttlSeconds: Int32?)
case inputMediaVenue(geoPoint: Api.InputGeoPoint, title: String, address: String, provider: String, venueId: String, venueType: String)
case inputMediaWebPage(flags: Int32, url: String)
@ -466,24 +466,26 @@ public extension Api {
}
serializeString(emoticon, buffer: buffer, boxed: false)
break
case .inputMediaDocument(let flags, let id, let videoCover, let ttlSeconds, let query):
case .inputMediaDocument(let flags, let id, let videoCover, let videoTimestamp, let ttlSeconds, let query):
if boxed {
buffer.appendInt32(1946579745)
buffer.appendInt32(-1468646731)
}
serializeInt32(flags, buffer: buffer, boxed: false)
id.serialize(buffer, true)
if Int(flags) & Int(1 << 3) != 0 {videoCover!.serialize(buffer, true)}
if Int(flags) & Int(1 << 4) != 0 {serializeInt32(videoTimestamp!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(ttlSeconds!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {serializeString(query!, buffer: buffer, boxed: false)}
break
case .inputMediaDocumentExternal(let flags, let url, let ttlSeconds, let videoCover):
case .inputMediaDocumentExternal(let flags, let url, let ttlSeconds, let videoCover, let videoTimestamp):
if boxed {
buffer.appendInt32(-149933938)
buffer.appendInt32(2006319353)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(url, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(ttlSeconds!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {videoCover!.serialize(buffer, true)}
if Int(flags) & Int(1 << 3) != 0 {serializeInt32(videoTimestamp!, buffer: buffer, boxed: false)}
break
case .inputMediaEmpty:
if boxed {
@ -582,9 +584,9 @@ public extension Api {
peer.serialize(buffer, true)
serializeInt32(id, buffer: buffer, boxed: false)
break
case .inputMediaUploadedDocument(let flags, let file, let thumb, let mimeType, let attributes, let stickers, let videoCover, let ttlSeconds):
case .inputMediaUploadedDocument(let flags, let file, let thumb, let mimeType, let attributes, let stickers, let videoCover, let videoTimestamp, let ttlSeconds):
if boxed {
buffer.appendInt32(-264125395)
buffer.appendInt32(58495792)
}
serializeInt32(flags, buffer: buffer, boxed: false)
file.serialize(buffer, true)
@ -601,6 +603,7 @@ public extension Api {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 6) != 0 {videoCover!.serialize(buffer, true)}
if Int(flags) & Int(1 << 7) != 0 {serializeInt32(videoTimestamp!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(ttlSeconds!, buffer: buffer, boxed: false)}
break
case .inputMediaUploadedPhoto(let flags, let file, let stickers, let ttlSeconds):
@ -643,10 +646,10 @@ public extension Api {
return ("inputMediaContact", [("phoneNumber", phoneNumber as Any), ("firstName", firstName as Any), ("lastName", lastName as Any), ("vcard", vcard as Any)])
case .inputMediaDice(let emoticon):
return ("inputMediaDice", [("emoticon", emoticon as Any)])
case .inputMediaDocument(let flags, let id, let videoCover, let ttlSeconds, let query):
return ("inputMediaDocument", [("flags", flags as Any), ("id", id as Any), ("videoCover", videoCover as Any), ("ttlSeconds", ttlSeconds as Any), ("query", query as Any)])
case .inputMediaDocumentExternal(let flags, let url, let ttlSeconds, let videoCover):
return ("inputMediaDocumentExternal", [("flags", flags as Any), ("url", url as Any), ("ttlSeconds", ttlSeconds as Any), ("videoCover", videoCover as Any)])
case .inputMediaDocument(let flags, let id, let videoCover, let videoTimestamp, let ttlSeconds, let query):
return ("inputMediaDocument", [("flags", flags as Any), ("id", id as Any), ("videoCover", videoCover as Any), ("videoTimestamp", videoTimestamp as Any), ("ttlSeconds", ttlSeconds as Any), ("query", query as Any)])
case .inputMediaDocumentExternal(let flags, let url, let ttlSeconds, let videoCover, let videoTimestamp):
return ("inputMediaDocumentExternal", [("flags", flags as Any), ("url", url as Any), ("ttlSeconds", ttlSeconds as Any), ("videoCover", videoCover as Any), ("videoTimestamp", videoTimestamp as Any)])
case .inputMediaEmpty:
return ("inputMediaEmpty", [])
case .inputMediaGame(let id):
@ -667,8 +670,8 @@ public extension Api {
return ("inputMediaPoll", [("flags", flags as Any), ("poll", poll as Any), ("correctAnswers", correctAnswers as Any), ("solution", solution as Any), ("solutionEntities", solutionEntities as Any)])
case .inputMediaStory(let peer, let id):
return ("inputMediaStory", [("peer", peer as Any), ("id", id as Any)])
case .inputMediaUploadedDocument(let flags, let file, let thumb, let mimeType, let attributes, let stickers, let videoCover, let ttlSeconds):
return ("inputMediaUploadedDocument", [("flags", flags as Any), ("file", file as Any), ("thumb", thumb as Any), ("mimeType", mimeType as Any), ("attributes", attributes as Any), ("stickers", stickers as Any), ("videoCover", videoCover as Any), ("ttlSeconds", ttlSeconds as Any)])
case .inputMediaUploadedDocument(let flags, let file, let thumb, let mimeType, let attributes, let stickers, let videoCover, let videoTimestamp, let ttlSeconds):
return ("inputMediaUploadedDocument", [("flags", flags as Any), ("file", file as Any), ("thumb", thumb as Any), ("mimeType", mimeType as Any), ("attributes", attributes as Any), ("stickers", stickers as Any), ("videoCover", videoCover as Any), ("videoTimestamp", videoTimestamp as Any), ("ttlSeconds", ttlSeconds as Any)])
case .inputMediaUploadedPhoto(let flags, let file, let stickers, let ttlSeconds):
return ("inputMediaUploadedPhoto", [("flags", flags as Any), ("file", file as Any), ("stickers", stickers as Any), ("ttlSeconds", ttlSeconds as Any)])
case .inputMediaVenue(let geoPoint, let title, let address, let provider, let venueId, let venueType):
@ -721,16 +724,19 @@ public extension Api {
_3 = Api.parse(reader, signature: signature) as? Api.InputPhoto
} }
var _4: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_4 = reader.readInt32() }
var _5: String?
if Int(_1!) & Int(1 << 1) != 0 {_5 = parseString(reader) }
if Int(_1!) & Int(1 << 4) != 0 {_4 = reader.readInt32() }
var _5: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_5 = reader.readInt32() }
var _6: String?
if Int(_1!) & Int(1 << 1) != 0 {_6 = parseString(reader) }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 3) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.InputMedia.inputMediaDocument(flags: _1!, id: _2!, videoCover: _3, ttlSeconds: _4, query: _5)
let _c4 = (Int(_1!) & Int(1 << 4) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 1) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.InputMedia.inputMediaDocument(flags: _1!, id: _2!, videoCover: _3, videoTimestamp: _4, ttlSeconds: _5, query: _6)
}
else {
return nil
@ -747,12 +753,15 @@ public extension Api {
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.InputPhoto
} }
var _5: Int32?
if Int(_1!) & Int(1 << 3) != 0 {_5 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.InputMedia.inputMediaDocumentExternal(flags: _1!, url: _2!, ttlSeconds: _3, videoCover: _4)
let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.InputMedia.inputMediaDocumentExternal(flags: _1!, url: _2!, ttlSeconds: _3, videoCover: _4, videoTimestamp: _5)
}
else {
return nil
@ -987,7 +996,9 @@ public extension Api {
_7 = Api.parse(reader, signature: signature) as? Api.InputPhoto
} }
var _8: Int32?
if Int(_1!) & Int(1 << 1) != 0 {_8 = reader.readInt32() }
if Int(_1!) & Int(1 << 7) != 0 {_8 = reader.readInt32() }
var _9: Int32?
if Int(_1!) & Int(1 << 1) != 0 {_9 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil
@ -995,9 +1006,10 @@ public extension Api {
let _c5 = _5 != nil
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
let _c7 = (Int(_1!) & Int(1 << 6) == 0) || _7 != nil
let _c8 = (Int(_1!) & Int(1 << 1) == 0) || _8 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
return Api.InputMedia.inputMediaUploadedDocument(flags: _1!, file: _2!, thumb: _3, mimeType: _4!, attributes: _5!, stickers: _6, videoCover: _7, ttlSeconds: _8)
let _c8 = (Int(_1!) & Int(1 << 7) == 0) || _8 != nil
let _c9 = (Int(_1!) & Int(1 << 1) == 0) || _9 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
return Api.InputMedia.inputMediaUploadedDocument(flags: _1!, file: _2!, thumb: _3, mimeType: _4!, attributes: _5!, stickers: _6, videoCover: _7, videoTimestamp: _8, ttlSeconds: _9)
}
else {
return nil

View File

@ -710,7 +710,7 @@ public extension Api {
indirect enum MessageMedia: TypeConstructorDescription {
case messageMediaContact(phoneNumber: String, firstName: String, lastName: String, vcard: String, userId: Int64)
case messageMediaDice(value: Int32, emoticon: String)
case messageMediaDocument(flags: Int32, document: Api.Document?, altDocuments: [Api.Document]?, videoCover: Api.Photo?, ttlSeconds: Int32?)
case messageMediaDocument(flags: Int32, document: Api.Document?, altDocuments: [Api.Document]?, videoCover: Api.Photo?, videoTimestamp: Int32?, ttlSeconds: Int32?)
case messageMediaEmpty
case messageMediaGame(game: Api.Game)
case messageMediaGeo(geo: Api.GeoPoint)
@ -745,9 +745,9 @@ public extension Api {
serializeInt32(value, buffer: buffer, boxed: false)
serializeString(emoticon, buffer: buffer, boxed: false)
break
case .messageMediaDocument(let flags, let document, let altDocuments, let videoCover, let ttlSeconds):
case .messageMediaDocument(let flags, let document, let altDocuments, let videoCover, let videoTimestamp, let ttlSeconds):
if boxed {
buffer.appendInt32(-608307692)
buffer.appendInt32(1389939929)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {document!.serialize(buffer, true)}
@ -757,6 +757,7 @@ public extension Api {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 9) != 0 {videoCover!.serialize(buffer, true)}
if Int(flags) & Int(1 << 10) != 0 {serializeInt32(videoTimestamp!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(ttlSeconds!, buffer: buffer, boxed: false)}
break
case .messageMediaEmpty:
@ -910,8 +911,8 @@ public extension Api {
return ("messageMediaContact", [("phoneNumber", phoneNumber as Any), ("firstName", firstName as Any), ("lastName", lastName as Any), ("vcard", vcard as Any), ("userId", userId as Any)])
case .messageMediaDice(let value, let emoticon):
return ("messageMediaDice", [("value", value as Any), ("emoticon", emoticon as Any)])
case .messageMediaDocument(let flags, let document, let altDocuments, let videoCover, let ttlSeconds):
return ("messageMediaDocument", [("flags", flags as Any), ("document", document as Any), ("altDocuments", altDocuments as Any), ("videoCover", videoCover as Any), ("ttlSeconds", ttlSeconds as Any)])
case .messageMediaDocument(let flags, let document, let altDocuments, let videoCover, let videoTimestamp, let ttlSeconds):
return ("messageMediaDocument", [("flags", flags as Any), ("document", document as Any), ("altDocuments", altDocuments as Any), ("videoCover", videoCover as Any), ("videoTimestamp", videoTimestamp as Any), ("ttlSeconds", ttlSeconds as Any)])
case .messageMediaEmpty:
return ("messageMediaEmpty", [])
case .messageMediaGame(let game):
@ -996,14 +997,17 @@ public extension Api {
_4 = Api.parse(reader, signature: signature) as? Api.Photo
} }
var _5: Int32?
if Int(_1!) & Int(1 << 2) != 0 {_5 = reader.readInt32() }
if Int(_1!) & Int(1 << 10) != 0 {_5 = reader.readInt32() }
var _6: Int32?
if Int(_1!) & Int(1 << 2) != 0 {_6 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil
let _c3 = (Int(_1!) & Int(1 << 5) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 9) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.MessageMedia.messageMediaDocument(flags: _1!, document: _2, altDocuments: _3, videoCover: _4, ttlSeconds: _5)
let _c5 = (Int(_1!) & Int(1 << 10) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.MessageMedia.messageMediaDocument(flags: _1!, document: _2, altDocuments: _3, videoCover: _4, videoTimestamp: _5, ttlSeconds: _6)
}
else {
return nil

View File

@ -350,7 +350,8 @@ func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerI
case let .messageMediaGeoLive(_, geo, heading, period, proximityNotificationRadius):
let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil, venueType: nil, liveBroadcastingTimeout: period, liveProximityNotificationRadius: proximityNotificationRadius, heading: heading)
return (mediaMap, nil, nil, nil, nil)
case let .messageMediaDocument(flags, document, altDocuments, coverPhoto, ttlSeconds):
case let .messageMediaDocument(flags, document, altDocuments, coverPhoto, videoTimestamp, ttlSeconds):
let _ = videoTimestamp
if let document = document {
if let mediaFile = telegramMediaFileFromApiDocument(document, altDocuments: altDocuments, videoCover: coverPhoto) {
return (mediaFile, ttlSeconds, (flags & (1 << 3)) != 0, (flags & (1 << 4)) != 0, nil)

View File

@ -229,7 +229,7 @@ func mediaContentToUpload(accountPeerId: PeerId, network: Network, postbox: Post
}
|> mapToSignal { validatedResource -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
if let validatedResource = validatedResource.updatedResource as? TelegramCloudMediaResourceWithFileReference, let reference = validatedResource.fileReference {
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(Api.InputMedia.inputMediaDocument(flags: 0, id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: reference)), videoCover: nil, ttlSeconds: nil, query: nil), text), reuploadInfo: nil, cacheReferenceKey: nil)))
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(Api.InputMedia.inputMediaDocument(flags: 0, id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: reference)), videoCover: nil, videoTimestamp: nil, ttlSeconds: nil, query: nil), text), reuploadInfo: nil, cacheReferenceKey: nil)))
} else {
return .fail(.generic)
}
@ -246,7 +246,7 @@ func mediaContentToUpload(accountPeerId: PeerId, network: Network, postbox: Post
}
}
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(Api.InputMedia.inputMediaDocument(flags: flags, id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), videoCover: nil, ttlSeconds: nil, query: emojiSearchQuery), text), reuploadInfo: nil, cacheReferenceKey: nil)))
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(Api.InputMedia.inputMediaDocument(flags: flags, id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), videoCover: nil, videoTimestamp: nil, ttlSeconds: nil, query: emojiSearchQuery), text), reuploadInfo: nil, cacheReferenceKey: nil)))
}
} else {
return uploadedMediaFileContent(network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, forceReupload: forceReupload, isGrouped: isGrouped, isPaid: false, passFetchProgress: passFetchProgress, forceNoBigParts: forceNoBigParts, peerId: peerId, messageId: messageId, text: text, attributes: attributes, autoremoveMessageAttribute: autoremoveMessageAttribute, autoclearMessageAttribute: autoclearMessageAttribute, file: file)
@ -866,7 +866,7 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
return .single(.progress(PendingMessageUploadedContentProgress(progress: 1.0)))
|> then(
.single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(Api.InputMedia.inputMediaDocument(flags: flags, id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: fileReference)), videoCover: nil, ttlSeconds: ttlSeconds, query: nil), text), reuploadInfo: nil, cacheReferenceKey: nil)))
.single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(Api.InputMedia.inputMediaDocument(flags: flags, id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: fileReference)), videoCover: nil, videoTimestamp: nil, ttlSeconds: ttlSeconds, query: nil), text), reuploadInfo: nil, cacheReferenceKey: nil)))
)
}
referenceKey = key
@ -1122,11 +1122,11 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
}
if ttlSeconds != nil {
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnailFile, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: stickers, videoCover: videoCoverPhoto, ttlSeconds: ttlSeconds), text), reuploadInfo: nil, cacheReferenceKey: referenceKey)))
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnailFile, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: stickers, videoCover: videoCoverPhoto, videoTimestamp: nil, ttlSeconds: ttlSeconds), text), reuploadInfo: nil, cacheReferenceKey: referenceKey)))
}
if !isGrouped {
let resultInfo = PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnailFile, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: stickers, videoCover: videoCoverPhoto, ttlSeconds: ttlSeconds), text), reuploadInfo: nil, cacheReferenceKey: referenceKey)
let resultInfo = PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnailFile, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: stickers, videoCover: videoCoverPhoto, videoTimestamp: nil, ttlSeconds: ttlSeconds), text), reuploadInfo: nil, cacheReferenceKey: referenceKey)
return .single(.content(resultInfo))
}
@ -1137,11 +1137,11 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
|> mapError { _ -> PendingMessageUploadError in }
|> mapToSignal { inputPeer -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
if let inputPeer = inputPeer {
return network.request(Api.functions.messages.uploadMedia(flags: 0, businessConnectionId: nil, peer: inputPeer, media: .inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnailFile, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: stickers, videoCover: videoCoverPhoto, ttlSeconds: ttlSeconds)))
return network.request(Api.functions.messages.uploadMedia(flags: 0, businessConnectionId: nil, peer: inputPeer, media: .inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnailFile, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: stickers, videoCover: videoCoverPhoto, videoTimestamp: nil, ttlSeconds: ttlSeconds)))
|> mapError { _ -> PendingMessageUploadError in return .generic }
|> mapToSignal { result -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
switch result {
case let .messageMediaDocument(_, document, altDocuments, _, _):
case let .messageMediaDocument(_, document, altDocuments, _, _, _):
if let document = document, let mediaFile = telegramMediaFileFromApiDocument(document, altDocuments: altDocuments), let resource = mediaFile.resource as? CloudDocumentMediaResource, let fileReference = resource.fileReference {
var flags: Int32 = 0
var ttlSeconds: Int32?
@ -1156,7 +1156,7 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
flags |= (1 << 3)
}
let result: PendingMessageUploadedContentResult = .content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaDocument(flags: flags, id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: fileReference)), videoCover: videoCoverPhoto, ttlSeconds: ttlSeconds, query: nil), text), reuploadInfo: nil, cacheReferenceKey: nil))
let result: PendingMessageUploadedContentResult = .content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaDocument(flags: flags, id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: fileReference)), videoCover: videoCoverPhoto, videoTimestamp: nil, ttlSeconds: ttlSeconds, query: nil), text), reuploadInfo: nil, cacheReferenceKey: nil))
if let _ = ttlSeconds {
return .single(result)
} else {

View File

@ -702,7 +702,7 @@ private func uploadedFile(account: Account, data: Data, mimeType: String, attrib
|> map { next -> UploadMediaEvent in
switch next {
case let .inputFile(inputFile):
return .result(Api.InputMedia.inputMediaUploadedDocument(flags: 0, file: inputFile, thumb: nil, mimeType: mimeType, attributes: inputDocumentAttributesFromFileAttributes(attributes), stickers: nil, videoCover: nil, ttlSeconds: nil))
return .result(Api.InputMedia.inputMediaUploadedDocument(flags: 0, file: inputFile, thumb: nil, mimeType: mimeType, attributes: inputDocumentAttributesFromFileAttributes(attributes), stickers: nil, videoCover: nil, videoTimestamp: nil, ttlSeconds: nil))
case .inputSecretFile:
preconditionFailure()
case let .progress(progress):

View File

@ -158,11 +158,11 @@ public func standaloneUploadedFile(postbox: Postbox, network: Network, peerId: P
if let _ = thumbnailFile {
flags |= 1 << 2
}
return network.request(Api.functions.messages.uploadMedia(flags: 0, businessConnectionId: nil, peer: inputPeer, media: Api.InputMedia.inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnailFile, mimeType: mimeType, attributes: inputDocumentAttributesFromFileAttributes(attributes), stickers: nil, videoCover: nil, ttlSeconds: nil)))
return network.request(Api.functions.messages.uploadMedia(flags: 0, businessConnectionId: nil, peer: inputPeer, media: Api.InputMedia.inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnailFile, mimeType: mimeType, attributes: inputDocumentAttributesFromFileAttributes(attributes), stickers: nil, videoCover: nil, videoTimestamp: nil, ttlSeconds: nil)))
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|> mapToSignal { media -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
switch media {
case let .messageMediaDocument(_, document, altDocuments, _, _):
case let .messageMediaDocument(_, document, altDocuments, _, _, _):
if let document = document {
if let mediaFile = telegramMediaFileFromApiDocument(document, altDocuments: altDocuments) {
return .single(.result(.media(.standalone(media: mediaFile))))

View File

@ -52,7 +52,7 @@ extension Api.MessageMedia {
} else {
return nil
}
case let .messageMediaDocument(_, document, _, _, _):
case let .messageMediaDocument(_, document, _, _, _, _):
if let document = document {
return collectPreCachedResources(for: document)
}
@ -626,14 +626,14 @@ extension Api.EncryptedMessage {
extension Api.InputMedia {
func withUpdatedStickers(_ stickers: [Api.InputDocument]?) -> Api.InputMedia {
switch self {
case let .inputMediaUploadedDocument(flags, file, thumb, mimeType, attributes, _, videoCover, ttlSeconds):
case let .inputMediaUploadedDocument(flags, file, thumb, mimeType, attributes, _, videoCover, videoTimestamp, ttlSeconds):
var flags = flags
var attributes = attributes
if let _ = stickers {
flags |= (1 << 0)
attributes.append(.documentAttributeHasStickers)
}
return .inputMediaUploadedDocument(flags: flags, file: file, thumb: thumb, mimeType: mimeType, attributes: attributes, stickers: stickers, videoCover: videoCover, ttlSeconds: ttlSeconds)
return .inputMediaUploadedDocument(flags: flags, file: file, thumb: thumb, mimeType: mimeType, attributes: attributes, stickers: stickers, videoCover: videoCover, videoTimestamp: videoTimestamp, ttlSeconds: ttlSeconds)
case let .inputMediaUploadedPhoto(flags, file, _, ttlSeconds):
var flags = flags
if let _ = stickers {

View File

@ -153,7 +153,7 @@ public extension TelegramEngine {
default:
break
}
inputMedia = .inputMediaUploadedDocument(flags: 0, file: inputFile, thumb: nil, mimeType: resolvedMimeType, attributes: attributes, stickers: nil, videoCover: nil, ttlSeconds: nil)
inputMedia = .inputMediaUploadedDocument(flags: 0, file: inputFile, thumb: nil, mimeType: resolvedMimeType, attributes: attributes, stickers: nil, videoCover: nil, videoTimestamp: nil, ttlSeconds: nil)
}
case let .progress(value):
return .single(value)

View File

@ -1405,7 +1405,7 @@ func _internal_deleteBotPreviews(account: Account, peerId: PeerId, language: Str
inputMedia.append(.inputMediaPhoto(flags: 0, id: .inputPhoto(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference)), ttlSeconds: nil))
inputMedia.append(Api.InputMedia.inputMediaPhoto(flags: 0, id: Api.InputPhoto.inputPhoto(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference)), ttlSeconds: nil))
} else if let file = item as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource {
inputMedia.append(.inputMediaDocument(flags: 0, id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), videoCover: nil, ttlSeconds: nil, query: nil))
inputMedia.append(.inputMediaDocument(flags: 0, id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), videoCover: nil, videoTimestamp: nil, ttlSeconds: nil, query: nil))
}
}
if language == nil {
@ -1463,7 +1463,7 @@ func _internal_deleteBotPreviewsLanguage(account: Account, peerId: PeerId, langu
inputMedia.append(.inputMediaPhoto(flags: 0, id: .inputPhoto(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference)), ttlSeconds: nil))
inputMedia.append(Api.InputMedia.inputMediaPhoto(flags: 0, id: Api.InputPhoto.inputPhoto(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference)), ttlSeconds: nil))
} else if let file = item as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource {
inputMedia.append(.inputMediaDocument(flags: 0, id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), videoCover: nil, ttlSeconds: nil, query: nil))
inputMedia.append(.inputMediaDocument(flags: 0, id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), videoCover: nil, videoTimestamp: nil, ttlSeconds: nil, query: nil))
}
}
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current -> CachedPeerData? in
@ -1528,7 +1528,7 @@ func _internal_editStory(account: Account, peerId: PeerId, id: Int32, media: Eng
if let result = result, case let .content(uploadedContent) = result, case let .media(media, _) = uploadedContent.content {
inputMedia = media
} else if case let .existing(media) = media, let file = media as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource {
inputMedia = .inputMediaUploadedDocument(flags: 0, file: .inputFileStoryDocument(id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), thumb: nil, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: nil, videoCover: nil, ttlSeconds: nil)
inputMedia = .inputMediaUploadedDocument(flags: 0, file: .inputFileStoryDocument(id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), thumb: nil, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: nil, videoCover: nil, videoTimestamp: nil, ttlSeconds: nil)
updatingCoverTime = true
} else {
inputMedia = nil
@ -2099,7 +2099,7 @@ extension Stories.StoredItem {
var parsedAlternativeMedia: [Media] = []
switch media {
case let .messageMediaDocument(_, _, altDocuments, _, _):
case let .messageMediaDocument(_, _, altDocuments, _, _, _):
if let altDocuments {
parsedAlternativeMedia = altDocuments.compactMap { telegramMediaFileFromApiDocument($0, altDocuments: []) }
}

View File

@ -2615,7 +2615,7 @@ public final class BotPreviewStoryListContext: StoryListContext {
inputMedia.append(.inputMediaPhoto(flags: 0, id: .inputPhoto(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference)), ttlSeconds: nil))
inputMedia.append(Api.InputMedia.inputMediaPhoto(flags: 0, id: Api.InputPhoto.inputPhoto(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference)), ttlSeconds: nil))
} else if let file = item as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource {
inputMedia.append(.inputMediaDocument(flags: 0, id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), videoCover: nil, ttlSeconds: nil, query: nil))
inputMedia.append(.inputMediaDocument(flags: 0, id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), videoCover: nil, videoTimestamp: nil, ttlSeconds: nil, query: nil))
}
}

View File

@ -925,7 +925,10 @@ private final class ProfileGiftsContextImpl {
private let cacheDisposable = MetaDisposable()
private let actionDisposable = MetaDisposable()
private var sorting: ProfileGiftsContext.Sorting = .date
private var filter: ProfileGiftsContext.Filters = ProfileGiftsContext.Filters.All
private var gifts: [ProfileGiftsContext.State.StarGift] = []
private var filteredGifts: [ProfileGiftsContext.State.StarGift] = []
private var count: Int32?
private var dataState: ProfileGiftsContext.State.DataState = .ready(canLoadMore: true, nextOffset: nil)
private var notificationsEnabled: Bool?
@ -1111,13 +1114,47 @@ private final class ProfileGiftsContextImpl {
self.pushState()
}
func updateFilter(_ filter: ProfileGiftsContext.Filters) {
self.filter = filter
self.pushState()
}
func updateSorting(_ sorting: ProfileGiftsContext.Sorting) {
self.sorting = sorting
self.pushState()
}
private func pushState() {
self._state = ProfileGiftsContext.State(gifts: self.gifts, count: self.count, dataState: self.dataState, notificationsEnabled: self.notificationsEnabled)
self.stateValue.set(.single(ProfileGiftsContext.State(gifts: self.gifts, count: self.count, dataState: self.dataState, notificationsEnabled: self.notificationsEnabled)))
let state = ProfileGiftsContext.State(filter: self.filter, sorting: self.sorting, gifts: self.gifts, count: self.count, dataState: self.dataState, notificationsEnabled: self.notificationsEnabled)
self._state = state
self.stateValue.set(.single(state))
}
}
public final class ProfileGiftsContext {
public struct Filters: OptionSet {
public var rawValue: Int32
public init(rawValue: Int32) {
self.rawValue = rawValue
}
public static let unlimited = Filters(rawValue: 1 << 0)
public static let limited = Filters(rawValue: 1 << 1)
public static let unique = Filters(rawValue: 1 << 2)
public static let displayed = Filters(rawValue: 1 << 3)
public static let hidden = Filters(rawValue: 1 << 4)
public static var All: Filters {
return [.unlimited, .limited, .unique, .displayed, .hidden]
}
}
public enum Sorting: Equatable {
case date
case value
}
public struct State: Equatable {
public struct StarGift: Equatable, Codable {
enum CodingKeys: String, CodingKey {
@ -1273,6 +1310,9 @@ public final class ProfileGiftsContext {
case ready(canLoadMore: Bool, nextOffset: String?)
}
public var filter: Filters
public var sorting: Sorting
public var gifts: [ProfileGiftsContext.State.StarGift]
public var count: Int32?
public var dataState: ProfileGiftsContext.State.DataState
@ -1349,6 +1389,18 @@ public final class ProfileGiftsContext {
}
}
public func updateFilter(_ filter: ProfileGiftsContext.Filters) {
self.impl.with { impl in
impl.updateFilter(filter)
}
}
public func updateSorting(_ sorting: ProfileGiftsContext.Sorting) {
self.impl.with { impl in
impl.updateSorting(sorting)
}
}
public var currentState: ProfileGiftsContext.State? {
var state: ProfileGiftsContext.State?
self.impl.syncWith { impl in

View File

@ -83,11 +83,11 @@ func _internal_uploadSticker(account: Account, peer: Peer, resource: MediaResour
attributes.append(.documentAttributeVideo(flags: 0, duration: duration, w: dimensions.width, h: dimensions.height, preloadPrefixSize: nil, videoStartTs: nil, videoCodec: nil))
}
attributes.append(.documentAttributeImageSize(w: dimensions.width, h: dimensions.height))
return account.network.request(Api.functions.messages.uploadMedia(flags: 0, businessConnectionId: nil, peer: inputPeer, media: Api.InputMedia.inputMediaUploadedDocument(flags: flags, file: file, thumb: thumbnailFile, mimeType: mimeType, attributes: attributes, stickers: nil, videoCover: nil, ttlSeconds: nil)))
return account.network.request(Api.functions.messages.uploadMedia(flags: 0, businessConnectionId: nil, peer: inputPeer, media: Api.InputMedia.inputMediaUploadedDocument(flags: flags, file: file, thumb: thumbnailFile, mimeType: mimeType, attributes: attributes, stickers: nil, videoCover: nil, videoTimestamp: nil, ttlSeconds: nil)))
|> mapError { _ -> UploadStickerError in return .generic }
|> mapToSignal { media -> Signal<UploadStickerStatus, UploadStickerError> in
switch media {
case let .messageMediaDocument(_, document, altDocuments, _, _):
case let .messageMediaDocument(_, document, altDocuments, _, _, _):
if let document = document, let file = telegramMediaFileFromApiDocument(document, altDocuments: altDocuments), let uploadedResource = file.resource as? CloudDocumentMediaResource {
account.postbox.mediaBox.copyResourceData(from: resource.id, to: uploadedResource.id, synchronous: true)
if let thumbnail, let previewRepresentation = file.previewRepresentations.first(where: { $0.dimensions == PixelDimensions(width: 320, height: 320) }) {

View File

@ -201,6 +201,7 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
case dismissedBusinessChatbotsBadge = 74
case captionAboveMediaTooltip = 75
case channelSendGiftTooltip = 76
case starGiftWearTips = 77
var key: ValueBoxKey {
let v = ValueBoxKey(length: 4)
@ -549,6 +550,10 @@ private struct ApplicationSpecificNoticeKeys {
static func channelSendGiftTooltip() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.channelSendGiftTooltip.key)
}
static func starGiftWearTips() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.starGiftWearTips.key)
}
}
public struct ApplicationSpecificNotice {
@ -2335,4 +2340,31 @@ public struct ApplicationSpecificNotice {
return Int(previousValue)
}
}
public static func getStarGiftWearTips(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> {
return accountManager.transaction { transaction -> Int32 in
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.starGiftWearTips())?.get(ApplicationSpecificCounterNotice.self) {
return value.value
} else {
return 0
}
}
}
public static func incrementStarGiftWearTips(accountManager: AccountManager<TelegramAccountManagerTypes>, count: Int = 1) -> Signal<Int, NoError> {
return accountManager.transaction { transaction -> Int in
var currentValue: Int32 = 0
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.starGiftWearTips())?.get(ApplicationSpecificCounterNotice.self) {
currentValue = value.value
}
let previousValue = currentValue
currentValue += Int32(count)
if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) {
transaction.setNotice(ApplicationSpecificNoticeKeys.starGiftWearTips(), entry)
}
return Int(previousValue)
}
}
}

View File

@ -193,4 +193,10 @@ public struct PresentationResourcesRootController {
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddStoryIcon"), color: .white)
})
}
public static func navigationSortIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationPostStoryIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SortIcon"), color: .white)
})
}
}

View File

@ -1113,7 +1113,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
}
case let .starGiftUnique(gift, isUpgrade, _, _, _, _, _, _, _, _):
if case let .unique(gift) = gift {
if !forAdditionalServiceMessage {
if !forAdditionalServiceMessage && !"".isEmpty {
attributedString = NSAttributedString(string: "\(gift.title) #\(gift.number)", font: titleFont, textColor: primaryTextColor)
} else if let messagePeer = message.peers[message.id.peerId] {
let peerName = EnginePeer(messagePeer).compactDisplayTitle

View File

@ -20,6 +20,7 @@ swift_library(
"//submodules/AccountContext",
"//submodules/PresentationDataUtils",
"//submodules/Markdown",
"//submodules/TelegramNotices",
"//submodules/ComponentFlow",
"//submodules/Components/ComponentDisplayAdapters",
"//submodules/Components/ViewControllerComponent",

View File

@ -31,6 +31,7 @@ import TooltipUI
import GiftAnimationComponent
import LottieComponent
import ContextUI
import TelegramNotices
private let modelButtonTag = GenericComponentViewTag()
private let backdropButtonTag = GenericComponentViewTag()
@ -286,6 +287,25 @@ private final class GiftViewSheetContent: CombinedComponent {
self.updated(transition: .spring(duration: 0.4))
}
func commitWear(_ uniqueGift: StarGift.UniqueGift) {
self.pendingWear = true
self.pendingTakeOff = false
self.inWearPreview = false
self.updated(transition: .spring(duration: 0.4))
let _ = self.context.engine.accountData.setStarGiftStatus(starGift: uniqueGift, expirationDate: nil).startStandalone()
let _ = ApplicationSpecificNotice.incrementStarGiftWearTips(accountManager: self.context.sharedContext.accountManager).startStandalone()
}
func commitTakeOff() {
self.pendingTakeOff = true
self.pendingWear = false
self.updated(transition: .spring(duration: 0.4))
let _ = self.context.engine.accountData.setEmojiStatus(file: nil, expirationDate: nil).startStandalone()
}
func commitUpgrade() {
guard let arguments = self.subject.arguments, let peerId = arguments.peerId, let starsContext = self.context.starsContext, let starsState = starsContext.currentState else {
return
@ -1117,6 +1137,7 @@ private final class GiftViewSheetContent: CombinedComponent {
if peer.id == component.context.account.peerId, peer.isPremium {
let animationContent: EmojiStatusComponent.Content
var color: UIColor?
var statusId: Int64 = 1
if state.pendingWear {
var fileId: Int64?
for attribute in uniqueGift.attributes {
@ -1128,6 +1149,7 @@ private final class GiftViewSheetContent: CombinedComponent {
}
}
if let fileId {
statusId = fileId
animationContent = .animation(content: .customEmoji(fileId: fileId), size: CGSize(width: 18.0, height: 18.0), placeholderColor: theme.list.mediaPlaceholderColor, themeColor: tableLinkColor, loopMode: .count(2))
} else {
animationContent = .premium(color: tableLinkColor)
@ -1168,7 +1190,7 @@ private final class GiftViewSheetContent: CombinedComponent {
))
),
AnyComponentWithIdentity(
id: AnyHashable(1),
id: AnyHashable(statusId),
component: AnyComponent(EmojiStatusComponent(
context: component.context,
animationCache: component.context.animationCache,
@ -1351,17 +1373,26 @@ private final class GiftViewSheetContent: CombinedComponent {
action: { [weak state] in
if let state {
if isWearing {
state.pendingTakeOff = true
state.pendingWear = false
state.updated(transition: .spring(duration: 0.4))
state.commitTakeOff()
component.showAttributeInfo(statusTag, strings.Gift_View_TookOff("\(uniqueGift.title) #\(uniqueGift.number)").string)
} else {
if let controller = controller() as? GiftViewScreen {
controller.dismissAllTooltips()
}
state.requestWearPreview()
let _ = (ApplicationSpecificNotice.getStarGiftWearTips(accountManager: component.context.sharedContext.accountManager)
|> deliverOnMainQueue).start(next: { [weak state] count in
guard let state else {
return
}
if !component.context.isPremium || count < 3 {
state.requestWearPreview()
} else {
state.commitWear(uniqueGift)
component.showAttributeInfo(statusTag, strings.Gift_View_PutOn("\(uniqueGift.title) #\(uniqueGift.number)").string)
}
})
}
}
}
@ -1731,7 +1762,7 @@ private final class GiftViewSheetContent: CombinedComponent {
items: tableItems
),
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: .greatestFiniteMagnitude),
transition: .immediate
transition: context.transition
)
context.add(table
.position(CGPoint(x: context.availableSize.width / 2.0, y: originY + table.size.height / 2.0))
@ -1866,13 +1897,7 @@ private final class GiftViewSheetContent: CombinedComponent {
)
controller.present(tooltipController, in: .window(.root))
} else {
state.pendingWear = true
state.pendingTakeOff = false
state.inWearPreview = false
state.updated(transition: .spring(duration: 0.4))
let _ = component.context.engine.accountData.setStarGiftStatus(starGift: uniqueGift, expirationDate: nil).start()
state.commitWear(uniqueGift)
Queue.mainQueue().after(0.2) {
component.showAttributeInfo(statusTag, strings.Gift_View_PutOn("\(uniqueGift.title) #\(uniqueGift.number)").string)
}

View File

@ -439,13 +439,7 @@ public final class PeerInfoCoverComponent: Component {
let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -1000.0 + availableSize.height), size: CGSize(width: availableSize.width, height: 1000.0))
transition.containedViewLayoutTransition.updateFrameAdditive(view: self.backgroundView, frame: backgroundFrame)
/*let avatarBackgroundPatternContainerFrame = CGSize(width: 0.0, height: 0.0).centered(around: component.avatarCenter)
transition.containedViewLayoutTransition.updateFrameAdditive(view: self.avatarBackgroundPatternContainer, frame: avatarBackgroundPatternContainerFrame)
transition.containedViewLayoutTransition.updateSublayerTransformScaleAdditive(layer: self.avatarBackgroundPatternContainer.layer, scale: component.avatarScale)*/
//transition.setFrame(view: self.avatarBackgroundPatternView, frame: CGSize(width: 200.0, height: 200.0).centered(around: CGPoint()))
let avatarPatternFrame = CGSize(width: 380.0, height: floor(component.defaultHeight * 1.0)).centered(around: component.avatarCenter)
transition.setFrame(layer: self.avatarBackgroundPatternContentsLayer, frame: avatarPatternFrame)
@ -457,7 +451,7 @@ public final class PeerInfoCoverComponent: Component {
]
} else if case let .status(status) = component.subject, case let .starGift(_, _, _, _, _, _, _, patternColorValue, _) = status.content {
let patternColor = UIColor(rgb: UInt32(bitPattern: patternColorValue))
self.avatarBackgroundPatternContentsLayer.compositingFilter = nil
self.avatarBackgroundPatternContentsLayer.compositingFilter = "overlayBlendMode"
self.avatarBackgroundPatternContentsLayer.colors = [
patternColor.withAlphaComponent(0.6).cgColor,
patternColor.withAlphaComponent(0.0).cgColor
@ -469,7 +463,6 @@ public final class PeerInfoCoverComponent: Component {
UIColor(white: 0.0, alpha: 0.6).cgColor,
UIColor(white: 0.0, alpha: 0.0).cgColor
]
} else {
self.avatarBackgroundPatternContentsLayer.compositingFilter = nil
let baseWhite: CGFloat = component.isDark ? 0.5 : 0.3

View File

@ -282,6 +282,10 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
text = ""
accessibilityText = presentationData.strings.Story_Privacy_PostStory
icon = PresentationResourcesRootController.navigationPostStoryIcon(presentationData.theme)
case .sort:
text = ""
accessibilityText = presentationData.strings.Common_More
icon = PresentationResourcesRootController.navigationSortIcon(presentationData.theme)
}
self.accessibilityLabel = accessibilityText
self.containerNode.isGestureEnabled = isGestureEnabled

View File

@ -21,6 +21,7 @@ enum PeerInfoHeaderNavigationButtonKey {
case qrCode
case moreToSearch
case postStory
case sort
}
struct PeerInfoHeaderNavigationButtonSpec: Equatable {

View File

@ -2306,11 +2306,11 @@ final class PeerInfoHeaderNode: ASDisplayNode {
Queue.mainQueue().after(0.2) {
backgroundCoverView.animateIn()
}
Queue.mainQueue().after(0.44) {
Queue.mainQueue().after(0.5) {
self.invokeDisplayGiftInfo()
}
} else {
Queue.mainQueue().after(0.44) {
Queue.mainQueue().after(0.5) {
self.invokeDisplayGiftInfo()
}
}

View File

@ -4430,14 +4430,27 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
case .search, .searchWithTags, .standaloneSearch:
strongSelf.activateSearch()
case .more:
if let currentPaneKey = strongSelf.paneContainerNode.currentPaneKey, case .savedMessagesChats = currentPaneKey {
if let controller = strongSelf.controller, let source {
PeerInfoScreenImpl.openSavedMessagesMoreMenu(context: strongSelf.context, sourceController: controller, isViewingAsTopics: true, sourceView: source.view, gesture: gesture)
guard let source else {
return
}
if let currentPaneKey = strongSelf.paneContainerNode.currentPaneKey {
switch currentPaneKey {
case .savedMessagesChats:
if let controller = strongSelf.controller {
PeerInfoScreenImpl.openSavedMessagesMoreMenu(context: strongSelf.context, sourceController: controller, isViewingAsTopics: true, sourceView: source.view, gesture: gesture)
}
default:
break
}
} else {
if let source = source {
strongSelf.displayMediaGalleryContextMenu(source: source, gesture: gesture)
}
strongSelf.displayMediaGalleryContextMenu(source: source, gesture: gesture)
}
case .sort:
guard let source else {
return
}
if let currentPaneKey = strongSelf.paneContainerNode.currentPaneKey, case .gifts = currentPaneKey {
strongSelf.displayGiftsContextMenu(source: source, gesture: gesture)
}
case .qrCode:
strongSelf.openQrCode()
@ -4651,6 +4664,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
style: .customBlur(backgroundColor, -4.0),
arrowStyle: .small,
location: .point(sourceRect, .bottom),
isShimmering: true,
cornerRadius: 10.0,
shouldDismissOnTouch: { _, _ in
return .dismiss(consume: false)
@ -10883,6 +10897,126 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
return .dismiss(consume: false)
}), in: .current)
}
private func displayGiftsContextMenu(source: ContextReferenceContentNode, gesture: ContextGesture?) {
guard let currentPaneKey = self.paneContainerNode.currentPaneKey, case .gifts = currentPaneKey else {
return
}
guard let controller = self.controller else {
return
}
guard let data = self.data, let channel = data.peer as? TelegramChannel, channel.hasPermission(.sendSomething), let giftsContext = data.profileGiftsContext else {
return
}
let strings = self.presentationData.strings
let items: Signal<ContextController.Items, NoError> = giftsContext.state
|> map { state in
return (state.filter, state.sorting)
}
|> distinctUntilChanged(isEqual: { lhs, rhs -> Bool in
let filterEquals = lhs.0 == rhs.0
let sortingEquals = lhs.1 == rhs.1
return filterEquals && sortingEquals
})
|> map { [weak giftsContext] filter, sorting -> ContextController.Items in
var items: [ContextMenuItem] = []
items.append(.action(ContextMenuActionItem(text: sorting == .date ? strings.PeerInfo_Gifts_SortByValue : strings.PeerInfo_Gifts_SortByDate, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: sorting == .date ? "Peer Info/SortValue" : "Peer Info/SortDate"), color: theme.contextMenu.primaryColor)
}, action: { [weak giftsContext] _, f in
f(.default)
giftsContext?.updateSorting(sorting == .date ? .value : .date)
})))
items.append(.separator)
let toggleFilter: (ProfileGiftsContext.Filters) -> Void = { [weak giftsContext] value in
var updatedFilter = filter
if updatedFilter.contains(value) {
updatedFilter.remove(value)
} else {
updatedFilter.insert(value)
}
giftsContext?.updateFilter(updatedFilter)
}
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Unlimited, icon: { theme in
return filter.contains(.unlimited) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
}, action: { _, f in
f(.default)
toggleFilter(.unlimited)
})))
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Limited, icon: { theme in
return filter.contains(.limited) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
}, action: { _, f in
f(.default)
toggleFilter(.limited)
})))
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Unique, icon: { theme in
return filter.contains(.unique) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
}, action: { _, f in
f(.default)
toggleFilter(.unique)
})))
items.append(.separator)
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Displayed, icon: { theme in
return filter.contains(.displayed) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
}, action: { _, f in
f(.default)
toggleFilter(.displayed)
})))
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Hidden, icon: { theme in
return filter.contains(.hidden) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
}, action: { _, f in
f(.default)
toggleFilter(.hidden)
})))
return ContextController.Items(content: .list(items))
}
let contextController = ContextController(presentationData: self.presentationData, source: .reference(PeerInfoContextReferenceContentSource(controller: controller, sourceNode: source)), items: items, gesture: gesture)
contextController.passthroughTouchEvent = { [weak self] sourceView, point in
guard let strongSelf = self else {
return .ignore
}
let localPoint = strongSelf.view.convert(sourceView.convert(point, to: nil), from: nil)
guard let localResult = strongSelf.hitTest(localPoint, with: nil) else {
return .dismiss(consume: true, result: nil)
}
var testView: UIView? = localResult
while true {
if let testViewValue = testView {
if let node = testViewValue.asyncdisplaykit_node as? PeerInfoHeaderNavigationButton {
node.isUserInteractionEnabled = false
DispatchQueue.main.async {
node.isUserInteractionEnabled = true
}
return .dismiss(consume: false, result: nil)
} else {
testView = testViewValue.superview
}
} else {
break
}
}
return .dismiss(consume: true, result: nil)
}
self.mediaGalleryContextMenu = contextController
controller.presentInGlobalOverlay(contextController)
}
private func displayMediaGalleryContextMenu(source: ContextReferenceContentNode, gesture: ContextGesture?) {
let peerId = self.peerId
@ -11873,6 +12007,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
if let data = self.data, data.hasBotPreviewItems, let user = data.peer as? TelegramUser, let botInfo = user.botInfo, botInfo.flags.contains(.canEdit) {
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .more, isForExpandedView: true))
}
case .gifts:
if let data = self.data, let channel = data.peer as? TelegramChannel, channel.hasPermission(.sendSomething) {
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .sort, isForExpandedView: true))
}
default:
break
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "sortdate_24.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "sort_30.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "sortvalue_24.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -26,6 +26,7 @@ swift_library(
"//submodules/TelegramUI/Components/Stories/AvatarStoryIndicatorComponent",
"//submodules/Components/BalancedTextComponent",
"//submodules/Components/MultilineTextWithEntitiesComponent",
"//submodules/ShimmerEffect",
],
visibility = [
"//visibility:public",

View File

@ -18,6 +18,7 @@ import AccountContext
import Markdown
import BalancedTextComponent
import MultilineTextWithEntitiesComponent
import ShimmerEffect
public enum TooltipActiveTextItem {
case url(String, Bool)
@ -126,6 +127,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
}
}
}
private let isShimmering: Bool
private let displayDuration: TooltipScreen.DisplayDuration
private let shouldDismissOnTouch: (CGPoint, CGRect) -> TooltipScreen.DismissOnTouch
private let requestDismiss: () -> Void
@ -149,6 +151,9 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
private var closeButtonNode: HighlightableButtonNode?
private var actionButtonNode: HighlightableButtonNode?
private var shimmerContainerView: UIView?
private var shimmerView: ShimmerEffectForegroundView?
private var isArrowInverted: Bool = false
private let fontSize: CGFloat
@ -172,6 +177,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
displayDuration: TooltipScreen.DisplayDuration,
inset: CGFloat = 12.0,
cornerRadius: CGFloat? = nil,
isShimmering: Bool = false,
shouldDismissOnTouch: @escaping (CGPoint, CGRect) -> TooltipScreen.DismissOnTouch, requestDismiss: @escaping () -> Void, openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)?)
{
self.context = context
@ -181,6 +187,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
self.action = action
self.location = location
self.displayDuration = displayDuration
self.isShimmering = isShimmering
self.inset = inset
self.shouldDismissOnTouch = shouldDismissOnTouch
self.requestDismiss = requestDismiss
@ -446,7 +453,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
self.actionButtonNode?.addTarget(self, action: #selector(self.actionPressed), forControlEvents: .touchUpInside)
self.closeButtonNode?.addTarget(self, action: #selector(self.closePressed), forControlEvents: .touchUpInside)
}
@objc private func actionPressed() {
if let action = self.action {
action.action()
@ -713,8 +720,8 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
transition.updateFrame(node: self.backgroundMaskNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size).insetBy(dx: -10.0, dy: -10.0))
transition.updateFrame(node: self.backgroundClipNode, frame: CGRect(origin: CGPoint(x: 10.0, y: 10.0), size: backgroundFrame.size))
let effectFrame = CGRect(origin: CGPoint(), size: backgroundFrame.size).insetBy(dx: -10.0, dy: -10.0)
if let effectNode = self.effectNode {
let effectFrame = CGRect(origin: CGPoint(), size: backgroundFrame.size).insetBy(dx: -10.0, dy: -10.0)
transition.updateFrame(node: effectNode, frame: effectFrame)
effectNode.update(size: effectFrame.size, transition: transition)
}
@ -843,6 +850,69 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
transition.updateFrame(node: avatarNode, frame: avatarFrame)
avatarNode.updateSize(size: avatarFrame.size)
}
if self.isShimmering {
let shimmerContainerView: UIView
let shimmerView: ShimmerEffectForegroundView
if let currentContainer = self.shimmerContainerView, let current = self.shimmerView {
shimmerContainerView = currentContainer
shimmerView = current
} else {
shimmerContainerView = UIView()
shimmerView = ShimmerEffectForegroundView()
if let outerSnapshot = self.backgroundMaskNode.layer.snapshotContentTree(), let innerSnapshot = self.backgroundMaskNode.layer.snapshotContentTree() {
outerSnapshot.backgroundColor = UIColor.black.cgColor
func tintLayers(_ layer: CALayer, color: UIColor, scale: CGFloat) {
if let sublayers = layer.sublayers {
for layer in sublayers {
if let shapeLayer = layer as? CAShapeLayer {
shapeLayer.fillColor = color.cgColor
} else {
if layer.cornerRadius > 0.0 {
layer.backgroundColor = color.cgColor
layer.bounds = CGRect(origin: .zero, size: CGSize(width: layer.bounds.width * scale, height: layer.bounds.height))
}
tintLayers(layer, color: color, scale: scale)
}
}
}
}
tintLayers(outerSnapshot, color: .white, scale: 1.0)
tintLayers(innerSnapshot, color: .black, scale: 1.085)
outerSnapshot.addSublayer(innerSnapshot)
innerSnapshot.transform = CATransform3DMakeScale(0.9, 0.9, 1.0)
innerSnapshot.position = innerSnapshot.position.offsetBy(dx: 10.0, dy: 10.0)
if let filter = CALayer.luminanceToAlpha() {
outerSnapshot.filters = [filter]
}
shimmerContainerView.layer.mask = outerSnapshot
}
self.shimmerContainerView = shimmerContainerView
self.backgroundContainerNode.view.addSubview(shimmerContainerView)
let shimmerFrame = effectFrame.insetBy(dx: -60.0, dy: 0.0)
shimmerView.frame = shimmerFrame
shimmerView.update(backgroundColor: .clear, foregroundColor: UIColor.white.withAlphaComponent(0.4), gradientSize: 60.0, globalTimeOffset: false, duration: 2.2, horizontal: true)
shimmerView.updateAbsoluteRect(shimmerFrame, within: shimmerFrame.size)
shimmerContainerView.addSubview(shimmerView)
}
shimmerContainerView.frame = effectFrame.offsetBy(dx: 10.0, dy: 10.0)
} else if let shimmerContainerView = self.shimmerContainerView, let shimmerView = self.shimmerView {
self.shimmerContainerView = nil
self.shimmerView = nil
shimmerContainerView.removeFromSuperview()
shimmerView.removeFromSuperview()
}
}
private var didRequestDismiss = false
@ -1064,6 +1134,7 @@ public final class TooltipScreen: ViewController {
}
}
}
private let isShimmering: Bool
private let displayDuration: DisplayDuration
private let inset: CGFloat
private let cornerRadius: CGFloat?
@ -1098,6 +1169,7 @@ public final class TooltipScreen: ViewController {
action: TooltipScreen.Action? = nil,
location: TooltipScreen.Location,
displayDuration: DisplayDuration = .default,
isShimmering: Bool = false,
inset: CGFloat = 12.0,
cornerRadius: CGFloat? = nil,
shouldDismissOnTouch: @escaping (CGPoint, CGRect) -> TooltipScreen.DismissOnTouch,
@ -1116,6 +1188,7 @@ public final class TooltipScreen: ViewController {
self.action = action
self.location = location
self.displayDuration = displayDuration
self.isShimmering = isShimmering
self.inset = inset
self.cornerRadius = cornerRadius
self.shouldDismissOnTouch = shouldDismissOnTouch
@ -1177,7 +1250,7 @@ public final class TooltipScreen: ViewController {
}
override public func loadDisplayNode() {
self.displayNode = TooltipScreenNode(context: self.context, account: self.account, sharedContext: self.sharedContext, text: self.text, textAlignment: self.textAlignment, balancedTextLayout: self.balancedTextLayout, constrainWidth: self.constrainWidth, style: self.style, arrowStyle: self.arrowStyle, icon: self.icon, action: self.action, location: self.location, displayDuration: self.displayDuration, inset: self.inset, cornerRadius: self.cornerRadius, shouldDismissOnTouch: self.shouldDismissOnTouch, requestDismiss: { [weak self] in
self.displayNode = TooltipScreenNode(context: self.context, account: self.account, sharedContext: self.sharedContext, text: self.text, textAlignment: self.textAlignment, balancedTextLayout: self.balancedTextLayout, constrainWidth: self.constrainWidth, style: self.style, arrowStyle: self.arrowStyle, icon: self.icon, action: self.action, location: self.location, displayDuration: self.displayDuration, inset: self.inset, cornerRadius: self.cornerRadius, isShimmering: self.isShimmering, shouldDismissOnTouch: self.shouldDismissOnTouch, requestDismiss: { [weak self] in
guard let strongSelf = self else {
return
}