Update API

This commit is contained in:
Isaac 2025-10-15 17:06:40 +08:00
parent 751f4801d6
commit f468cea13c
33 changed files with 5221 additions and 3883 deletions

View File

@ -303,6 +303,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-29248689] = { return Api.GlobalPrivacySettings.parse_globalPrivacySettings($0) }
dict[1429932961] = { return Api.GroupCall.parse_groupCall($0) }
dict[2004925620] = { return Api.GroupCall.parse_groupCallDiscarded($0) }
dict[-2018173984] = { return Api.GroupCallMessage.parse_groupCallMessage($0) }
dict[708691884] = { return Api.GroupCallParticipant.parse_groupCallParticipant($0) }
dict[1735736008] = { return Api.GroupCallParticipantVideo.parse_groupCallParticipantVideo($0) }
dict[-592373577] = { return Api.GroupCallParticipantVideoSourceGroup.parse_groupCallParticipantVideoSourceGroup($0) }
@ -1112,7 +1113,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1535694705] = { return Api.Update.parse_updateGroupCallChainBlocks($0) }
dict[192428418] = { return Api.Update.parse_updateGroupCallConnection($0) }
dict[-917002394] = { return Api.Update.parse_updateGroupCallEncryptedMessage($0) }
dict[-964095818] = { return Api.Update.parse_updateGroupCallMessage($0) }
dict[-667783411] = { return Api.Update.parse_updateGroupCallMessage($0) }
dict[-219423922] = { return Api.Update.parse_updateGroupCallParticipants($0) }
dict[1763610706] = { return Api.Update.parse_updateInlineBotCallbackQuery($0) }
dict[1442983757] = { return Api.Update.parse_updateLangPack($0) }
@ -1816,6 +1817,8 @@ public extension Api {
_1.serialize(buffer, boxed)
case let _1 as Api.GroupCall:
_1.serialize(buffer, boxed)
case let _1 as Api.GroupCallMessage:
_1.serialize(buffer, boxed)
case let _1 as Api.GroupCallParticipant:
_1.serialize(buffer, boxed)
case let _1 as Api.GroupCallParticipantVideo:

View File

@ -1,3 +1,313 @@
public extension Api {
indirect enum InputFileLocation: TypeConstructorDescription {
case inputDocumentFileLocation(id: Int64, accessHash: Int64, fileReference: Buffer, thumbSize: String)
case inputEncryptedFileLocation(id: Int64, accessHash: Int64)
case inputFileLocation(volumeId: Int64, localId: Int32, secret: Int64, fileReference: Buffer)
case inputGroupCallStream(flags: Int32, call: Api.InputGroupCall, timeMs: Int64, scale: Int32, videoChannel: Int32?, videoQuality: Int32?)
case inputPeerPhotoFileLocation(flags: Int32, peer: Api.InputPeer, photoId: Int64)
case inputPhotoFileLocation(id: Int64, accessHash: Int64, fileReference: Buffer, thumbSize: String)
case inputPhotoLegacyFileLocation(id: Int64, accessHash: Int64, fileReference: Buffer, volumeId: Int64, localId: Int32, secret: Int64)
case inputSecureFileLocation(id: Int64, accessHash: Int64)
case inputStickerSetThumb(stickerset: Api.InputStickerSet, thumbVersion: Int32)
case inputTakeoutFileLocation
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .inputDocumentFileLocation(let id, let accessHash, let fileReference, let thumbSize):
if boxed {
buffer.appendInt32(-1160743548)
}
serializeInt64(id, buffer: buffer, boxed: false)
serializeInt64(accessHash, buffer: buffer, boxed: false)
serializeBytes(fileReference, buffer: buffer, boxed: false)
serializeString(thumbSize, buffer: buffer, boxed: false)
break
case .inputEncryptedFileLocation(let id, let accessHash):
if boxed {
buffer.appendInt32(-182231723)
}
serializeInt64(id, buffer: buffer, boxed: false)
serializeInt64(accessHash, buffer: buffer, boxed: false)
break
case .inputFileLocation(let volumeId, let localId, let secret, let fileReference):
if boxed {
buffer.appendInt32(-539317279)
}
serializeInt64(volumeId, buffer: buffer, boxed: false)
serializeInt32(localId, buffer: buffer, boxed: false)
serializeInt64(secret, buffer: buffer, boxed: false)
serializeBytes(fileReference, buffer: buffer, boxed: false)
break
case .inputGroupCallStream(let flags, let call, let timeMs, let scale, let videoChannel, let videoQuality):
if boxed {
buffer.appendInt32(93890858)
}
serializeInt32(flags, buffer: buffer, boxed: false)
call.serialize(buffer, true)
serializeInt64(timeMs, buffer: buffer, boxed: false)
serializeInt32(scale, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(videoChannel!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(videoQuality!, buffer: buffer, boxed: false)}
break
case .inputPeerPhotoFileLocation(let flags, let peer, let photoId):
if boxed {
buffer.appendInt32(925204121)
}
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeInt64(photoId, buffer: buffer, boxed: false)
break
case .inputPhotoFileLocation(let id, let accessHash, let fileReference, let thumbSize):
if boxed {
buffer.appendInt32(1075322878)
}
serializeInt64(id, buffer: buffer, boxed: false)
serializeInt64(accessHash, buffer: buffer, boxed: false)
serializeBytes(fileReference, buffer: buffer, boxed: false)
serializeString(thumbSize, buffer: buffer, boxed: false)
break
case .inputPhotoLegacyFileLocation(let id, let accessHash, let fileReference, let volumeId, let localId, let secret):
if boxed {
buffer.appendInt32(-667654413)
}
serializeInt64(id, buffer: buffer, boxed: false)
serializeInt64(accessHash, buffer: buffer, boxed: false)
serializeBytes(fileReference, buffer: buffer, boxed: false)
serializeInt64(volumeId, buffer: buffer, boxed: false)
serializeInt32(localId, buffer: buffer, boxed: false)
serializeInt64(secret, buffer: buffer, boxed: false)
break
case .inputSecureFileLocation(let id, let accessHash):
if boxed {
buffer.appendInt32(-876089816)
}
serializeInt64(id, buffer: buffer, boxed: false)
serializeInt64(accessHash, buffer: buffer, boxed: false)
break
case .inputStickerSetThumb(let stickerset, let thumbVersion):
if boxed {
buffer.appendInt32(-1652231205)
}
stickerset.serialize(buffer, true)
serializeInt32(thumbVersion, buffer: buffer, boxed: false)
break
case .inputTakeoutFileLocation:
if boxed {
buffer.appendInt32(700340377)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .inputDocumentFileLocation(let id, let accessHash, let fileReference, let thumbSize):
return ("inputDocumentFileLocation", [("id", id as Any), ("accessHash", accessHash as Any), ("fileReference", fileReference as Any), ("thumbSize", thumbSize as Any)])
case .inputEncryptedFileLocation(let id, let accessHash):
return ("inputEncryptedFileLocation", [("id", id as Any), ("accessHash", accessHash as Any)])
case .inputFileLocation(let volumeId, let localId, let secret, let fileReference):
return ("inputFileLocation", [("volumeId", volumeId as Any), ("localId", localId as Any), ("secret", secret as Any), ("fileReference", fileReference as Any)])
case .inputGroupCallStream(let flags, let call, let timeMs, let scale, let videoChannel, let videoQuality):
return ("inputGroupCallStream", [("flags", flags as Any), ("call", call as Any), ("timeMs", timeMs as Any), ("scale", scale as Any), ("videoChannel", videoChannel as Any), ("videoQuality", videoQuality as Any)])
case .inputPeerPhotoFileLocation(let flags, let peer, let photoId):
return ("inputPeerPhotoFileLocation", [("flags", flags as Any), ("peer", peer as Any), ("photoId", photoId as Any)])
case .inputPhotoFileLocation(let id, let accessHash, let fileReference, let thumbSize):
return ("inputPhotoFileLocation", [("id", id as Any), ("accessHash", accessHash as Any), ("fileReference", fileReference as Any), ("thumbSize", thumbSize as Any)])
case .inputPhotoLegacyFileLocation(let id, let accessHash, let fileReference, let volumeId, let localId, let secret):
return ("inputPhotoLegacyFileLocation", [("id", id as Any), ("accessHash", accessHash as Any), ("fileReference", fileReference as Any), ("volumeId", volumeId as Any), ("localId", localId as Any), ("secret", secret as Any)])
case .inputSecureFileLocation(let id, let accessHash):
return ("inputSecureFileLocation", [("id", id as Any), ("accessHash", accessHash as Any)])
case .inputStickerSetThumb(let stickerset, let thumbVersion):
return ("inputStickerSetThumb", [("stickerset", stickerset as Any), ("thumbVersion", thumbVersion as Any)])
case .inputTakeoutFileLocation:
return ("inputTakeoutFileLocation", [])
}
}
public static func parse_inputDocumentFileLocation(_ reader: BufferReader) -> InputFileLocation? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int64?
_2 = reader.readInt64()
var _3: Buffer?
_3 = parseBytes(reader)
var _4: String?
_4 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.InputFileLocation.inputDocumentFileLocation(id: _1!, accessHash: _2!, fileReference: _3!, thumbSize: _4!)
}
else {
return nil
}
}
public static func parse_inputEncryptedFileLocation(_ reader: BufferReader) -> InputFileLocation? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int64?
_2 = reader.readInt64()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.InputFileLocation.inputEncryptedFileLocation(id: _1!, accessHash: _2!)
}
else {
return nil
}
}
public static func parse_inputFileLocation(_ reader: BufferReader) -> InputFileLocation? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int64?
_3 = reader.readInt64()
var _4: Buffer?
_4 = parseBytes(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.InputFileLocation.inputFileLocation(volumeId: _1!, localId: _2!, secret: _3!, fileReference: _4!)
}
else {
return nil
}
}
public static func parse_inputGroupCallStream(_ reader: BufferReader) -> InputFileLocation? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.InputGroupCall?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.InputGroupCall
}
var _3: Int64?
_3 = reader.readInt64()
var _4: Int32?
_4 = reader.readInt32()
var _5: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_5 = reader.readInt32() }
var _6: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_6 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.InputFileLocation.inputGroupCallStream(flags: _1!, call: _2!, timeMs: _3!, scale: _4!, videoChannel: _5, videoQuality: _6)
}
else {
return nil
}
}
public static func parse_inputPeerPhotoFileLocation(_ reader: BufferReader) -> InputFileLocation? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.InputPeer?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.InputPeer
}
var _3: Int64?
_3 = reader.readInt64()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.InputFileLocation.inputPeerPhotoFileLocation(flags: _1!, peer: _2!, photoId: _3!)
}
else {
return nil
}
}
public static func parse_inputPhotoFileLocation(_ reader: BufferReader) -> InputFileLocation? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int64?
_2 = reader.readInt64()
var _3: Buffer?
_3 = parseBytes(reader)
var _4: String?
_4 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.InputFileLocation.inputPhotoFileLocation(id: _1!, accessHash: _2!, fileReference: _3!, thumbSize: _4!)
}
else {
return nil
}
}
public static func parse_inputPhotoLegacyFileLocation(_ reader: BufferReader) -> InputFileLocation? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int64?
_2 = reader.readInt64()
var _3: Buffer?
_3 = parseBytes(reader)
var _4: Int64?
_4 = reader.readInt64()
var _5: Int32?
_5 = reader.readInt32()
var _6: Int64?
_6 = reader.readInt64()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.InputFileLocation.inputPhotoLegacyFileLocation(id: _1!, accessHash: _2!, fileReference: _3!, volumeId: _4!, localId: _5!, secret: _6!)
}
else {
return nil
}
}
public static func parse_inputSecureFileLocation(_ reader: BufferReader) -> InputFileLocation? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int64?
_2 = reader.readInt64()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.InputFileLocation.inputSecureFileLocation(id: _1!, accessHash: _2!)
}
else {
return nil
}
}
public static func parse_inputStickerSetThumb(_ reader: BufferReader) -> InputFileLocation? {
var _1: Api.InputStickerSet?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.InputStickerSet
}
var _2: Int32?
_2 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.InputFileLocation.inputStickerSetThumb(stickerset: _1!, thumbVersion: _2!)
}
else {
return nil
}
}
public static func parse_inputTakeoutFileLocation(_ reader: BufferReader) -> InputFileLocation? {
return Api.InputFileLocation.inputTakeoutFileLocation
}
}
}
public extension Api {
indirect enum InputFolderPeer: TypeConstructorDescription {
case inputFolderPeer(peer: Api.InputPeer, folderId: Int32)
@ -630,681 +940,3 @@ public extension Api {
}
}
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?, 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?)
case inputMediaGeoPoint(geoPoint: Api.InputGeoPoint)
case inputMediaInvoice(flags: Int32, title: String, description: String, photo: Api.InputWebDocument?, invoice: Api.Invoice, payload: Buffer, provider: String?, providerData: Api.DataJSON, startParam: String?, extendedMedia: Api.InputMedia?)
case inputMediaPaidMedia(flags: Int32, starsAmount: Int64, extendedMedia: [Api.InputMedia], payload: String?)
case inputMediaPhoto(flags: Int32, id: Api.InputPhoto, ttlSeconds: Int32?)
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 inputMediaTodo(todo: Api.TodoList)
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)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .inputMediaContact(let phoneNumber, let firstName, let lastName, let vcard):
if boxed {
buffer.appendInt32(-122978821)
}
serializeString(phoneNumber, buffer: buffer, boxed: false)
serializeString(firstName, buffer: buffer, boxed: false)
serializeString(lastName, buffer: buffer, boxed: false)
serializeString(vcard, buffer: buffer, boxed: false)
break
case .inputMediaDice(let emoticon):
if boxed {
buffer.appendInt32(-428884101)
}
serializeString(emoticon, buffer: buffer, boxed: false)
break
case .inputMediaDocument(let flags, let id, let videoCover, let videoTimestamp, let ttlSeconds, let query):
if boxed {
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, let videoTimestamp):
if boxed {
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 {
buffer.appendInt32(-1771768449)
}
break
case .inputMediaGame(let id):
if boxed {
buffer.appendInt32(-750828557)
}
id.serialize(buffer, true)
break
case .inputMediaGeoLive(let flags, let geoPoint, let heading, let period, let proximityNotificationRadius):
if boxed {
buffer.appendInt32(-1759532989)
}
serializeInt32(flags, buffer: buffer, boxed: false)
geoPoint.serialize(buffer, true)
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(heading!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(period!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 3) != 0 {serializeInt32(proximityNotificationRadius!, buffer: buffer, boxed: false)}
break
case .inputMediaGeoPoint(let geoPoint):
if boxed {
buffer.appendInt32(-104578748)
}
geoPoint.serialize(buffer, true)
break
case .inputMediaInvoice(let flags, let title, let description, let photo, let invoice, let payload, let provider, let providerData, let startParam, let extendedMedia):
if boxed {
buffer.appendInt32(1080028941)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(title, buffer: buffer, boxed: false)
serializeString(description, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {photo!.serialize(buffer, true)}
invoice.serialize(buffer, true)
serializeBytes(payload, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 3) != 0 {serializeString(provider!, buffer: buffer, boxed: false)}
providerData.serialize(buffer, true)
if Int(flags) & Int(1 << 1) != 0 {serializeString(startParam!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {extendedMedia!.serialize(buffer, true)}
break
case .inputMediaPaidMedia(let flags, let starsAmount, let extendedMedia, let payload):
if boxed {
buffer.appendInt32(-1005571194)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(starsAmount, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(extendedMedia.count))
for item in extendedMedia {
item.serialize(buffer, true)
}
if Int(flags) & Int(1 << 0) != 0 {serializeString(payload!, buffer: buffer, boxed: false)}
break
case .inputMediaPhoto(let flags, let id, let ttlSeconds):
if boxed {
buffer.appendInt32(-1279654347)
}
serializeInt32(flags, buffer: buffer, boxed: false)
id.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(ttlSeconds!, buffer: buffer, boxed: false)}
break
case .inputMediaPhotoExternal(let flags, let url, let ttlSeconds):
if boxed {
buffer.appendInt32(-440664550)
}
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)}
break
case .inputMediaPoll(let flags, let poll, let correctAnswers, let solution, let solutionEntities):
if boxed {
buffer.appendInt32(261416433)
}
serializeInt32(flags, buffer: buffer, boxed: false)
poll.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(correctAnswers!.count))
for item in correctAnswers! {
serializeBytes(item, buffer: buffer, boxed: false)
}}
if Int(flags) & Int(1 << 1) != 0 {serializeString(solution!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(solutionEntities!.count))
for item in solutionEntities! {
item.serialize(buffer, true)
}}
break
case .inputMediaStory(let peer, let id):
if boxed {
buffer.appendInt32(-1979852936)
}
peer.serialize(buffer, true)
serializeInt32(id, buffer: buffer, boxed: false)
break
case .inputMediaTodo(let todo):
if boxed {
buffer.appendInt32(-1614454818)
}
todo.serialize(buffer, true)
break
case .inputMediaUploadedDocument(let flags, let file, let thumb, let mimeType, let attributes, let stickers, let videoCover, let videoTimestamp, let ttlSeconds):
if boxed {
buffer.appendInt32(58495792)
}
serializeInt32(flags, buffer: buffer, boxed: false)
file.serialize(buffer, true)
if Int(flags) & Int(1 << 2) != 0 {thumb!.serialize(buffer, true)}
serializeString(mimeType, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(attributes.count))
for item in attributes {
item.serialize(buffer, true)
}
if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(stickers!.count))
for item in stickers! {
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):
if boxed {
buffer.appendInt32(505969924)
}
serializeInt32(flags, buffer: buffer, boxed: false)
file.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(stickers!.count))
for item in stickers! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(ttlSeconds!, buffer: buffer, boxed: false)}
break
case .inputMediaVenue(let geoPoint, let title, let address, let provider, let venueId, let venueType):
if boxed {
buffer.appendInt32(-1052959727)
}
geoPoint.serialize(buffer, true)
serializeString(title, buffer: buffer, boxed: false)
serializeString(address, buffer: buffer, boxed: false)
serializeString(provider, buffer: buffer, boxed: false)
serializeString(venueId, buffer: buffer, boxed: false)
serializeString(venueType, buffer: buffer, boxed: false)
break
case .inputMediaWebPage(let flags, let url):
if boxed {
buffer.appendInt32(-1038383031)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(url, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .inputMediaContact(let phoneNumber, let firstName, let lastName, let vcard):
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 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):
return ("inputMediaGame", [("id", id as Any)])
case .inputMediaGeoLive(let flags, let geoPoint, let heading, let period, let proximityNotificationRadius):
return ("inputMediaGeoLive", [("flags", flags as Any), ("geoPoint", geoPoint as Any), ("heading", heading as Any), ("period", period as Any), ("proximityNotificationRadius", proximityNotificationRadius as Any)])
case .inputMediaGeoPoint(let geoPoint):
return ("inputMediaGeoPoint", [("geoPoint", geoPoint as Any)])
case .inputMediaInvoice(let flags, let title, let description, let photo, let invoice, let payload, let provider, let providerData, let startParam, let extendedMedia):
return ("inputMediaInvoice", [("flags", flags as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("invoice", invoice as Any), ("payload", payload as Any), ("provider", provider as Any), ("providerData", providerData as Any), ("startParam", startParam as Any), ("extendedMedia", extendedMedia as Any)])
case .inputMediaPaidMedia(let flags, let starsAmount, let extendedMedia, let payload):
return ("inputMediaPaidMedia", [("flags", flags as Any), ("starsAmount", starsAmount as Any), ("extendedMedia", extendedMedia as Any), ("payload", payload as Any)])
case .inputMediaPhoto(let flags, let id, let ttlSeconds):
return ("inputMediaPhoto", [("flags", flags as Any), ("id", id as Any), ("ttlSeconds", ttlSeconds as Any)])
case .inputMediaPhotoExternal(let flags, let url, let ttlSeconds):
return ("inputMediaPhotoExternal", [("flags", flags as Any), ("url", url as Any), ("ttlSeconds", ttlSeconds as Any)])
case .inputMediaPoll(let flags, let poll, let correctAnswers, let solution, let solutionEntities):
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 .inputMediaTodo(let todo):
return ("inputMediaTodo", [("todo", todo 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):
return ("inputMediaVenue", [("geoPoint", geoPoint as Any), ("title", title as Any), ("address", address as Any), ("provider", provider as Any), ("venueId", venueId as Any), ("venueType", venueType as Any)])
case .inputMediaWebPage(let flags, let url):
return ("inputMediaWebPage", [("flags", flags as Any), ("url", url as Any)])
}
}
public static func parse_inputMediaContact(_ reader: BufferReader) -> InputMedia? {
var _1: String?
_1 = parseString(reader)
var _2: String?
_2 = parseString(reader)
var _3: String?
_3 = parseString(reader)
var _4: String?
_4 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.InputMedia.inputMediaContact(phoneNumber: _1!, firstName: _2!, lastName: _3!, vcard: _4!)
}
else {
return nil
}
}
public static func parse_inputMediaDice(_ reader: BufferReader) -> InputMedia? {
var _1: String?
_1 = parseString(reader)
let _c1 = _1 != nil
if _c1 {
return Api.InputMedia.inputMediaDice(emoticon: _1!)
}
else {
return nil
}
}
public static func parse_inputMediaDocument(_ reader: BufferReader) -> InputMedia? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.InputDocument?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.InputDocument
}
var _3: Api.InputPhoto?
if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.InputPhoto
} }
var _4: Int32?
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 << 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
}
}
public static func parse_inputMediaDocumentExternal(_ reader: BufferReader) -> InputMedia? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() }
var _4: Api.InputPhoto?
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
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
}
}
public static func parse_inputMediaEmpty(_ reader: BufferReader) -> InputMedia? {
return Api.InputMedia.inputMediaEmpty
}
public static func parse_inputMediaGame(_ reader: BufferReader) -> InputMedia? {
var _1: Api.InputGame?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.InputGame
}
let _c1 = _1 != nil
if _c1 {
return Api.InputMedia.inputMediaGame(id: _1!)
}
else {
return nil
}
}
public static func parse_inputMediaGeoLive(_ reader: BufferReader) -> InputMedia? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.InputGeoPoint?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.InputGeoPoint
}
var _3: Int32?
if Int(_1!) & Int(1 << 2) != 0 {_3 = reader.readInt32() }
var _4: Int32?
if Int(_1!) & Int(1 << 1) != 0 {_4 = reader.readInt32() }
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 << 2) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.InputMedia.inputMediaGeoLive(flags: _1!, geoPoint: _2!, heading: _3, period: _4, proximityNotificationRadius: _5)
}
else {
return nil
}
}
public static func parse_inputMediaGeoPoint(_ reader: BufferReader) -> InputMedia? {
var _1: Api.InputGeoPoint?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.InputGeoPoint
}
let _c1 = _1 != nil
if _c1 {
return Api.InputMedia.inputMediaGeoPoint(geoPoint: _1!)
}
else {
return nil
}
}
public static func parse_inputMediaInvoice(_ reader: BufferReader) -> InputMedia? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: String?
_3 = parseString(reader)
var _4: Api.InputWebDocument?
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.InputWebDocument
} }
var _5: Api.Invoice?
if let signature = reader.readInt32() {
_5 = Api.parse(reader, signature: signature) as? Api.Invoice
}
var _6: Buffer?
_6 = parseBytes(reader)
var _7: String?
if Int(_1!) & Int(1 << 3) != 0 {_7 = parseString(reader) }
var _8: Api.DataJSON?
if let signature = reader.readInt32() {
_8 = Api.parse(reader, signature: signature) as? Api.DataJSON
}
var _9: String?
if Int(_1!) & Int(1 << 1) != 0 {_9 = parseString(reader) }
var _10: Api.InputMedia?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_10 = Api.parse(reader, signature: signature) as? Api.InputMedia
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
let _c7 = (Int(_1!) & Int(1 << 3) == 0) || _7 != nil
let _c8 = _8 != nil
let _c9 = (Int(_1!) & Int(1 << 1) == 0) || _9 != nil
let _c10 = (Int(_1!) & Int(1 << 2) == 0) || _10 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 {
return Api.InputMedia.inputMediaInvoice(flags: _1!, title: _2!, description: _3!, photo: _4, invoice: _5!, payload: _6!, provider: _7, providerData: _8!, startParam: _9, extendedMedia: _10)
}
else {
return nil
}
}
public static func parse_inputMediaPaidMedia(_ reader: BufferReader) -> InputMedia? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
var _3: [Api.InputMedia]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputMedia.self)
}
var _4: String?
if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.InputMedia.inputMediaPaidMedia(flags: _1!, starsAmount: _2!, extendedMedia: _3!, payload: _4)
}
else {
return nil
}
}
public static func parse_inputMediaPhoto(_ reader: BufferReader) -> InputMedia? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.InputPhoto?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.InputPhoto
}
var _3: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
if _c1 && _c2 && _c3 {
return Api.InputMedia.inputMediaPhoto(flags: _1!, id: _2!, ttlSeconds: _3)
}
else {
return nil
}
}
public static func parse_inputMediaPhotoExternal(_ reader: BufferReader) -> InputMedia? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
if _c1 && _c2 && _c3 {
return Api.InputMedia.inputMediaPhotoExternal(flags: _1!, url: _2!, ttlSeconds: _3)
}
else {
return nil
}
}
public static func parse_inputMediaPoll(_ reader: BufferReader) -> InputMedia? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Poll?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Poll
}
var _3: [Buffer]?
if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: -1255641564, elementType: Buffer.self)
} }
var _4: String?
if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) }
var _5: [Api.MessageEntity]?
if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.InputMedia.inputMediaPoll(flags: _1!, poll: _2!, correctAnswers: _3, solution: _4, solutionEntities: _5)
}
else {
return nil
}
}
public static func parse_inputMediaStory(_ reader: BufferReader) -> InputMedia? {
var _1: Api.InputPeer?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.InputPeer
}
var _2: Int32?
_2 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.InputMedia.inputMediaStory(peer: _1!, id: _2!)
}
else {
return nil
}
}
public static func parse_inputMediaTodo(_ reader: BufferReader) -> InputMedia? {
var _1: Api.TodoList?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.TodoList
}
let _c1 = _1 != nil
if _c1 {
return Api.InputMedia.inputMediaTodo(todo: _1!)
}
else {
return nil
}
}
public static func parse_inputMediaUploadedDocument(_ reader: BufferReader) -> InputMedia? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.InputFile?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.InputFile
}
var _3: Api.InputFile?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.InputFile
} }
var _4: String?
_4 = parseString(reader)
var _5: [Api.DocumentAttribute]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.DocumentAttribute.self)
}
var _6: [Api.InputDocument]?
if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputDocument.self)
} }
var _7: Api.InputPhoto?
if Int(_1!) & Int(1 << 6) != 0 {if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.InputPhoto
} }
var _8: Int32?
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
let _c4 = _4 != nil
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 << 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
}
}
public static func parse_inputMediaUploadedPhoto(_ reader: BufferReader) -> InputMedia? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.InputFile?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.InputFile
}
var _3: [Api.InputDocument]?
if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputDocument.self)
} }
var _4: Int32?
if Int(_1!) & Int(1 << 1) != 0 {_4 = 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 << 1) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.InputMedia.inputMediaUploadedPhoto(flags: _1!, file: _2!, stickers: _3, ttlSeconds: _4)
}
else {
return nil
}
}
public static func parse_inputMediaVenue(_ reader: BufferReader) -> InputMedia? {
var _1: Api.InputGeoPoint?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.InputGeoPoint
}
var _2: String?
_2 = parseString(reader)
var _3: String?
_3 = parseString(reader)
var _4: String?
_4 = parseString(reader)
var _5: String?
_5 = parseString(reader)
var _6: String?
_6 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.InputMedia.inputMediaVenue(geoPoint: _1!, title: _2!, address: _3!, provider: _4!, venueId: _5!, venueType: _6!)
}
else {
return nil
}
}
public static func parse_inputMediaWebPage(_ reader: BufferReader) -> InputMedia? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.InputMedia.inputMediaWebPage(flags: _1!, url: _2!)
}
else {
return nil
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,675 @@
public extension Api {
enum KeyboardButtonRow: TypeConstructorDescription {
case keyboardButtonRow(buttons: [Api.KeyboardButton])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .keyboardButtonRow(let buttons):
if boxed {
buffer.appendInt32(2002815875)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(buttons.count))
for item in buttons {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .keyboardButtonRow(let buttons):
return ("keyboardButtonRow", [("buttons", buttons as Any)])
}
}
public static func parse_keyboardButtonRow(_ reader: BufferReader) -> KeyboardButtonRow? {
var _1: [Api.KeyboardButton]?
if let _ = reader.readInt32() {
_1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.KeyboardButton.self)
}
let _c1 = _1 != nil
if _c1 {
return Api.KeyboardButtonRow.keyboardButtonRow(buttons: _1!)
}
else {
return nil
}
}
}
}
public extension Api {
enum LabeledPrice: TypeConstructorDescription {
case labeledPrice(label: String, amount: Int64)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .labeledPrice(let label, let amount):
if boxed {
buffer.appendInt32(-886477832)
}
serializeString(label, buffer: buffer, boxed: false)
serializeInt64(amount, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .labeledPrice(let label, let amount):
return ("labeledPrice", [("label", label as Any), ("amount", amount as Any)])
}
}
public static func parse_labeledPrice(_ reader: BufferReader) -> LabeledPrice? {
var _1: String?
_1 = parseString(reader)
var _2: Int64?
_2 = reader.readInt64()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.LabeledPrice.labeledPrice(label: _1!, amount: _2!)
}
else {
return nil
}
}
}
}
public extension Api {
enum LangPackDifference: TypeConstructorDescription {
case langPackDifference(langCode: String, fromVersion: Int32, version: Int32, strings: [Api.LangPackString])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .langPackDifference(let langCode, let fromVersion, let version, let strings):
if boxed {
buffer.appendInt32(-209337866)
}
serializeString(langCode, buffer: buffer, boxed: false)
serializeInt32(fromVersion, buffer: buffer, boxed: false)
serializeInt32(version, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(strings.count))
for item in strings {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .langPackDifference(let langCode, let fromVersion, let version, let strings):
return ("langPackDifference", [("langCode", langCode as Any), ("fromVersion", fromVersion as Any), ("version", version as Any), ("strings", strings as Any)])
}
}
public static func parse_langPackDifference(_ reader: BufferReader) -> LangPackDifference? {
var _1: String?
_1 = parseString(reader)
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
var _4: [Api.LangPackString]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.LangPackString.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.LangPackDifference.langPackDifference(langCode: _1!, fromVersion: _2!, version: _3!, strings: _4!)
}
else {
return nil
}
}
}
}
public extension Api {
enum LangPackLanguage: TypeConstructorDescription {
case langPackLanguage(flags: Int32, name: String, nativeName: String, langCode: String, baseLangCode: String?, pluralCode: String, stringsCount: Int32, translatedCount: Int32, translationsUrl: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .langPackLanguage(let flags, let name, let nativeName, let langCode, let baseLangCode, let pluralCode, let stringsCount, let translatedCount, let translationsUrl):
if boxed {
buffer.appendInt32(-288727837)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(name, buffer: buffer, boxed: false)
serializeString(nativeName, buffer: buffer, boxed: false)
serializeString(langCode, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {serializeString(baseLangCode!, buffer: buffer, boxed: false)}
serializeString(pluralCode, buffer: buffer, boxed: false)
serializeInt32(stringsCount, buffer: buffer, boxed: false)
serializeInt32(translatedCount, buffer: buffer, boxed: false)
serializeString(translationsUrl, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .langPackLanguage(let flags, let name, let nativeName, let langCode, let baseLangCode, let pluralCode, let stringsCount, let translatedCount, let translationsUrl):
return ("langPackLanguage", [("flags", flags as Any), ("name", name as Any), ("nativeName", nativeName as Any), ("langCode", langCode as Any), ("baseLangCode", baseLangCode as Any), ("pluralCode", pluralCode as Any), ("stringsCount", stringsCount as Any), ("translatedCount", translatedCount as Any), ("translationsUrl", translationsUrl as Any)])
}
}
public static func parse_langPackLanguage(_ reader: BufferReader) -> LangPackLanguage? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: String?
_3 = parseString(reader)
var _4: String?
_4 = parseString(reader)
var _5: String?
if Int(_1!) & Int(1 << 1) != 0 {_5 = parseString(reader) }
var _6: String?
_6 = parseString(reader)
var _7: Int32?
_7 = reader.readInt32()
var _8: Int32?
_8 = reader.readInt32()
var _9: String?
_9 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
let _c8 = _8 != nil
let _c9 = _9 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
return Api.LangPackLanguage.langPackLanguage(flags: _1!, name: _2!, nativeName: _3!, langCode: _4!, baseLangCode: _5, pluralCode: _6!, stringsCount: _7!, translatedCount: _8!, translationsUrl: _9!)
}
else {
return nil
}
}
}
}
public extension Api {
enum LangPackString: TypeConstructorDescription {
case langPackString(key: String, value: String)
case langPackStringDeleted(key: String)
case langPackStringPluralized(flags: Int32, key: String, zeroValue: String?, oneValue: String?, twoValue: String?, fewValue: String?, manyValue: String?, otherValue: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .langPackString(let key, let value):
if boxed {
buffer.appendInt32(-892239370)
}
serializeString(key, buffer: buffer, boxed: false)
serializeString(value, buffer: buffer, boxed: false)
break
case .langPackStringDeleted(let key):
if boxed {
buffer.appendInt32(695856818)
}
serializeString(key, buffer: buffer, boxed: false)
break
case .langPackStringPluralized(let flags, let key, let zeroValue, let oneValue, let twoValue, let fewValue, let manyValue, let otherValue):
if boxed {
buffer.appendInt32(1816636575)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(key, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeString(zeroValue!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {serializeString(oneValue!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {serializeString(twoValue!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 3) != 0 {serializeString(fewValue!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 4) != 0 {serializeString(manyValue!, buffer: buffer, boxed: false)}
serializeString(otherValue, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .langPackString(let key, let value):
return ("langPackString", [("key", key as Any), ("value", value as Any)])
case .langPackStringDeleted(let key):
return ("langPackStringDeleted", [("key", key as Any)])
case .langPackStringPluralized(let flags, let key, let zeroValue, let oneValue, let twoValue, let fewValue, let manyValue, let otherValue):
return ("langPackStringPluralized", [("flags", flags as Any), ("key", key as Any), ("zeroValue", zeroValue as Any), ("oneValue", oneValue as Any), ("twoValue", twoValue as Any), ("fewValue", fewValue as Any), ("manyValue", manyValue as Any), ("otherValue", otherValue as Any)])
}
}
public static func parse_langPackString(_ reader: BufferReader) -> LangPackString? {
var _1: String?
_1 = parseString(reader)
var _2: String?
_2 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.LangPackString.langPackString(key: _1!, value: _2!)
}
else {
return nil
}
}
public static func parse_langPackStringDeleted(_ reader: BufferReader) -> LangPackString? {
var _1: String?
_1 = parseString(reader)
let _c1 = _1 != nil
if _c1 {
return Api.LangPackString.langPackStringDeleted(key: _1!)
}
else {
return nil
}
}
public static func parse_langPackStringPluralized(_ reader: BufferReader) -> LangPackString? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: String?
if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) }
var _4: String?
if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) }
var _5: String?
if Int(_1!) & Int(1 << 2) != 0 {_5 = parseString(reader) }
var _6: String?
if Int(_1!) & Int(1 << 3) != 0 {_6 = parseString(reader) }
var _7: String?
if Int(_1!) & Int(1 << 4) != 0 {_7 = parseString(reader) }
var _8: String?
_8 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil
let _c7 = (Int(_1!) & Int(1 << 4) == 0) || _7 != nil
let _c8 = _8 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
return Api.LangPackString.langPackStringPluralized(flags: _1!, key: _2!, zeroValue: _3, oneValue: _4, twoValue: _5, fewValue: _6, manyValue: _7, otherValue: _8!)
}
else {
return nil
}
}
}
}
public extension Api {
enum MaskCoords: TypeConstructorDescription {
case maskCoords(n: Int32, x: Double, y: Double, zoom: Double)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .maskCoords(let n, let x, let y, let zoom):
if boxed {
buffer.appendInt32(-1361650766)
}
serializeInt32(n, buffer: buffer, boxed: false)
serializeDouble(x, buffer: buffer, boxed: false)
serializeDouble(y, buffer: buffer, boxed: false)
serializeDouble(zoom, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .maskCoords(let n, let x, let y, let zoom):
return ("maskCoords", [("n", n as Any), ("x", x as Any), ("y", y as Any), ("zoom", zoom as Any)])
}
}
public static func parse_maskCoords(_ reader: BufferReader) -> MaskCoords? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Double?
_2 = reader.readDouble()
var _3: Double?
_3 = reader.readDouble()
var _4: Double?
_4 = reader.readDouble()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.MaskCoords.maskCoords(n: _1!, x: _2!, y: _3!, zoom: _4!)
}
else {
return nil
}
}
}
}
public extension Api {
indirect enum MediaArea: TypeConstructorDescription {
case inputMediaAreaChannelPost(coordinates: Api.MediaAreaCoordinates, channel: Api.InputChannel, msgId: Int32)
case inputMediaAreaVenue(coordinates: Api.MediaAreaCoordinates, queryId: Int64, resultId: String)
case mediaAreaChannelPost(coordinates: Api.MediaAreaCoordinates, channelId: Int64, msgId: Int32)
case mediaAreaGeoPoint(flags: Int32, coordinates: Api.MediaAreaCoordinates, geo: Api.GeoPoint, address: Api.GeoPointAddress?)
case mediaAreaStarGift(coordinates: Api.MediaAreaCoordinates, slug: String)
case mediaAreaSuggestedReaction(flags: Int32, coordinates: Api.MediaAreaCoordinates, reaction: Api.Reaction)
case mediaAreaUrl(coordinates: Api.MediaAreaCoordinates, url: String)
case mediaAreaVenue(coordinates: Api.MediaAreaCoordinates, geo: Api.GeoPoint, title: String, address: String, provider: String, venueId: String, venueType: String)
case mediaAreaWeather(coordinates: Api.MediaAreaCoordinates, emoji: String, temperatureC: Double, color: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .inputMediaAreaChannelPost(let coordinates, let channel, let msgId):
if boxed {
buffer.appendInt32(577893055)
}
coordinates.serialize(buffer, true)
channel.serialize(buffer, true)
serializeInt32(msgId, buffer: buffer, boxed: false)
break
case .inputMediaAreaVenue(let coordinates, let queryId, let resultId):
if boxed {
buffer.appendInt32(-1300094593)
}
coordinates.serialize(buffer, true)
serializeInt64(queryId, buffer: buffer, boxed: false)
serializeString(resultId, buffer: buffer, boxed: false)
break
case .mediaAreaChannelPost(let coordinates, let channelId, let msgId):
if boxed {
buffer.appendInt32(1996756655)
}
coordinates.serialize(buffer, true)
serializeInt64(channelId, buffer: buffer, boxed: false)
serializeInt32(msgId, buffer: buffer, boxed: false)
break
case .mediaAreaGeoPoint(let flags, let coordinates, let geo, let address):
if boxed {
buffer.appendInt32(-891992787)
}
serializeInt32(flags, buffer: buffer, boxed: false)
coordinates.serialize(buffer, true)
geo.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {address!.serialize(buffer, true)}
break
case .mediaAreaStarGift(let coordinates, let slug):
if boxed {
buffer.appendInt32(1468491885)
}
coordinates.serialize(buffer, true)
serializeString(slug, buffer: buffer, boxed: false)
break
case .mediaAreaSuggestedReaction(let flags, let coordinates, let reaction):
if boxed {
buffer.appendInt32(340088945)
}
serializeInt32(flags, buffer: buffer, boxed: false)
coordinates.serialize(buffer, true)
reaction.serialize(buffer, true)
break
case .mediaAreaUrl(let coordinates, let url):
if boxed {
buffer.appendInt32(926421125)
}
coordinates.serialize(buffer, true)
serializeString(url, buffer: buffer, boxed: false)
break
case .mediaAreaVenue(let coordinates, let geo, let title, let address, let provider, let venueId, let venueType):
if boxed {
buffer.appendInt32(-1098720356)
}
coordinates.serialize(buffer, true)
geo.serialize(buffer, true)
serializeString(title, buffer: buffer, boxed: false)
serializeString(address, buffer: buffer, boxed: false)
serializeString(provider, buffer: buffer, boxed: false)
serializeString(venueId, buffer: buffer, boxed: false)
serializeString(venueType, buffer: buffer, boxed: false)
break
case .mediaAreaWeather(let coordinates, let emoji, let temperatureC, let color):
if boxed {
buffer.appendInt32(1235637404)
}
coordinates.serialize(buffer, true)
serializeString(emoji, buffer: buffer, boxed: false)
serializeDouble(temperatureC, buffer: buffer, boxed: false)
serializeInt32(color, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .inputMediaAreaChannelPost(let coordinates, let channel, let msgId):
return ("inputMediaAreaChannelPost", [("coordinates", coordinates as Any), ("channel", channel as Any), ("msgId", msgId as Any)])
case .inputMediaAreaVenue(let coordinates, let queryId, let resultId):
return ("inputMediaAreaVenue", [("coordinates", coordinates as Any), ("queryId", queryId as Any), ("resultId", resultId as Any)])
case .mediaAreaChannelPost(let coordinates, let channelId, let msgId):
return ("mediaAreaChannelPost", [("coordinates", coordinates as Any), ("channelId", channelId as Any), ("msgId", msgId as Any)])
case .mediaAreaGeoPoint(let flags, let coordinates, let geo, let address):
return ("mediaAreaGeoPoint", [("flags", flags as Any), ("coordinates", coordinates as Any), ("geo", geo as Any), ("address", address as Any)])
case .mediaAreaStarGift(let coordinates, let slug):
return ("mediaAreaStarGift", [("coordinates", coordinates as Any), ("slug", slug as Any)])
case .mediaAreaSuggestedReaction(let flags, let coordinates, let reaction):
return ("mediaAreaSuggestedReaction", [("flags", flags as Any), ("coordinates", coordinates as Any), ("reaction", reaction as Any)])
case .mediaAreaUrl(let coordinates, let url):
return ("mediaAreaUrl", [("coordinates", coordinates as Any), ("url", url as Any)])
case .mediaAreaVenue(let coordinates, let geo, let title, let address, let provider, let venueId, let venueType):
return ("mediaAreaVenue", [("coordinates", coordinates as Any), ("geo", geo as Any), ("title", title as Any), ("address", address as Any), ("provider", provider as Any), ("venueId", venueId as Any), ("venueType", venueType as Any)])
case .mediaAreaWeather(let coordinates, let emoji, let temperatureC, let color):
return ("mediaAreaWeather", [("coordinates", coordinates as Any), ("emoji", emoji as Any), ("temperatureC", temperatureC as Any), ("color", color as Any)])
}
}
public static func parse_inputMediaAreaChannelPost(_ reader: BufferReader) -> MediaArea? {
var _1: Api.MediaAreaCoordinates?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.MediaAreaCoordinates
}
var _2: Api.InputChannel?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.InputChannel
}
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.MediaArea.inputMediaAreaChannelPost(coordinates: _1!, channel: _2!, msgId: _3!)
}
else {
return nil
}
}
public static func parse_inputMediaAreaVenue(_ reader: BufferReader) -> MediaArea? {
var _1: Api.MediaAreaCoordinates?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.MediaAreaCoordinates
}
var _2: Int64?
_2 = reader.readInt64()
var _3: String?
_3 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.MediaArea.inputMediaAreaVenue(coordinates: _1!, queryId: _2!, resultId: _3!)
}
else {
return nil
}
}
public static func parse_mediaAreaChannelPost(_ reader: BufferReader) -> MediaArea? {
var _1: Api.MediaAreaCoordinates?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.MediaAreaCoordinates
}
var _2: Int64?
_2 = reader.readInt64()
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.MediaArea.mediaAreaChannelPost(coordinates: _1!, channelId: _2!, msgId: _3!)
}
else {
return nil
}
}
public static func parse_mediaAreaGeoPoint(_ reader: BufferReader) -> MediaArea? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.MediaAreaCoordinates?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.MediaAreaCoordinates
}
var _3: Api.GeoPoint?
if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.GeoPoint
}
var _4: Api.GeoPointAddress?
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.GeoPointAddress
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.MediaArea.mediaAreaGeoPoint(flags: _1!, coordinates: _2!, geo: _3!, address: _4)
}
else {
return nil
}
}
public static func parse_mediaAreaStarGift(_ reader: BufferReader) -> MediaArea? {
var _1: Api.MediaAreaCoordinates?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.MediaAreaCoordinates
}
var _2: String?
_2 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.MediaArea.mediaAreaStarGift(coordinates: _1!, slug: _2!)
}
else {
return nil
}
}
public static func parse_mediaAreaSuggestedReaction(_ reader: BufferReader) -> MediaArea? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.MediaAreaCoordinates?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.MediaAreaCoordinates
}
var _3: Api.Reaction?
if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.Reaction
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.MediaArea.mediaAreaSuggestedReaction(flags: _1!, coordinates: _2!, reaction: _3!)
}
else {
return nil
}
}
public static func parse_mediaAreaUrl(_ reader: BufferReader) -> MediaArea? {
var _1: Api.MediaAreaCoordinates?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.MediaAreaCoordinates
}
var _2: String?
_2 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.MediaArea.mediaAreaUrl(coordinates: _1!, url: _2!)
}
else {
return nil
}
}
public static func parse_mediaAreaVenue(_ reader: BufferReader) -> MediaArea? {
var _1: Api.MediaAreaCoordinates?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.MediaAreaCoordinates
}
var _2: Api.GeoPoint?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.GeoPoint
}
var _3: String?
_3 = parseString(reader)
var _4: String?
_4 = parseString(reader)
var _5: String?
_5 = parseString(reader)
var _6: String?
_6 = parseString(reader)
var _7: String?
_7 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
return Api.MediaArea.mediaAreaVenue(coordinates: _1!, geo: _2!, title: _3!, address: _4!, provider: _5!, venueId: _6!, venueType: _7!)
}
else {
return nil
}
}
public static func parse_mediaAreaWeather(_ reader: BufferReader) -> MediaArea? {
var _1: Api.MediaAreaCoordinates?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.MediaAreaCoordinates
}
var _2: String?
_2 = parseString(reader)
var _3: Double?
_3 = reader.readDouble()
var _4: Int32?
_4 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.MediaArea.mediaAreaWeather(coordinates: _1!, emoji: _2!, temperatureC: _3!, color: _4!)
}
else {
return nil
}
}
}
}
public extension Api {
enum MediaAreaCoordinates: TypeConstructorDescription {
case mediaAreaCoordinates(flags: Int32, x: Double, y: Double, w: Double, h: Double, rotation: Double, radius: Double?)

View File

@ -608,7 +608,7 @@ public extension Api {
case updateGroupCallChainBlocks(call: Api.InputGroupCall, subChainId: Int32, blocks: [Buffer], nextOffset: Int32)
case updateGroupCallConnection(flags: Int32, params: Api.DataJSON)
case updateGroupCallEncryptedMessage(call: Api.InputGroupCall, fromId: Api.Peer, encryptedMessage: Buffer)
case updateGroupCallMessage(flags: Int32, call: Api.InputGroupCall, fromId: Api.Peer, randomId: Int64, message: Api.TextWithEntities, paidMessageStars: Int64?)
case updateGroupCallMessage(call: Api.InputGroupCall, message: Api.GroupCallMessage)
case updateGroupCallParticipants(call: Api.InputGroupCall, participants: [Api.GroupCallParticipant], version: Int32)
case updateInlineBotCallbackQuery(flags: Int32, queryId: Int64, userId: Int64, msgId: Api.InputBotInlineMessageID, chatInstance: Int64, data: Buffer?, gameShortName: String?)
case updateLangPack(difference: Api.LangPackDifference)
@ -1307,16 +1307,12 @@ public extension Api {
fromId.serialize(buffer, true)
serializeBytes(encryptedMessage, buffer: buffer, boxed: false)
break
case .updateGroupCallMessage(let flags, let call, let fromId, let randomId, let message, let paidMessageStars):
case .updateGroupCallMessage(let call, let message):
if boxed {
buffer.appendInt32(-964095818)
buffer.appendInt32(-667783411)
}
serializeInt32(flags, buffer: buffer, boxed: false)
call.serialize(buffer, true)
fromId.serialize(buffer, true)
serializeInt64(randomId, buffer: buffer, boxed: false)
message.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(paidMessageStars!, buffer: buffer, boxed: false)}
break
case .updateGroupCallParticipants(let call, let participants, let version):
if boxed {
@ -2120,8 +2116,8 @@ public extension Api {
return ("updateGroupCallConnection", [("flags", flags as Any), ("params", params as Any)])
case .updateGroupCallEncryptedMessage(let call, let fromId, let encryptedMessage):
return ("updateGroupCallEncryptedMessage", [("call", call as Any), ("fromId", fromId as Any), ("encryptedMessage", encryptedMessage as Any)])
case .updateGroupCallMessage(let flags, let call, let fromId, let randomId, let message, let paidMessageStars):
return ("updateGroupCallMessage", [("flags", flags as Any), ("call", call as Any), ("fromId", fromId as Any), ("randomId", randomId as Any), ("message", message as Any), ("paidMessageStars", paidMessageStars as Any)])
case .updateGroupCallMessage(let call, let message):
return ("updateGroupCallMessage", [("call", call as Any), ("message", message as Any)])
case .updateGroupCallParticipants(let call, let participants, let version):
return ("updateGroupCallParticipants", [("call", call as Any), ("participants", participants as Any), ("version", version as Any)])
case .updateInlineBotCallbackQuery(let flags, let queryId, let userId, let msgId, let chatInstance, let data, let gameShortName):
@ -3595,32 +3591,18 @@ public extension Api {
}
}
public static func parse_updateGroupCallMessage(_ reader: BufferReader) -> Update? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.InputGroupCall?
var _1: Api.InputGroupCall?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.InputGroupCall
_1 = Api.parse(reader, signature: signature) as? Api.InputGroupCall
}
var _3: Api.Peer?
var _2: Api.GroupCallMessage?
if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.Peer
_2 = Api.parse(reader, signature: signature) as? Api.GroupCallMessage
}
var _4: Int64?
_4 = reader.readInt64()
var _5: Api.TextWithEntities?
if let signature = reader.readInt32() {
_5 = Api.parse(reader, signature: signature) as? Api.TextWithEntities
}
var _6: Int64?
if Int(_1!) & Int(1 << 0) != 0 {_6 = reader.readInt64() }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.Update.updateGroupCallMessage(flags: _1!, call: _2!, fromId: _3!, randomId: _4!, message: _5!, paidMessageStars: _6)
if _c1 && _c2 {
return Api.Update.updateGroupCallMessage(call: _1!, message: _2!)
}
else {
return nil

View File

@ -1328,6 +1328,66 @@ public extension Api {
}
}
public extension Api {
enum GroupCallMessage: TypeConstructorDescription {
case groupCallMessage(flags: Int32, fromId: Api.Peer, date: Int32, randomId: Int64, message: Api.TextWithEntities, paidMessageStars: Int64?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .groupCallMessage(let flags, let fromId, let date, let randomId, let message, let paidMessageStars):
if boxed {
buffer.appendInt32(-2018173984)
}
serializeInt32(flags, buffer: buffer, boxed: false)
fromId.serialize(buffer, true)
serializeInt32(date, buffer: buffer, boxed: false)
serializeInt64(randomId, buffer: buffer, boxed: false)
message.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(paidMessageStars!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .groupCallMessage(let flags, let fromId, let date, let randomId, let message, let paidMessageStars):
return ("groupCallMessage", [("flags", flags as Any), ("fromId", fromId as Any), ("date", date as Any), ("randomId", randomId as Any), ("message", message as Any), ("paidMessageStars", paidMessageStars as Any)])
}
}
public static func parse_groupCallMessage(_ reader: BufferReader) -> GroupCallMessage? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Peer?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _3: Int32?
_3 = reader.readInt32()
var _4: Int64?
_4 = reader.readInt64()
var _5: Api.TextWithEntities?
if let signature = reader.readInt32() {
_5 = Api.parse(reader, signature: signature) as? Api.TextWithEntities
}
var _6: Int64?
if Int(_1!) & Int(1 << 0) != 0 {_6 = reader.readInt64() }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.GroupCallMessage.groupCallMessage(flags: _1!, fromId: _2!, date: _3!, randomId: _4!, message: _5!, paidMessageStars: _6)
}
else {
return nil
}
}
}
}
public extension Api {
enum GroupCallParticipant: TypeConstructorDescription {
case groupCallParticipant(flags: Int32, peer: Api.Peer, date: Int32, activeDate: Int32?, source: Int32, volume: Int32?, about: String?, raiseHandRating: Int64?, video: Api.GroupCallParticipantVideo?, presentation: Api.GroupCallParticipantVideo?, paidStarsTotal: Int64?)
@ -1410,57 +1470,3 @@ public extension Api {
}
}
public extension Api {
enum GroupCallParticipantVideo: TypeConstructorDescription {
case groupCallParticipantVideo(flags: Int32, endpoint: String, sourceGroups: [Api.GroupCallParticipantVideoSourceGroup], audioSource: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .groupCallParticipantVideo(let flags, let endpoint, let sourceGroups, let audioSource):
if boxed {
buffer.appendInt32(1735736008)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(endpoint, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(sourceGroups.count))
for item in sourceGroups {
item.serialize(buffer, true)
}
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(audioSource!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .groupCallParticipantVideo(let flags, let endpoint, let sourceGroups, let audioSource):
return ("groupCallParticipantVideo", [("flags", flags as Any), ("endpoint", endpoint as Any), ("sourceGroups", sourceGroups as Any), ("audioSource", audioSource as Any)])
}
}
public static func parse_groupCallParticipantVideo(_ reader: BufferReader) -> GroupCallParticipantVideo? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: [Api.GroupCallParticipantVideoSourceGroup]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.GroupCallParticipantVideoSourceGroup.self)
}
var _4: Int32?
if Int(_1!) & Int(1 << 1) != 0 {_4 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.GroupCallParticipantVideo.groupCallParticipantVideo(flags: _1!, endpoint: _2!, sourceGroups: _3!, audioSource: _4)
}
else {
return nil
}
}
}
}

View File

@ -1,3 +1,57 @@
public extension Api {
enum GroupCallParticipantVideo: TypeConstructorDescription {
case groupCallParticipantVideo(flags: Int32, endpoint: String, sourceGroups: [Api.GroupCallParticipantVideoSourceGroup], audioSource: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .groupCallParticipantVideo(let flags, let endpoint, let sourceGroups, let audioSource):
if boxed {
buffer.appendInt32(1735736008)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(endpoint, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(sourceGroups.count))
for item in sourceGroups {
item.serialize(buffer, true)
}
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(audioSource!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .groupCallParticipantVideo(let flags, let endpoint, let sourceGroups, let audioSource):
return ("groupCallParticipantVideo", [("flags", flags as Any), ("endpoint", endpoint as Any), ("sourceGroups", sourceGroups as Any), ("audioSource", audioSource as Any)])
}
}
public static func parse_groupCallParticipantVideo(_ reader: BufferReader) -> GroupCallParticipantVideo? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: [Api.GroupCallParticipantVideoSourceGroup]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.GroupCallParticipantVideoSourceGroup.self)
}
var _4: Int32?
if Int(_1!) & Int(1 << 1) != 0 {_4 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.GroupCallParticipantVideo.groupCallParticipantVideo(flags: _1!, endpoint: _2!, sourceGroups: _3!, audioSource: _4)
}
else {
return nil
}
}
}
}
public extension Api {
enum GroupCallParticipantVideoSourceGroup: TypeConstructorDescription {
case groupCallParticipantVideoSourceGroup(semantics: String, sources: [Int32])
@ -1192,57 +1246,3 @@ public extension Api {
}
}
public extension Api {
enum InputBusinessChatLink: TypeConstructorDescription {
case inputBusinessChatLink(flags: Int32, message: String, entities: [Api.MessageEntity]?, title: String?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .inputBusinessChatLink(let flags, let message, let entities, let title):
if boxed {
buffer.appendInt32(292003751)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(message, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(entities!.count))
for item in entities! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 1) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .inputBusinessChatLink(let flags, let message, let entities, let title):
return ("inputBusinessChatLink", [("flags", flags as Any), ("message", message as Any), ("entities", entities as Any), ("title", title as Any)])
}
}
public static func parse_inputBusinessChatLink(_ reader: BufferReader) -> InputBusinessChatLink? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: [Api.MessageEntity]?
if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
} }
var _4: String?
if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.InputBusinessChatLink.inputBusinessChatLink(flags: _1!, message: _2!, entities: _3, title: _4)
}
else {
return nil
}
}
}
}

View File

@ -1,3 +1,57 @@
public extension Api {
enum InputBusinessChatLink: TypeConstructorDescription {
case inputBusinessChatLink(flags: Int32, message: String, entities: [Api.MessageEntity]?, title: String?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .inputBusinessChatLink(let flags, let message, let entities, let title):
if boxed {
buffer.appendInt32(292003751)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(message, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(entities!.count))
for item in entities! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 1) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .inputBusinessChatLink(let flags, let message, let entities, let title):
return ("inputBusinessChatLink", [("flags", flags as Any), ("message", message as Any), ("entities", entities as Any), ("title", title as Any)])
}
}
public static func parse_inputBusinessChatLink(_ reader: BufferReader) -> InputBusinessChatLink? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: [Api.MessageEntity]?
if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
} }
var _4: String?
if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.InputBusinessChatLink.inputBusinessChatLink(flags: _1!, message: _2!, entities: _3, title: _4)
}
else {
return nil
}
}
}
}
public extension Api {
enum InputBusinessGreetingMessage: TypeConstructorDescription {
case inputBusinessGreetingMessage(shortcutId: Int32, recipients: Api.InputBusinessRecipients, noActivityDays: Int32)
@ -992,313 +1046,3 @@ public extension Api {
}
}
public extension Api {
indirect enum InputFileLocation: TypeConstructorDescription {
case inputDocumentFileLocation(id: Int64, accessHash: Int64, fileReference: Buffer, thumbSize: String)
case inputEncryptedFileLocation(id: Int64, accessHash: Int64)
case inputFileLocation(volumeId: Int64, localId: Int32, secret: Int64, fileReference: Buffer)
case inputGroupCallStream(flags: Int32, call: Api.InputGroupCall, timeMs: Int64, scale: Int32, videoChannel: Int32?, videoQuality: Int32?)
case inputPeerPhotoFileLocation(flags: Int32, peer: Api.InputPeer, photoId: Int64)
case inputPhotoFileLocation(id: Int64, accessHash: Int64, fileReference: Buffer, thumbSize: String)
case inputPhotoLegacyFileLocation(id: Int64, accessHash: Int64, fileReference: Buffer, volumeId: Int64, localId: Int32, secret: Int64)
case inputSecureFileLocation(id: Int64, accessHash: Int64)
case inputStickerSetThumb(stickerset: Api.InputStickerSet, thumbVersion: Int32)
case inputTakeoutFileLocation
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .inputDocumentFileLocation(let id, let accessHash, let fileReference, let thumbSize):
if boxed {
buffer.appendInt32(-1160743548)
}
serializeInt64(id, buffer: buffer, boxed: false)
serializeInt64(accessHash, buffer: buffer, boxed: false)
serializeBytes(fileReference, buffer: buffer, boxed: false)
serializeString(thumbSize, buffer: buffer, boxed: false)
break
case .inputEncryptedFileLocation(let id, let accessHash):
if boxed {
buffer.appendInt32(-182231723)
}
serializeInt64(id, buffer: buffer, boxed: false)
serializeInt64(accessHash, buffer: buffer, boxed: false)
break
case .inputFileLocation(let volumeId, let localId, let secret, let fileReference):
if boxed {
buffer.appendInt32(-539317279)
}
serializeInt64(volumeId, buffer: buffer, boxed: false)
serializeInt32(localId, buffer: buffer, boxed: false)
serializeInt64(secret, buffer: buffer, boxed: false)
serializeBytes(fileReference, buffer: buffer, boxed: false)
break
case .inputGroupCallStream(let flags, let call, let timeMs, let scale, let videoChannel, let videoQuality):
if boxed {
buffer.appendInt32(93890858)
}
serializeInt32(flags, buffer: buffer, boxed: false)
call.serialize(buffer, true)
serializeInt64(timeMs, buffer: buffer, boxed: false)
serializeInt32(scale, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(videoChannel!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(videoQuality!, buffer: buffer, boxed: false)}
break
case .inputPeerPhotoFileLocation(let flags, let peer, let photoId):
if boxed {
buffer.appendInt32(925204121)
}
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeInt64(photoId, buffer: buffer, boxed: false)
break
case .inputPhotoFileLocation(let id, let accessHash, let fileReference, let thumbSize):
if boxed {
buffer.appendInt32(1075322878)
}
serializeInt64(id, buffer: buffer, boxed: false)
serializeInt64(accessHash, buffer: buffer, boxed: false)
serializeBytes(fileReference, buffer: buffer, boxed: false)
serializeString(thumbSize, buffer: buffer, boxed: false)
break
case .inputPhotoLegacyFileLocation(let id, let accessHash, let fileReference, let volumeId, let localId, let secret):
if boxed {
buffer.appendInt32(-667654413)
}
serializeInt64(id, buffer: buffer, boxed: false)
serializeInt64(accessHash, buffer: buffer, boxed: false)
serializeBytes(fileReference, buffer: buffer, boxed: false)
serializeInt64(volumeId, buffer: buffer, boxed: false)
serializeInt32(localId, buffer: buffer, boxed: false)
serializeInt64(secret, buffer: buffer, boxed: false)
break
case .inputSecureFileLocation(let id, let accessHash):
if boxed {
buffer.appendInt32(-876089816)
}
serializeInt64(id, buffer: buffer, boxed: false)
serializeInt64(accessHash, buffer: buffer, boxed: false)
break
case .inputStickerSetThumb(let stickerset, let thumbVersion):
if boxed {
buffer.appendInt32(-1652231205)
}
stickerset.serialize(buffer, true)
serializeInt32(thumbVersion, buffer: buffer, boxed: false)
break
case .inputTakeoutFileLocation:
if boxed {
buffer.appendInt32(700340377)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .inputDocumentFileLocation(let id, let accessHash, let fileReference, let thumbSize):
return ("inputDocumentFileLocation", [("id", id as Any), ("accessHash", accessHash as Any), ("fileReference", fileReference as Any), ("thumbSize", thumbSize as Any)])
case .inputEncryptedFileLocation(let id, let accessHash):
return ("inputEncryptedFileLocation", [("id", id as Any), ("accessHash", accessHash as Any)])
case .inputFileLocation(let volumeId, let localId, let secret, let fileReference):
return ("inputFileLocation", [("volumeId", volumeId as Any), ("localId", localId as Any), ("secret", secret as Any), ("fileReference", fileReference as Any)])
case .inputGroupCallStream(let flags, let call, let timeMs, let scale, let videoChannel, let videoQuality):
return ("inputGroupCallStream", [("flags", flags as Any), ("call", call as Any), ("timeMs", timeMs as Any), ("scale", scale as Any), ("videoChannel", videoChannel as Any), ("videoQuality", videoQuality as Any)])
case .inputPeerPhotoFileLocation(let flags, let peer, let photoId):
return ("inputPeerPhotoFileLocation", [("flags", flags as Any), ("peer", peer as Any), ("photoId", photoId as Any)])
case .inputPhotoFileLocation(let id, let accessHash, let fileReference, let thumbSize):
return ("inputPhotoFileLocation", [("id", id as Any), ("accessHash", accessHash as Any), ("fileReference", fileReference as Any), ("thumbSize", thumbSize as Any)])
case .inputPhotoLegacyFileLocation(let id, let accessHash, let fileReference, let volumeId, let localId, let secret):
return ("inputPhotoLegacyFileLocation", [("id", id as Any), ("accessHash", accessHash as Any), ("fileReference", fileReference as Any), ("volumeId", volumeId as Any), ("localId", localId as Any), ("secret", secret as Any)])
case .inputSecureFileLocation(let id, let accessHash):
return ("inputSecureFileLocation", [("id", id as Any), ("accessHash", accessHash as Any)])
case .inputStickerSetThumb(let stickerset, let thumbVersion):
return ("inputStickerSetThumb", [("stickerset", stickerset as Any), ("thumbVersion", thumbVersion as Any)])
case .inputTakeoutFileLocation:
return ("inputTakeoutFileLocation", [])
}
}
public static func parse_inputDocumentFileLocation(_ reader: BufferReader) -> InputFileLocation? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int64?
_2 = reader.readInt64()
var _3: Buffer?
_3 = parseBytes(reader)
var _4: String?
_4 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.InputFileLocation.inputDocumentFileLocation(id: _1!, accessHash: _2!, fileReference: _3!, thumbSize: _4!)
}
else {
return nil
}
}
public static func parse_inputEncryptedFileLocation(_ reader: BufferReader) -> InputFileLocation? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int64?
_2 = reader.readInt64()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.InputFileLocation.inputEncryptedFileLocation(id: _1!, accessHash: _2!)
}
else {
return nil
}
}
public static func parse_inputFileLocation(_ reader: BufferReader) -> InputFileLocation? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int64?
_3 = reader.readInt64()
var _4: Buffer?
_4 = parseBytes(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.InputFileLocation.inputFileLocation(volumeId: _1!, localId: _2!, secret: _3!, fileReference: _4!)
}
else {
return nil
}
}
public static func parse_inputGroupCallStream(_ reader: BufferReader) -> InputFileLocation? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.InputGroupCall?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.InputGroupCall
}
var _3: Int64?
_3 = reader.readInt64()
var _4: Int32?
_4 = reader.readInt32()
var _5: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_5 = reader.readInt32() }
var _6: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_6 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.InputFileLocation.inputGroupCallStream(flags: _1!, call: _2!, timeMs: _3!, scale: _4!, videoChannel: _5, videoQuality: _6)
}
else {
return nil
}
}
public static func parse_inputPeerPhotoFileLocation(_ reader: BufferReader) -> InputFileLocation? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.InputPeer?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.InputPeer
}
var _3: Int64?
_3 = reader.readInt64()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.InputFileLocation.inputPeerPhotoFileLocation(flags: _1!, peer: _2!, photoId: _3!)
}
else {
return nil
}
}
public static func parse_inputPhotoFileLocation(_ reader: BufferReader) -> InputFileLocation? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int64?
_2 = reader.readInt64()
var _3: Buffer?
_3 = parseBytes(reader)
var _4: String?
_4 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.InputFileLocation.inputPhotoFileLocation(id: _1!, accessHash: _2!, fileReference: _3!, thumbSize: _4!)
}
else {
return nil
}
}
public static func parse_inputPhotoLegacyFileLocation(_ reader: BufferReader) -> InputFileLocation? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int64?
_2 = reader.readInt64()
var _3: Buffer?
_3 = parseBytes(reader)
var _4: Int64?
_4 = reader.readInt64()
var _5: Int32?
_5 = reader.readInt32()
var _6: Int64?
_6 = reader.readInt64()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.InputFileLocation.inputPhotoLegacyFileLocation(id: _1!, accessHash: _2!, fileReference: _3!, volumeId: _4!, localId: _5!, secret: _6!)
}
else {
return nil
}
}
public static func parse_inputSecureFileLocation(_ reader: BufferReader) -> InputFileLocation? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int64?
_2 = reader.readInt64()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.InputFileLocation.inputSecureFileLocation(id: _1!, accessHash: _2!)
}
else {
return nil
}
}
public static func parse_inputStickerSetThumb(_ reader: BufferReader) -> InputFileLocation? {
var _1: Api.InputStickerSet?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.InputStickerSet
}
var _2: Int32?
_2 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.InputFileLocation.inputStickerSetThumb(stickerset: _1!, thumbVersion: _2!)
}
else {
return nil
}
}
public static func parse_inputTakeoutFileLocation(_ reader: BufferReader) -> InputFileLocation? {
return Api.InputFileLocation.inputTakeoutFileLocation
}
}
}

View File

@ -492,10 +492,6 @@ public final class MediaStreamVideoComponent: Component {
} else if !self.hadVideo {
aspect = 16.0 / 9
}
#if DEBUG
aspect = 9.0 / 16.0
#endif
if component.isFullscreen || !component.addInset {
videoSize = CGSize(width: aspect * 100.0, height: 100.0).aspectFitted(.init(width: availableSize.width - videoInset * 2, height: availableSize.height))

View File

@ -930,11 +930,15 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
if let data = accountContext.currentAppConfiguration.with({ $0 }).data, let value = data["group_call_message_ttl"] as? Double {
messageLifetime = Int32(value)
}
if isStream {
messageLifetime = Int32.max
}
self.messagesContext = accountContext.engine.messages.groupCallMessages(
callId: initialCall.description.id,
reference: .id(id: initialCall.description.id, accessHash: initialCall.description.accessHash),
e2eContext: self.e2eContext,
messageLifetime: messageLifetime
messageLifetime: messageLifetime,
isLiveStream: isStream
)
self.messagesStatePromise.set(self.messagesContext!.state)
}
@ -4032,9 +4036,9 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
})
}
public func sendMessage(randomId: Int64? = nil, text: String, entities: [MessageTextEntity]) {
public func sendMessage(randomId: Int64? = nil, text: String, entities: [MessageTextEntity], paidStars: Int64?) {
if let messagesContext = self.messagesContext {
messagesContext.send(fromId: self.joinAsPeerId, randomId: randomId, text: text, entities: entities)
messagesContext.send(fromId: self.joinAsPeerId, randomId: randomId, text: text, entities: entities, paidStars: paidStars)
}
}
}

View File

@ -1415,7 +1415,7 @@ final class VideoChatScreenComponent: Component {
return
}
let entities = generateTextEntities(text.string, enabledTypes: [.mention, .hashtag], currentEntities: generateChatInputTextEntities(text))
call.sendMessage(randomId: randomId, text: text.string, entities: entities)
call.sendMessage(randomId: randomId, text: text.string, entities: entities, paidStars: nil)
}
inputPanelView.clearSendMessageInput(updateState: true)
@ -3572,6 +3572,7 @@ final class VideoChatScreenComponent: Component {
},
timeoutAction: nil,
forwardAction: nil,
paidMessageAction: nil,
moreAction: nil,
presentCaptionPositionTooltip: nil,
presentVoiceMessagesUnavailableTooltip: nil,
@ -3833,7 +3834,7 @@ final class VideoChatScreenComponent: Component {
guard case let .group(groupCall) = self.currentCall, let call = groupCall as? PresentationGroupCallImpl else {
return
}
call.sendMessage(text: text, entities: entities)
call.sendMessage(text: text, entities: entities, paidStars: nil)
})
}

View File

@ -118,7 +118,7 @@ enum AccountStateMutationOperation {
case UpdateGroupCallParticipants(id: Int64, accessHash: Int64, participants: [Api.GroupCallParticipant], version: Int32)
case UpdateGroupCall(peerId: PeerId?, call: Api.GroupCall)
case UpdateGroupCallChainBlocks(id: Int64, accessHash: Int64, subChainId: Int32, blocks: [Data], nextOffset: Int32)
case UpdateGroupCallMessage(id: Int64, authorId: PeerId, randomId: Int64, text: Api.TextWithEntities)
case UpdateGroupCallMessage(id: Int64, authorId: PeerId, randomId: Int64, text: Api.TextWithEntities, date: Int32, paidMessageStars: Int64?)
case UpdateGroupCallOpaqueMessage(id: Int64, authorId: PeerId, data: Data)
case UpdateAutoremoveTimeout(peer: Api.Peer, value: CachedPeerAutoremoveTimeout.Value?)
case UpdateAttachMenuBots
@ -411,8 +411,8 @@ struct AccountMutableState {
self.addOperation(.UpdateGroupCallChainBlocks(id: id, accessHash: accessHash, subChainId: subChainId, blocks: blocks, nextOffset: nextOffset))
}
mutating func updateGroupCallMessage(id: Int64, authorId: PeerId, randomId: Int64, text: Api.TextWithEntities) {
self.addOperation(.UpdateGroupCallMessage(id: id, authorId: authorId, randomId: randomId, text: text))
mutating func updateGroupCallMessage(id: Int64, authorId: PeerId, randomId: Int64, text: Api.TextWithEntities, date: Int32, paidMessageStars: Int64?) {
self.addOperation(.UpdateGroupCallMessage(id: id, authorId: authorId, randomId: randomId, text: text, date: date, paidMessageStars: paidMessageStars))
}
mutating func updateGroupCallOpaqueMessage(id: Int64, authorId: PeerId, data: Data) {

View File

@ -202,10 +202,10 @@ public enum CreateForumChannelTopicError {
}
func _internal_createForumChannelTopic(account: Account, peerId: PeerId, title: String, iconColor: Int32, iconFileId: Int64?) -> Signal<Int64, CreateForumChannelTopicError> {
return _internal_createForumChannelTopic(postbox: account.postbox, network: account.network, stateManager: account.stateManager, accountPeerId: account.peerId, peerId: peerId, title: title, iconColor: iconColor, iconFileId: iconFileId)
return _internal_createForumChannelTopic(postbox: account.postbox, network: account.network, stateManager: account.stateManager, accountPeerId: account.peerId, peerId: peerId, title: title, iconColor: iconColor, iconFileId: iconFileId, isTitleMissing: false)
}
func _internal_createForumChannelTopic(postbox: Postbox, network: Network, stateManager: AccountStateManager, accountPeerId: PeerId, peerId: PeerId, title: String, iconColor: Int32, iconFileId: Int64?) -> Signal<Int64, CreateForumChannelTopicError> {
func _internal_createForumChannelTopic(postbox: Postbox, network: Network, stateManager: AccountStateManager, accountPeerId: PeerId, peerId: PeerId, title: String, iconColor: Int32, iconFileId: Int64?, isTitleMissing: Bool) -> Signal<Int64, CreateForumChannelTopicError> {
return postbox.transaction { transaction -> Peer? in
return transaction.getPeer(peerId)
}
@ -222,6 +222,9 @@ func _internal_createForumChannelTopic(postbox: Postbox, network: Network, state
flags |= (1 << 3)
}
flags |= (1 << 0)
if isTitleMissing {
flags |= (1 << 4)
}
return network.request(Api.functions.messages.createForumTopic(
flags: flags,
peer: inputPeer,

View File

@ -1683,9 +1683,12 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
if case let .inputGroupCall(id, accessHash) = call {
updatedState.updateGroupCallChainBlocks(id: id, accessHash: accessHash, subChainId: subChainId, blocks: blocks.map { $0.makeData() }, nextOffset: nextOffset)
}
case let .updateGroupCallMessage(_, call, fromId, randomId, message, _):
case let .updateGroupCallMessage(call, message):
if case let .inputGroupCall(id, _) = call {
updatedState.updateGroupCallMessage(id: id, authorId: fromId.peerId, randomId: randomId, text: message)
switch message {
case let .groupCallMessage(_, fromId, date, randomId, message, paidMessageStars):
updatedState.updateGroupCallMessage(id: id, authorId: fromId.peerId, randomId: randomId, text: message, date: date, paidMessageStars: paidMessageStars)
}
}
case let .updateGroupCallEncryptedMessage(call, fromId, encryptedMessage):
if case let .inputGroupCall(id, _) = call {
@ -4879,10 +4882,10 @@ func replayFinalState(
callId,
.state(update: GroupCallParticipantsContext.Update.StateUpdate(participants: participants, version: version))
))
case let .UpdateGroupCallMessage(callId, authorId, randomId, text):
case let .UpdateGroupCallMessage(callId, authorId, randomId, text, date, paidMessageStars):
switch text {
case let .textWithEntities(text, entities):
groupCallMessageUpdates.append(GroupCallMessageUpdate(callId: callId, update: .newPlaintextMessage(authorId: authorId, randomId: randomId, text: text, entities: messageTextEntitiesFromApiEntities(entities))))
groupCallMessageUpdates.append(GroupCallMessageUpdate(callId: callId, update: .newPlaintextMessage(authorId: authorId, randomId: randomId, text: text, entities: messageTextEntitiesFromApiEntities(entities), timestamp: date, paidMessageStars: paidMessageStars)))
}
case let .UpdateGroupCallOpaqueMessage(callId, authorId, data):
groupCallMessageUpdates.append(GroupCallMessageUpdate(callId: callId, update: .newOpaqueMessage(authorId: authorId, data: data)))

View File

@ -488,15 +488,21 @@ public final class PendingMessageManager {
let disposable = MetaDisposable()
strongSelf.newTopicDisposables[messagePeerId] = disposable
var topicName = "New Thread"
if !message.text.isEmpty {
topicName = String(message.text.prefix(16))
}
disposable.set(_internal_createForumChannelTopic(
postbox: strongSelf.postbox,
network: strongSelf.network,
stateManager: strongSelf.stateManager,
accountPeerId: strongSelf.accountPeerId,
peerId: message.id.peerId,
title: "New Thread",
title: topicName,
iconColor: 0,
iconFileId: nil
iconFileId: nil,
isTitleMissing: true
).startStrict(next: { [weak strongSelf] topicId in
guard let strongSelf else {
return

View File

@ -3460,7 +3460,7 @@ func _internal_refreshInlineGroupCall(account: Account, messageId: MessageId) ->
struct GroupCallMessageUpdate {
enum Update {
case newPlaintextMessage(authorId: PeerId, randomId: Int64, text: String, entities: [MessageTextEntity])
case newPlaintextMessage(authorId: PeerId, randomId: Int64, text: String, entities: [MessageTextEntity], timestamp: Int32, paidMessageStars: Int64?)
case newOpaqueMessage(authorId: PeerId, data: Data)
}
@ -3680,14 +3680,16 @@ public final class GroupCallMessagesContext {
public let entities: [MessageTextEntity]
public let date: Int32
public let lifetime: Int32
public let paidStars: Int64?
public init(id: Int64, author: EnginePeer?, text: String, entities: [MessageTextEntity], date: Int32, lifetime: Int32) {
public init(id: Int64, author: EnginePeer?, text: String, entities: [MessageTextEntity], date: Int32, lifetime: Int32, paidStars: Int64?) {
self.id = id
self.author = author
self.text = text
self.entities = entities
self.date = date
self.lifetime = lifetime
self.paidStars = paidStars
}
public static func ==(lhs: Message, rhs: Message) -> Bool {
@ -3712,6 +3714,9 @@ public final class GroupCallMessagesContext {
if lhs.lifetime != rhs.lifetime {
return false
}
if lhs.paidStars != rhs.paidStars {
return false
}
return true
}
}
@ -3726,6 +3731,7 @@ public final class GroupCallMessagesContext {
private final class Impl {
private let messageLifetime: Int32
private let isLiveStream: Bool
let queue: Queue
let account: Account
@ -3747,13 +3753,14 @@ public final class GroupCallMessagesContext {
private var messageLifeTimer: SwiftSignalKit.Timer?
init(queue: Queue, account: Account, callId: Int64, reference: InternalGroupCallReference, e2eContext: ConferenceCallE2EContext?, messageLifetime: Int32) {
init(queue: Queue, account: Account, callId: Int64, reference: InternalGroupCallReference, e2eContext: ConferenceCallE2EContext?, messageLifetime: Int32, isLiveStream: Bool) {
self.queue = queue
self.account = account
self.callId = callId
self.reference = reference
self.e2eContext = e2eContext
self.messageLifetime = messageLifetime
self.isLiveStream = isLiveStream
self.state = State(messages: [])
self.stateValue.set(self.state)
@ -3764,16 +3771,16 @@ public final class GroupCallMessagesContext {
return
}
let currentTime = Int32(CFAbsoluteTimeGetCurrent())
var addedMessages: [(authorId: PeerId, randomId: Int64, text: String, entities: [MessageTextEntity])] = []
var addedMessages: [(authorId: PeerId, randomId: Int64, text: String, entities: [MessageTextEntity], timestamp: Int32, paidMessageStars: Int64?)] = []
var addedOpaqueMessages: [(authorId: PeerId, data: Data)] = []
for update in updates {
if update.callId != self.callId {
continue
}
switch update.update {
case let .newPlaintextMessage(authorId, randomId, text, entities):
case let .newPlaintextMessage(authorId, randomId, text, entities, timestamp, paidMessageStars):
if authorId != self.account.peerId {
addedMessages.append((authorId, randomId, text, entities))
addedMessages.append((authorId, randomId, text, entities, timestamp, paidMessageStars))
}
case let .newOpaqueMessage(authorId, data):
if authorId != self.account.peerId {
@ -3783,6 +3790,9 @@ public final class GroupCallMessagesContext {
}
if !addedMessages.isEmpty || !addedOpaqueMessages.isEmpty {
let messageLifetime = self.messageLifetime
let isLiveStream = self.isLiveStream
let _ = (self.account.postbox.transaction { transaction -> [Message] in
var messages: [Message] = []
if let e2eContext = self.e2eContext {
@ -3814,7 +3824,8 @@ public final class GroupCallMessagesContext {
text: text,
entities: entities,
date: currentTime,
lifetime: self.messageLifetime
lifetime: messageLifetime,
paidStars: nil
))
}
} else {
@ -3822,13 +3833,22 @@ public final class GroupCallMessagesContext {
if self.processedIds.contains(addedMessage.randomId) {
continue
}
let lifetime: Int32
if isLiveStream {
lifetime = Int32(GroupCallMessagesContext.getStarAmountParamMapping(value: addedMessage.paidMessageStars ?? 0).period)
} else {
lifetime = self.messageLifetime
}
messages.append(Message(
id: addedMessage.randomId,
author: transaction.getPeer(addedMessage.authorId).flatMap(EnginePeer.init),
text: addedMessage.text,
entities: addedMessage.entities,
date: currentTime,
lifetime: self.messageLifetime
date: addedMessage.timestamp,
lifetime: lifetime,
paidStars: addedMessage.paidMessageStars
))
}
}
@ -3871,7 +3891,7 @@ public final class GroupCallMessagesContext {
}
}
func send(fromId: EnginePeer.Id, randomId requestedRandomId: Int64?, text: String, entities: [MessageTextEntity]) {
func send(fromId: EnginePeer.Id, randomId requestedRandomId: Int64?, text: String, entities: [MessageTextEntity], paidStars: Int64?) {
let _ = (self.account.postbox.transaction { transaction -> Peer? in
return transaction.getPeer(fromId)
}
@ -3888,6 +3908,14 @@ public final class GroupCallMessagesContext {
} else {
arc4random_buf(&randomId, 8)
}
let lifetime: Int32
if isLiveStream {
lifetime = Int32(GroupCallMessagesContext.getStarAmountParamMapping(value: paidStars ?? 0).period)
} else {
lifetime = self.messageLifetime
}
var state = self.state
state.messages.append(Message(
id: randomId,
@ -3895,10 +3923,18 @@ public final class GroupCallMessagesContext {
text: text,
entities: entities,
date: currentTime,
lifetime: self.messageLifetime
lifetime: lifetime,
paidStars: paidStars
))
self.state = state
#if DEBUG
var paidStars = paidStars
if "".isEmpty {
paidStars = nil
}
#endif
self.processedIds.insert(randomId)
if let e2eContext = self.e2eContext, let messageData = serializeGroupCallMessage(randomId: randomId, text: text, entities: entities) {
@ -3921,6 +3957,10 @@ public final class GroupCallMessagesContext {
} else {
arc4random_buf(&randomId, 8)
}
var flags: Int32 = 0
if paidStars != nil {
flags |= 1 << 0
}
self.sendMessageDisposables.add(self.account.network.request(Api.functions.phone.sendGroupCallMessage(
flags: 0,
call: self.reference.apiInputGroupCall,
@ -3929,7 +3969,7 @@ public final class GroupCallMessagesContext {
text: text,
entities: apiEntitiesFromMessageTextEntities(entities, associatedPeers: SimpleDictionary())
),
allowPaidStars: nil
allowPaidStars: paidStars
)).startStrict())
}
})
@ -3945,17 +3985,42 @@ public final class GroupCallMessagesContext {
}
}
init(account: Account, callId: Int64, reference: InternalGroupCallReference, e2eContext: ConferenceCallE2EContext?, messageLifetime: Int32) {
init(account: Account, callId: Int64, reference: InternalGroupCallReference, e2eContext: ConferenceCallE2EContext?, messageLifetime: Int32, isLiveStream: Bool) {
let queue = Queue(name: "GroupCallMessagesContext")
self.queue = queue
self.impl = QueueLocalObject(queue: queue, generate: {
return Impl(queue: queue, account: account, callId: callId, reference: reference, e2eContext: e2eContext, messageLifetime: messageLifetime)
return Impl(queue: queue, account: account, callId: callId, reference: reference, e2eContext: e2eContext, messageLifetime: messageLifetime, isLiveStream: isLiveStream)
})
}
public func send(fromId: EnginePeer.Id, randomId: Int64?, text: String, entities: [MessageTextEntity]) {
public func send(fromId: EnginePeer.Id, randomId: Int64?, text: String, entities: [MessageTextEntity], paidStars: Int64?) {
self.impl.with { impl in
impl.send(fromId: fromId, randomId: randomId, text: text, entities: entities)
impl.send(fromId: fromId, randomId: randomId, text: text, entities: entities, paidStars: paidStars)
}
}
public static func getStarAmountParamMapping(value: Int64) -> (period: Int, maxLength: Int, emojiCount: Int) {
if value >= 10000 {
return (3600, 400, 20)
}
if value >= 2000 {
return (1800, 280, 10)
}
if value >= 500 {
return (900, 200, 7)
}
if value >= 250 {
return (600, 150, 4)
}
if value >= 100 {
return (300, 110, 3)
}
if value >= 50 {
return (120, 80, 2)
}
if value >= 10 {
return (60, 60, 1)
}
return (30, 30, 0)
}
}

View File

@ -1648,8 +1648,8 @@ public extension TelegramEngine {
return _internal_refreshGlobalPostSearchState(account: self.account)
}
public func groupCallMessages(callId: Int64, reference: InternalGroupCallReference, e2eContext: ConferenceCallE2EContext?, messageLifetime: Int32) -> GroupCallMessagesContext {
return GroupCallMessagesContext(account: self.account, callId: callId, reference: reference, e2eContext: e2eContext, messageLifetime: messageLifetime)
public func groupCallMessages(callId: Int64, reference: InternalGroupCallReference, e2eContext: ConferenceCallE2EContext?, messageLifetime: Int32, isLiveStream: Bool) -> GroupCallMessagesContext {
return GroupCallMessagesContext(account: self.account, callId: callId, reference: reference, e2eContext: e2eContext, messageLifetime: messageLifetime, isLiveStream: isLiveStream)
}
}
}

View File

@ -135,13 +135,16 @@ private final class BalanceComponent: CombinedComponent {
private final class BadgeComponent: Component {
let theme: PresentationTheme
let title: String
let color: UIColor
init(
theme: PresentationTheme,
title: String
title: String,
color: UIColor
) {
self.theme = theme
self.title = title
self.color = color
}
static func ==(lhs: BadgeComponent, rhs: BadgeComponent) -> Bool {
@ -151,6 +154,9 @@ private final class BadgeComponent: Component {
if lhs.title != rhs.title {
return false
}
if lhs.color != rhs.color {
return false
}
return true
}
@ -242,6 +248,7 @@ private final class BadgeComponent: Component {
self.badgeIcon.image = UIImage(bundleImageName: "Premium/SendStarsStarSliderIcon")?.withRenderingMode(.alwaysTemplate)
}
let previousComponent = self.component
self.component = component
self.badgeIcon.tintColor = .white
@ -268,12 +275,12 @@ private final class BadgeComponent: Component {
let size = badgeSize
transition.setFrame(view: self.badgeLabel, frame: CGRect(origin: CGPoint(x: 14.0 + floorToScreenPixels((badgeFullSize.width - badgeLabelSize.width) / 2.0), y: 5.0), size: badgeLabelSize))
if self.previousAvailableSize != availableSize {
if self.previousAvailableSize != availableSize || previousComponent?.color != component.color {
self.previousAvailableSize = availableSize
let activeColors: [UIColor] = [
UIColor(rgb: 0xFFAB03),
UIColor(rgb: 0xFFCB37)
component.color,
component.color
]
var locations: [CGFloat] = []
@ -421,7 +428,7 @@ private final class PeerBadgeComponent: Component {
let contentSize = CGSize(width: iconSize.width + titleSpacing + titleSize.width, height: titleSize.height)
let size = CGSize(width: contentSize.width + sideInset * 2.0, height: contentSize.height + 3.0 * 2.0)
self.backgroundMaskLayer.backgroundColor = component.theme.list.plainBackgroundColor.cgColor
self.backgroundMaskLayer.backgroundColor = component.theme.overallDarkAppearance ? component.theme.list.blocksBackgroundColor.cgColor : component.theme.list.plainBackgroundColor.cgColor
self.backgroundLayer.backgroundColor = UIColor(rgb: 0xFFB10D).cgColor
let backgroundFrame = CGRect(origin: CGPoint(), size: size)
@ -599,17 +606,20 @@ private final class SliderBackgroundComponent: Component {
let strings: PresentationStrings
let value: CGFloat
let topCutoff: CGFloat?
let color: UIColor
init(
theme: PresentationTheme,
strings: PresentationStrings,
value: CGFloat,
topCutoff: CGFloat?
topCutoff: CGFloat?,
color: UIColor
) {
self.theme = theme
self.strings = strings
self.value = value
self.topCutoff = topCutoff
self.color = color
}
static func ==(lhs: SliderBackgroundComponent, rhs: SliderBackgroundComponent) -> Bool {
@ -625,6 +635,9 @@ private final class SliderBackgroundComponent: Component {
if lhs.topCutoff != rhs.topCutoff {
return false
}
if lhs.color != rhs.color {
return false
}
return true
}
@ -692,7 +705,7 @@ private final class SliderBackgroundComponent: Component {
func update(component: SliderBackgroundComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.sliderBackground.backgroundColor = component.theme.list.itemPrimaryTextColor.withMultipliedAlpha(component.theme.overallDarkAppearance ? 0.2 : 0.07)
self.sliderForeground.backgroundColor = UIColor(rgb: 0xFFB10D)
self.sliderForeground.backgroundColor = component.color
self.topForegroundLine.backgroundColor = component.theme.list.plainBackgroundColor.cgColor
self.topBackgroundLine.backgroundColor = component.theme.list.plainBackgroundColor.cgColor
@ -1429,6 +1442,8 @@ private final class ChatSendStarsScreenComponent: Component {
switch component.initialData.subjectInitialData {
case let .react(reactData):
targetPeerId = reactData.peer.id
case let .liveStreamMessage(liveStreamMessageData):
targetPeerId = liveStreamMessageData.peer.id
}
let _ = (context.engine.payments.starsTopUpOptions()
@ -1502,6 +1517,11 @@ private final class ChatSendStarsScreenComponent: Component {
}
}
})
case let .liveStreamMessage(liveStreamMessageData):
self.currentMyPeer = nil
self.amount = Amount(realValue: 50, maxRealValue: liveStreamMessageData.maxAmount, maxSliderValue: 999, isLogarithmic: true)
self.privacyPeer = .account
}
if let starsContext = component.context.starsContext {
@ -1559,6 +1579,8 @@ private final class ChatSendStarsScreenComponent: Component {
switch component.initialData.subjectInitialData {
case let .react(reactData):
maxAmount = reactData.maxAmount
case let .liveStreamMessage(liveStreamMessageData):
maxAmount = liveStreamMessageData.maxAmount
}
self.amount = self.amount.withSliderValue(value)
@ -1612,6 +1634,7 @@ private final class ChatSendStarsScreenComponent: Component {
var topCutoffFraction: CGFloat?
var topCount: Int?
var sliderColor: UIColor = UIColor(rgb: 0xFFB10D)
switch component.initialData.subjectInitialData {
case let .react(reactData):
let topOthersCount: Int? = reactData.topPeers.filter({ !$0.isMy }).max(by: { $0.count < $1.count })?.count
@ -1638,6 +1661,8 @@ private final class ChatSendStarsScreenComponent: Component {
} else {
self.isPastTopCutoff = nil
}
case .liveStreamMessage:
sliderColor = getLiveStreamStarAmountColorMapping(value: Int64(self.amount.realValue))
}
let _ = self.sliderBackground.update(
@ -1646,7 +1671,8 @@ private final class ChatSendStarsScreenComponent: Component {
theme: environment.theme,
strings: environment.strings,
value: progressFraction,
topCutoff: topCutoffFraction
topCutoff: topCutoffFraction,
color: sliderColor
)),
environment: {},
containerSize: sliderBackgroundFrame.size
@ -1666,7 +1692,8 @@ private final class ChatSendStarsScreenComponent: Component {
transition: transition,
component: AnyComponent(BadgeComponent(
theme: environment.theme,
title: "\(self.amount.realValue)"
title: "\(self.amount.realValue)",
color: sliderColor
)),
environment: {},
containerSize: CGSize(width: 200.0, height: 200.0)
@ -1761,6 +1788,8 @@ private final class ChatSendStarsScreenComponent: Component {
transition.setFrame(view: peerSelectorButtonView, frame: peerSelectorButtonFrame)
peerSelectorButtonView.isHidden = sendAsPeers.count <= 1
}
case .liveStreamMessage:
break
}
if themeUpdated {
@ -1812,6 +1841,8 @@ private final class ChatSendStarsScreenComponent: Component {
case let .react(reactData):
let currentMyPeer = self.currentMyPeer ?? reactData.myPeer
subtitleText = environment.strings.SendStarReactions_SubtitleFrom(currentMyPeer.compactDisplayTitle).string
case .liveStreamMessage:
subtitleText = nil
}
var subtitleSize: CGSize?
@ -1830,6 +1861,9 @@ private final class ChatSendStarsScreenComponent: Component {
switch component.initialData.subjectInitialData {
case .react:
titleText = environment.strings.SendStarReactions_Title
case .liveStreamMessage:
//TODO:localize
titleText = "Highlight and Pin"
}
let titleSize = title.update(
@ -1877,6 +1911,9 @@ private final class ChatSendStarsScreenComponent: Component {
} else {
text = environment.strings.SendStarReactions_TextGeneric(reactData.peer.debugDisplayTitle).string
}
case let .liveStreamMessage(liveStreamMessageData):
//TODO:localize
text = "Highlight and pin a message\nby adding Stars for **\(liveStreamMessageData.peer.displayTitle(strings: environment.strings, displayOrder: .firstLast))**."
}
let body = MarkdownAttributeSet(font: Font.regular(15.0), textColor: environment.theme.list.itemPrimaryTextColor)
@ -2242,6 +2279,8 @@ private final class ChatSendStarsScreenComponent: Component {
}
contentHeight += anonymousContentsSize.height + 27.0
case .liveStreamMessage:
break
}
initialContentHeight = contentHeight
@ -2254,11 +2293,14 @@ private final class ChatSendStarsScreenComponent: Component {
switch component.initialData.subjectInitialData {
case .react:
buttonString = environment.strings.SendStarReactions_SendButtonTitle("\(self.amount.realValue)").string
case .liveStreamMessage:
//TODO:localize
buttonString = "Add # \(self.amount.realValue)"
}
let buttonAttributedString = NSMutableAttributedString(string: buttonString, font: Font.semibold(17.0), textColor: .white, paragraphAlignment: .center)
let buttonAttributedString = NSMutableAttributedString(string: buttonString, font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
if let range = buttonAttributedString.string.range(of: "#"), let starImage = self.cachedStarImage?.0 {
buttonAttributedString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: buttonAttributedString.string))
buttonAttributedString.addAttribute(.foregroundColor, value: UIColor(rgb: 0xffffff), range: NSRange(range, in: buttonAttributedString.string))
buttonAttributedString.addAttribute(.foregroundColor, value: environment.theme.list.itemCheckColors.foregroundColor, range: NSRange(range, in: buttonAttributedString.string))
buttonAttributedString.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: buttonAttributedString.string))
}
@ -2300,6 +2342,9 @@ private final class ChatSendStarsScreenComponent: Component {
switch component.initialData.subjectInitialData {
case let .react(reactData):
purchasePurpose = .reactions(peerId: reactData.peer.id, requiredStars: Int64(self.amount.realValue))
case let .liveStreamMessage(liveStreamMessageData):
//TODO:localize
purchasePurpose = .reactions(peerId: liveStreamMessageData.peer.id, requiredStars: Int64(self.amount.realValue))
}
let purchaseScreen = component.context.sharedContext.makeStarsPurchaseScreen(context: component.context, starsContext: starsContext, options: options, purpose: purchasePurpose, targetPeerId: nil, completion: { result in
@ -2343,6 +2388,13 @@ private final class ChatSendStarsScreenComponent: Component {
sourceView: badgeView.badgeIcon
)
)
case let .liveStreamMessage(liveStreamMessageData):
liveStreamMessageData.completion(
Int64(self.amount.realValue),
ChatSendStarsScreen.TransitionOut(
sourceView: badgeView.badgeIcon
)
)
}
self.environment?.controller()?.dismiss()
}
@ -2486,7 +2538,20 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
}
}
final class LiveStreamMessage {
let peer: EnginePeer
let maxAmount: Int
let completion: (Int64, ChatSendStarsScreen.TransitionOut) -> Void
init(peer: EnginePeer, maxAmount: Int, completion: @escaping (Int64, ChatSendStarsScreen.TransitionOut) -> Void) {
self.peer = peer
self.maxAmount = maxAmount
self.completion = completion
}
}
case react(React)
case liveStreamMessage(LiveStreamMessage)
}
public final class InitialData {
@ -2565,15 +2630,15 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
private var didPlayAppearAnimation: Bool = false
private var isDismissed: Bool = false
private var presenceDisposable: Disposable?
public init(context: AccountContext, initialData: InitialData) {
public init(context: AccountContext, initialData: InitialData, theme: PresentationTheme? = nil) {
self.context = context
super.init(context: context, component: ChatSendStarsScreenComponent(
context: context,
initialData: initialData
), navigationBarAppearance: .none)
), navigationBarAppearance: .none, theme: theme.flatMap {
return .custom($0)
} ?? .default)
self.statusBar.statusBarStyle = .Ignore
self.navigationPresentation = .flatModal
@ -2585,7 +2650,6 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
}
deinit {
self.presenceDisposable?.dispose()
}
override public func viewDidAppear(_ animated: Bool) {
@ -2739,6 +2803,45 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
}
}
public static func initialDataLiveStreamMessage(context: AccountContext, peerId: EnginePeer.Id, completion: @escaping (Int64, TransitionOut) -> Void) -> Signal<InitialData?, NoError> {
let balance: Signal<StarsAmount?, NoError>
if let starsContext = context.starsContext {
balance = starsContext.state
|> map { state in
return state?.balance
}
|> take(1)
} else {
balance = .single(nil)
}
var maxAmount = 10000
if let data = context.currentAppConfiguration.with({ $0 }).data, let value = data["stars_live_stream_pin_amount_max"] as? Double {
maxAmount = Int(value)
}
return combineLatest(
context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId),
),
balance
)
|> map { peer, balance -> InitialData? in
guard let peer else {
return nil
}
return InitialData(
subjectInitialData: .liveStreamMessage(SubjectInitialData.LiveStreamMessage(
peer: peer,
maxAmount: maxAmount,
completion: completion
)),
balance: balance
)
}
}
override public func dismiss(completion: (() -> Void)? = nil) {
if !self.isDismissed {
self.isDismissed = true
@ -3138,3 +3241,25 @@ final class HeaderContextReferenceContentSource: ContextReferenceContentSource {
return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds, actionsPosition: self.actionsOnTop ? .top : .bottom)
}
}
private func getLiveStreamStarAmountColorMapping(value: Int64) -> UIColor {
if value >= 10000 {
return UIColor(rgb: 0x7C8695)
}
if value >= 2000 {
return UIColor(rgb: 0xE6514E)
}
if value >= 500 {
return UIColor(rgb: 0xEE7E20)
}
if value >= 250 {
return UIColor(rgb: 0xE4A20A)
}
if value >= 100 {
return UIColor(rgb: 0x5AB03D)
}
if value >= 50 {
return UIColor(rgb: 0x3E9CDF)
}
return UIColor(rgb: 0x985FDC)
}

View File

@ -261,6 +261,7 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
}
} : nil,
forwardAction: nil,
paidMessageAction: nil,
moreAction: nil,
presentCaptionPositionTooltip: { [weak self] sourceView in
if let self {

View File

@ -1453,6 +1453,7 @@ final class MediaEditorScreenComponent: Component {
controller.presentTimeoutSetup(sourceView: view, gesture: gesture)
},
forwardAction: nil,
paidMessageAction: nil,
moreAction: nil,
presentCaptionPositionTooltip: nil,
presentVoiceMessagesUnavailableTooltip: nil,

View File

@ -275,6 +275,7 @@ final class StoryPreviewComponent: Component {
inputModeAction: nil,
timeoutAction: nil,
forwardAction: {},
paidMessageAction: nil,
moreAction: { _, _ in },
presentCaptionPositionTooltip: nil,
presentVoiceMessagesUnavailableTooltip: nil,

View File

@ -261,6 +261,8 @@ public final class MessageInputActionButtonComponent: Component {
private var backgroundView: GlassBackgroundView?
private let sendIconView: UIImageView
private var reactionHeartView: UIImageView?
private var starsIconView: UIImageView?
private var starsTextView: ComponentView<Empty>?
private var moreButton: MoreHeaderButton?
private var animation: ComponentView<Empty>?
private var reactionIconView: ReactionIconView?
@ -684,6 +686,42 @@ public final class MessageInputActionButtonComponent: Component {
}
}
if case let .stars(amount) = component.mode {
let _ = amount
var starsTransition = transition
let starsIconView: UIImageView
if let current = self.starsIconView {
starsIconView = current
} else {
starsTransition = starsTransition.withAnimation(.none)
starsIconView = UIImageView()
self.starsIconView = starsIconView
starsIconView.image = UIImage(bundleImageName: "Premium/Stars/ButtonStar")?.withRenderingMode(.alwaysTemplate)
starsIconView.tintColor = .white
self.addSubview(starsIconView)
if !transition.animation.isImmediate {
starsIconView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.18)
}
}
if let image = starsIconView.image {
let iconFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - image.size.width) * 0.5), y: floorToScreenPixels((availableSize.height - image.size.height) * 0.5)), size: image.size)
starsTransition.setPosition(view: starsIconView, position: iconFrame.center)
starsTransition.setBounds(view: starsIconView, bounds: CGRect(origin: CGPoint(), size: iconFrame.size))
}
} else {
if let starsIconView = self.starsIconView {
self.starsIconView = nil
starsIconView.removeFromSuperview()
}
if let starsTextView = self.starsTextView {
self.starsTextView = nil
starsTextView.view?.removeFromSuperview()
}
}
transition.setFrame(view: self.button.view, frame: CGRect(origin: .zero, size: availableSize))
transition.setFrame(view: self.containerNode.view, frame: CGRect(origin: .zero, size: availableSize))
transition.setFrame(view: self.referenceNode.view, frame: CGRect(origin: .zero, size: availableSize))

View File

@ -201,6 +201,7 @@ public final class MessageInputPanelComponent: Component {
public let inputModeAction: (() -> Void)?
public let timeoutAction: ((UIView, ContextGesture?) -> Void)?
public let forwardAction: (() -> Void)?
public let paidMessageAction: (() -> Void)?
public let moreAction: ((UIView, ContextGesture?) -> Void)?
public let presentCaptionPositionTooltip: ((UIView) -> Void)?
public let presentVoiceMessagesUnavailableTooltip: ((UIView) -> Void)?
@ -260,6 +261,7 @@ public final class MessageInputPanelComponent: Component {
inputModeAction: (() -> Void)?,
timeoutAction: ((UIView, ContextGesture?) -> Void)?,
forwardAction: (() -> Void)?,
paidMessageAction: (() -> Void)?,
moreAction: ((UIView, ContextGesture?) -> Void)?,
presentCaptionPositionTooltip: ((UIView) -> Void)?,
presentVoiceMessagesUnavailableTooltip: ((UIView) -> Void)?,
@ -318,6 +320,7 @@ public final class MessageInputPanelComponent: Component {
self.inputModeAction = inputModeAction
self.timeoutAction = timeoutAction
self.forwardAction = forwardAction
self.paidMessageAction = paidMessageAction
self.moreAction = moreAction
self.presentCaptionPositionTooltip = presentCaptionPositionTooltip
self.presentVoiceMessagesUnavailableTooltip = presentVoiceMessagesUnavailableTooltip
@ -501,6 +504,7 @@ public final class MessageInputPanelComponent: Component {
private let inputActionButton = ComponentView<Empty>()
private let likeButton = ComponentView<Empty>()
private let stickerButton = ComponentView<Empty>()
private var paidMessageButton: ComponentView<Empty>?
private let timeoutButton = ComponentView<Empty>()
private var mediaRecordingVibrancyContainer: UIView
@ -816,6 +820,11 @@ public final class MessageInputPanelComponent: Component {
if component.bottomInset <= 32.0 && !component.forceIsEditing && !component.hideKeyboard && !self.textFieldExternalState.isEditing {
textFieldSideInset += 18.0
insets.right += 18.0
} else {
#if DEBUG
textFieldSideInset += 8.0
insets.right += 8.0
#endif
}
var mediaInsets = UIEdgeInsets(top: insets.top, left: textFieldSideInset, bottom: insets.bottom, right: 40.0 + 8.0)
@ -1078,6 +1087,10 @@ public final class MessageInputPanelComponent: Component {
} else if isEditing || component.style == .editor || component.style == .media {
fieldBackgroundFrame = fieldFrame
} else {
#if DEBUG
fieldBackgroundFrame = fieldFrame
fieldBackgroundFrame.size.width += 16.0
#else
if component.forwardAction != nil && component.likeAction != nil {
fieldBackgroundFrame = CGRect(origin: CGPoint(x: mediaInsets.left, y: insets.top), size: CGSize(width: availableSize.width - mediaInsets.left - insets.right - 49.0, height: textFieldSize.height))
} else if component.forwardAction != nil {
@ -1085,6 +1098,7 @@ public final class MessageInputPanelComponent: Component {
} else {
fieldBackgroundFrame = CGRect(origin: CGPoint(x: mediaInsets.left, y: insets.top), size: CGSize(width: availableSize.width - mediaInsets.left - 50.0, height: textFieldSize.height))
}
#endif
}
let rawFieldBackgroundFrame = fieldBackgroundFrame
@ -1103,7 +1117,7 @@ public final class MessageInputPanelComponent: Component {
self.fieldBackgroundTint.isHidden = true
}
if let fieldGlassBackgroundView = self.fieldGlassBackgroundView {
fieldGlassBackgroundView.update(size: fieldBackgroundFrame.size, cornerRadius: baseFieldHeight * 0.5, isDark: true, tintColor: component.style == .story ? .init(kind: .panel, color: defaultDarkPresentationTheme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)) : .init(kind: .custom, color: UIColor(rgb: 0x25272e, alpha: 0.72)), transition: transition)
fieldGlassBackgroundView.update(size: fieldBackgroundFrame.size, cornerRadius: baseFieldHeight * 0.5, isDark: true, tintColor: component.style == .story ? .init(kind: .panel, color: defaultDarkPresentationTheme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)) : .init(kind: .custom, color: UIColor(rgb: 0x25272e, alpha: 0.72)), isInteractive: true, transition: transition)
transition.setFrame(view: fieldGlassBackgroundView, frame: fieldBackgroundFrame)
}
default:
@ -1552,22 +1566,35 @@ public final class MessageInputPanelComponent: Component {
if case .story = component.style {
inputActionButtonAvailableSize = CGSize(width: 40.0, height: 40.0)
}
if hasMediaEditing {
inputActionButtonMode = .send
} else {
if let storyItem = component.storyItem, case .liveStream = storyItem.media {
if self.textFieldExternalState.hasText {
if let sendPaidMessageStars = component.sendPaidMessageStars, !"".isEmpty {
inputActionButtonMode = .stars(sendPaidMessageStars.value)
} else {
inputActionButtonMode = .send
}
} else if !isEditing && component.forwardAction != nil {
inputActionButtonMode = .forward
} else {
if component.areVoiceMessagesAvailable {
inputActionButtonMode = self.currentMediaInputIsVoice ? .voiceInput : .videoInput
inputActionButtonMode = .stars(123)
}
} else {
if hasMediaEditing {
inputActionButtonMode = .send
} else {
if self.textFieldExternalState.hasText {
if let sendPaidMessageStars = component.sendPaidMessageStars, !"".isEmpty {
inputActionButtonMode = .stars(sendPaidMessageStars.value)
} else {
inputActionButtonMode = .send
}
} else if !isEditing && component.forwardAction != nil {
inputActionButtonMode = .forward
} else {
inputActionButtonMode = .unavailableVoiceInput
if component.areVoiceMessagesAvailable {
inputActionButtonMode = self.currentMediaInputIsVoice ? .voiceInput : .videoInput
} else {
inputActionButtonMode = .unavailableVoiceInput
}
}
}
}
@ -1803,6 +1830,13 @@ public final class MessageInputPanelComponent: Component {
if isEditing {
inputModeVisible = true
}
var isLiveStream = false
if let storyItem = component.storyItem, case .liveStream = storyItem.media {
isLiveStream = true
}
if isLiveStream && component.sendPaidMessageStars == nil {
inputModeVisible = false
}
let animationName: String
var animationPlay = false
@ -1900,6 +1934,58 @@ public final class MessageInputPanelComponent: Component {
}
}
if let _ = component.paidMessageAction {
let paidMessageButton: ComponentView<Empty>
var paidMessageButtonTransition = transition
if let current = self.paidMessageButton {
paidMessageButton = current
} else {
paidMessageButton = ComponentView()
self.paidMessageButton = paidMessageButton
paidMessageButtonTransition = paidMessageButtonTransition.withAnimation(.none)
}
let paidMessageButtonSize = paidMessageButton.update(
transition: transition,
component: AnyComponent(Button(
content: AnyComponent(BundleIconComponent(
name: "Chat/Input/Text/AccessoryIconSuggestPost",
tintColor: defaultDarkPresentationTheme.chat.inputPanel.inputControlColor
)),
action: { [weak self] in
guard let self else {
return
}
self.component?.paidMessageAction?()
}
).minSize(CGSize(width: 32.0, height: 32.0))),
environment: {},
containerSize: CGSize(width: 32.0, height: 32.0)
)
if let paidMessageButtonView = paidMessageButton.view as? Button.View {
if paidMessageButtonView.superview == nil {
paidMessageButtonView.alpha = 0.0
self.addSubview(paidMessageButtonView)
}
let paidMessageButtonFrame = CGRect(origin: CGPoint(x: fieldIconNextX - paidMessageButtonSize.width, y: fieldBackgroundFrame.maxY - 4.0 - paidMessageButtonSize.height), size: paidMessageButtonSize)
transition.setPosition(view: paidMessageButtonView, position: paidMessageButtonFrame.center)
transition.setBounds(view: paidMessageButtonView, bounds: CGRect(origin: CGPoint(), size: paidMessageButtonFrame.size))
transition.setAlpha(view: paidMessageButtonView, alpha: 1.0)
fieldIconNextX -= paidMessageButtonSize.width + 2.0
}
} else {
if let paidMessageButton = self.paidMessageButton {
self.paidMessageButton = nil
if let paidMessageButtonView = paidMessageButton.view {
transition.setAlpha(view: paidMessageButtonView, alpha: 0.0, completion: { [weak paidMessageButtonView] _ in
paidMessageButtonView?.removeFromSuperview()
})
}
}
}
let accentColor = component.theme.chat.inputPanel.panelControlAccentColor
if let timeoutAction = component.timeoutAction, let timeoutValue = component.timeoutValue {
let timeoutButtonSize = self.timeoutButton.update(

View File

@ -102,6 +102,11 @@ swift_library(
"//submodules/DirectMediaImageCache",
"//submodules/PromptUI",
"//submodules/TelegramCallsUI",
"//submodules/TelegramUI/Components/AsyncListComponent",
"//submodules/Components/MultilineTextWithEntitiesComponent",
"//submodules/Components/MultilineTextComponent",
"//submodules/TelegramUI/Components/Chat/ChatSendStarsScreen",
"//submodules/TelegramUI/Components/GlassBackgroundComponent",
],
visibility = [
"//visibility:public",

View File

@ -68,6 +68,7 @@ public final class StoryContentItem: Equatable {
public let externalState: ExternalState
public let sharedState: SharedState
public let theme: PresentationTheme
public let containerInsets: UIEdgeInsets
public let presentationProgressUpdated: (Double, Bool, Bool) -> Void
public let markAsSeen: (StoryId) -> Void
@ -75,12 +76,14 @@ public final class StoryContentItem: Equatable {
externalState: ExternalState,
sharedState: SharedState,
theme: PresentationTheme,
containerInsets: UIEdgeInsets,
presentationProgressUpdated: @escaping (Double, Bool, Bool) -> Void,
markAsSeen: @escaping (StoryId) -> Void
) {
self.externalState = externalState
self.sharedState = sharedState
self.theme = theme
self.containerInsets = containerInsets
self.presentationProgressUpdated = presentationProgressUpdated
self.markAsSeen = markAsSeen
}
@ -95,6 +98,9 @@ public final class StoryContentItem: Equatable {
if lhs.theme !== rhs.theme {
return false
}
if lhs.containerInsets != rhs.containerInsets {
return false
}
return true
}
}

View File

@ -0,0 +1,849 @@
import Foundation
import UIKit
import Display
import ComponentFlow
import MultilineTextComponent
import AccountContext
import Postbox
import TelegramCore
import TelegramPresentationData
import SwiftSignalKit
import TelegramCallsUI
import AsyncListComponent
import AvatarNode
import MultilineTextWithEntitiesComponent
import GlassBackgroundComponent
import MultilineTextComponent
private final class MessageItemComponent: Component {
let context: AccountContext
let strings: PresentationStrings
let theme: PresentationTheme
let message: GroupCallMessagesContext.Message
init(context: AccountContext, strings: PresentationStrings, theme: PresentationTheme, message: GroupCallMessagesContext.Message) {
self.context = context
self.strings = strings
self.theme = theme
self.message = message
}
static func ==(lhs: MessageItemComponent, rhs: MessageItemComponent) -> Bool {
if lhs === rhs {
return true
}
if lhs.context !== rhs.context {
return false
}
if lhs.strings !== rhs.strings {
return false
}
if lhs.theme !== rhs.theme {
return false
}
if lhs.message != rhs.message {
return false
}
return true
}
final class View: UIView {
private let contentContainer: UIView
private var avatarNode: AvatarNode?
private let text = ComponentView<Empty>()
private var backgroundView: UIImageView?
private var component: MessageItemComponent?
private weak var state: EmptyComponentState?
private var isUpdating: Bool = false
override init(frame: CGRect) {
self.contentContainer = UIView()
self.contentContainer.transform = CGAffineTransformMakeRotation(-CGFloat.pi)
super.init(frame: frame)
self.addSubview(self.contentContainer)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if !self.bounds.contains(point) {
return nil
}
guard let result = super.hitTest(point, with: event) else {
return nil
}
return result
}
func update(component: MessageItemComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.isUpdating = true
defer {
self.isUpdating = false
}
self.component = component
self.state = state
let insets = UIEdgeInsets(top: 8.0, left: 20.0, bottom: 8.0, right: 20.0)
let avatarSize: CGFloat = 24.0
let avatarSpacing: CGFloat = 6.0
let textString = NSMutableAttributedString()
textString.append(NSAttributedString(string: component.message.author?.displayTitle(strings: component.strings, displayOrder: .firstLast) ?? " ", font: Font.semibold(15.0), textColor: UIColor(white: 0.9, alpha: 1.0)))
textString.append(NSAttributedString(string: " ", font: Font.semibold(15.0), textColor: UIColor(white: 0.9, alpha: 1.0)))
textString.append(NSAttributedString(string: component.message.text, font: Font.regular(15.0), textColor: UIColor(white: 1.0, alpha: 1.0)))
let textSize = self.text.update(
transition: .immediate,
component: AnyComponent(MultilineTextWithEntitiesComponent(
context: component.context,
animationCache: component.context.animationCache,
animationRenderer: component.context.animationRenderer,
placeholderColor: .gray,
text: .plain(textString),
maximumNumberOfLines: 0
)),
environment: {},
containerSize: CGSize(width: availableSize.width - insets.left - insets.right - avatarSize - avatarSpacing, height: 100000.0)
)
let size = CGSize(width: availableSize.width, height: insets.top + textSize.height + insets.bottom)
let avatarFrame = CGRect(origin: CGPoint(x: insets.left, y: insets.top - 4.0), size: CGSize(width: avatarSize, height: avatarSize))
do {
let avatarNode: AvatarNode
if let current = self.avatarNode {
avatarNode = current
} else {
avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 10.0))
self.avatarNode = avatarNode
self.contentContainer.addSubview(avatarNode.view)
}
transition.setFrame(view: avatarNode.view, frame: avatarFrame)
avatarNode.updateSize(size: avatarFrame.size)
if let peer = component.message.author {
if peer.smallProfileImage != nil {
avatarNode.setPeerV2(context: component.context, theme: component.theme, peer: peer, displayDimensions: CGSize(width: avatarSize, height: avatarSize))
} else {
avatarNode.setPeer(context: component.context, theme: component.theme, peer: peer, displayDimensions: CGSize(width: avatarSize, height: avatarSize))
}
} else {
avatarNode.setCustomLetters([" "])
}
}
let textFrame = CGRect(origin: CGPoint(x: insets.left + avatarSize + avatarSpacing, y: insets.top), size: textSize)
if let textView = self.text.view {
if textView.superview == nil {
textView.layer.anchorPoint = CGPoint()
self.contentContainer.addSubview(textView)
}
transition.setPosition(view: textView, position: textFrame.origin)
textView.bounds = CGRect(origin: CGPoint(), size: textFrame.size)
}
if let paidStars = component.message.paidStars {
let backgroundView: UIImageView
if let current = self.backgroundView {
backgroundView = current
} else {
backgroundView = UIImageView()
self.backgroundView = backgroundView
self.contentContainer.insertSubview(backgroundView, at: 0)
backgroundView.image = generateStretchableFilledCircleImage(diameter: 28.0, color: .white)?.withRenderingMode(.alwaysTemplate)
}
let backgroundFrame = CGRect(origin: CGPoint(x: 16.0, y: 2.0), size: CGSize(width: textFrame.maxX + 8.0 - 16.0, height: textFrame.maxY + 3.0))
transition.setFrame(view: backgroundView, frame: backgroundFrame)
backgroundView.tintColor = getStarAmountColorMapping(value: paidStars)
} else if let backgroundView = self.backgroundView {
self.backgroundView = nil
backgroundView.removeFromSuperview()
}
let contentFrame = CGRect(origin: CGPoint(), size: size)
transition.setPosition(view: self.contentContainer, position: contentFrame.center)
transition.setBounds(view: self.contentContainer, bounds: CGRect(origin: CGPoint(), size: contentFrame.size))
return size
}
}
func makeView() -> View {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}
private func getStarAmountColorMapping(value: Int64) -> UIColor {
if value >= 10000 {
return UIColor(rgb: 0x7C8695)
}
if value >= 2000 {
return UIColor(rgb: 0xE6514E)
}
if value >= 500 {
return UIColor(rgb: 0xEE7E20)
}
if value >= 250 {
return UIColor(rgb: 0xE4A20A)
}
if value >= 100 {
return UIColor(rgb: 0x5AB03D)
}
if value >= 50 {
return UIColor(rgb: 0x3E9CDF)
}
return UIColor(rgb: 0x985FDC)
}
private final class PinnedBarMessageComponent: Component {
let context: AccountContext
let strings: PresentationStrings
let theme: PresentationTheme
let message: GroupCallMessagesContext.Message
init(context: AccountContext, strings: PresentationStrings, theme: PresentationTheme, message: GroupCallMessagesContext.Message) {
self.context = context
self.strings = strings
self.theme = theme
self.message = message
}
static func ==(lhs: PinnedBarMessageComponent, rhs: PinnedBarMessageComponent) -> Bool {
if lhs === rhs {
return true
}
if lhs.context !== rhs.context {
return false
}
if lhs.strings !== rhs.strings {
return false
}
if lhs.theme !== rhs.theme {
return false
}
if lhs.message != rhs.message {
return false
}
return true
}
final class View: UIView {
private let backgroundView: UIImageView
private let foregroundClippingView: UIView
private let foregroundView: UIImageView
private var avatarNode: AvatarNode?
private let title = ComponentView<Empty>()
private var component: PinnedBarMessageComponent?
private weak var state: EmptyComponentState?
private var isUpdating: Bool = false
private var updateTimer: Foundation.Timer?
override init(frame: CGRect) {
self.backgroundView = UIImageView()
self.foregroundClippingView = UIView()
self.foregroundClippingView.clipsToBounds = true
self.foregroundView = UIImageView()
super.init(frame: frame)
self.addSubview(self.backgroundView)
self.foregroundClippingView.addSubview(self.foregroundView)
self.addSubview(self.foregroundClippingView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.updateTimer?.invalidate()
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if !self.bounds.contains(point) {
return nil
}
guard let result = super.hitTest(point, with: event) else {
return nil
}
return result
}
func update(component: PinnedBarMessageComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.isUpdating = true
defer {
self.isUpdating = false
}
if self.updateTimer == nil {
self.updateTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 1.0 / 30.0, repeats: true, block: { [weak self] _ in
guard let self else {
return
}
if !self.isUpdating {
self.state?.updated(transition: .immediate, isLocal: true)
}
})
}
self.component = component
self.state = state
let itemHeight: CGFloat = 32.0
let avatarInset: CGFloat = 4.0
let avatarSize: CGFloat = 24.0
let avatarSpacing: CGFloat = 6.0
let rightInset: CGFloat = 10.0
let titleSize = self.title.update(
transition: .immediate,
component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: component.message.author?.displayTitle(strings: component.strings, displayOrder: .firstLast) ?? " ", font: Font.semibold(15.0), textColor: .white))
)),
environment: {},
containerSize: CGSize(width: 1000.0, height: itemHeight)
)
let size = CGSize(width: avatarInset + avatarSize + avatarSpacing + titleSize.width + rightInset, height: itemHeight)
if self.backgroundView.image == nil {
self.backgroundView.image = generateStretchableFilledCircleImage(diameter: itemHeight, color: .white)?.withRenderingMode(.alwaysTemplate)
self.foregroundView.image = self.backgroundView.image
}
let baseColor = getStarAmountColorMapping(value: component.message.paidStars ?? 0)
self.backgroundView.tintColor = baseColor.withMultipliedBrightnessBy(0.7)
self.foregroundView.tintColor = baseColor
let timestamp = CFAbsoluteTimeGetCurrent()
let currentDuration = max(0.0, timestamp - Double(component.message.date))
let timeFraction: CGFloat = 1.0 - min(1.0, currentDuration / Double(component.message.lifetime))
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(), size: size))
transition.setFrame(view: self.foregroundView, frame: CGRect(origin: CGPoint(), size: size))
transition.setFrame(view: self.foregroundClippingView, frame: CGRect(origin: CGPoint(), size: CGSize(width: floorToScreenPixels(size.width * timeFraction), height: size.height)))
let avatarFrame = CGRect(origin: CGPoint(x: avatarInset, y: floor((itemHeight - avatarSize) * 0.5)), size: CGSize(width: avatarSize, height: avatarSize))
do {
let avatarNode: AvatarNode
if let current = self.avatarNode {
avatarNode = current
} else {
avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 10.0))
self.avatarNode = avatarNode
self.addSubview(avatarNode.view)
}
transition.setFrame(view: avatarNode.view, frame: avatarFrame)
avatarNode.updateSize(size: avatarFrame.size)
if let peer = component.message.author {
if peer.smallProfileImage != nil {
avatarNode.setPeerV2(context: component.context, theme: component.theme, peer: peer, displayDimensions: CGSize(width: avatarSize, height: avatarSize))
} else {
avatarNode.setPeer(context: component.context, theme: component.theme, peer: peer, displayDimensions: CGSize(width: avatarSize, height: avatarSize))
}
} else {
avatarNode.setCustomLetters([" "])
}
}
let titleFrame = CGRect(origin: CGPoint(x: avatarInset + avatarSize + avatarSpacing, y: floor((itemHeight - titleSize.height) * 0.5)), size: titleSize)
if let titleView = self.title.view {
if titleView.superview == nil {
titleView.layer.anchorPoint = CGPoint()
self.addSubview(titleView)
}
transition.setPosition(view: titleView, position: titleFrame.origin)
titleView.bounds = CGRect(origin: CGPoint(), size: titleFrame.size)
}
return size
}
}
func makeView() -> View {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}
private final class PinnedBarComponent: Component {
let context: AccountContext
let strings: PresentationStrings
let theme: PresentationTheme
let isExpanded: Bool
let messages: [GroupCallMessagesContext.Message]
let toggleExpandedAction: () -> Void
init(context: AccountContext, strings: PresentationStrings, theme: PresentationTheme, isExpanded: Bool, messages: [GroupCallMessagesContext.Message], toggleExpandedAction: @escaping () -> Void) {
self.context = context
self.strings = strings
self.theme = theme
self.isExpanded = isExpanded
self.messages = messages
self.toggleExpandedAction = toggleExpandedAction
}
static func ==(lhs: PinnedBarComponent, rhs: PinnedBarComponent) -> Bool {
if lhs === rhs {
return true
}
if lhs.context !== rhs.context {
return false
}
if lhs.strings !== rhs.strings {
return false
}
if lhs.theme !== rhs.theme {
return false
}
if lhs.isExpanded != rhs.isExpanded {
return false
}
if lhs.messages != rhs.messages {
return false
}
return true
}
final class View: UIView {
private let listContainer: UIView
private let listState = AsyncListComponent.ExternalState()
private let list = ComponentView<Empty>()
private let toggleButtonBackground: GlassBackgroundView
private let toggleButton: HighlightTrackingButton
private let toggleButtonIcon: UIImageView
private var component: PinnedBarComponent?
private weak var state: EmptyComponentState?
private var isUpdating: Bool = false
override init(frame: CGRect) {
self.listContainer = UIView()
self.listContainer.clipsToBounds = true
self.toggleButtonBackground = GlassBackgroundView()
self.toggleButton = HighlightTrackingButton()
self.toggleButtonIcon = UIImageView()
super.init(frame: frame)
self.addSubview(self.listContainer)
self.toggleButtonBackground.contentView.addSubview(self.toggleButtonIcon)
self.toggleButtonBackground.contentView.addSubview(self.toggleButton)
self.addSubview(self.toggleButtonBackground)
self.toggleButton.addTarget(self, action: #selector(self.toggleButtonPressed), for: .touchUpInside)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
}
@objc private func toggleButtonPressed() {
guard let component = self.component else {
return
}
component.toggleExpandedAction()
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if !self.bounds.contains(point) {
return nil
}
guard let result = super.hitTest(point, with: event) else {
return nil
}
return result
}
func update(component: PinnedBarComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.isUpdating = true
defer {
self.isUpdating = false
}
self.component = component
self.state = state
let itemHeight: CGFloat = 32.0
let insets = UIEdgeInsets(top: 16.0, left: 16.0, bottom: 16.0, right: 16.0)
let size = CGSize(width: availableSize.width, height: insets.top + itemHeight + insets.bottom)
let toggleButtonFrame = CGRect(origin: CGPoint(x: insets.left, y: insets.top), size: CGSize(width: itemHeight, height: itemHeight))
transition.setFrame(view: self.toggleButtonBackground, frame: toggleButtonFrame)
self.toggleButtonBackground.update(size: toggleButtonFrame.size, cornerRadius: toggleButtonFrame.height * 0.5, isDark: true, tintColor: .init(kind: .panel, color: component.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)), isInteractive: true, transition: transition)
transition.setFrame(view: self.toggleButton, frame: CGRect(origin: CGPoint(), size: toggleButtonFrame.size))
if self.toggleButtonIcon.image == nil {
self.toggleButtonIcon.image = UIImage(bundleImageName: "Chat/Context Menu/ReactionExpandArrow")?.withRenderingMode(.alwaysTemplate)
self.toggleButtonIcon.tintColor = .white
}
if let image = self.toggleButtonIcon.image {
var iconFrame = image.size.centered(in: CGRect(origin: CGPoint(), size: toggleButtonFrame.size))
iconFrame.origin.y += 1.0
transition.setTransform(view: self.toggleButtonIcon, transform: CATransform3DMakeRotation((!component.isExpanded) ? CGFloat.pi : 0.0, 0.0, 0.0, 1.0))
transition.setPosition(view: self.toggleButtonIcon, position: iconFrame.center)
transition.setBounds(view: self.toggleButtonIcon, bounds: CGRect(origin: CGPoint(), size: iconFrame.size))
}
var listItems: [AnyComponentWithIdentity<Empty>] = []
for message in component.messages {
if let author = message.author {
listItems.append(AnyComponentWithIdentity(id: author.id, component: AnyComponent(PinnedBarMessageComponent(
context: component.context,
strings: component.strings,
theme: component.theme,
message: message
))))
}
}
let listInsets = UIEdgeInsets(top: 0.0, left: 5.0, bottom: 0.0, right: 5.0 + 20.0)
let listFrame = CGRect(origin: CGPoint(x: toggleButtonFrame.maxX, y: 0.0), size: CGSize(width: size.width - toggleButtonFrame.maxX, height: size.height))
let _ = self.list.update(
transition: transition,
component: AnyComponent(AsyncListComponent(
externalState: self.listState,
items: listItems,
itemSetId: AnyHashable(0),
direction: .horizontal,
insets: listInsets
)),
environment: {},
containerSize: listFrame.size
)
if let listView = self.list.view {
if listView.superview == nil {
self.listContainer.addSubview(listView)
}
transition.setPosition(view: listView, position: CGRect(origin: CGPoint(), size: listFrame.size).center)
transition.setBounds(view: listView, bounds: CGRect(origin: CGPoint(), size: listFrame.size))
}
transition.setFrame(view: self.listContainer, frame: listFrame)
return size
}
}
func makeView() -> View {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}
final class StoryContentLiveChatComponent: Component {
let context: AccountContext
let strings: PresentationStrings
let theme: PresentationTheme
let call: PresentationGroupCall
let insets: UIEdgeInsets
init(
context: AccountContext,
strings: PresentationStrings,
theme: PresentationTheme,
call: PresentationGroupCall,
insets: UIEdgeInsets
) {
self.context = context
self.strings = strings
self.theme = theme
self.call = call
self.insets = insets
}
static func ==(lhs: StoryContentLiveChatComponent, rhs: StoryContentLiveChatComponent) -> Bool {
if lhs.context !== rhs.context {
return false
}
if lhs.strings !== rhs.strings {
return false
}
if lhs.theme !== rhs.theme {
return false
}
if lhs.call !== rhs.call {
return false
}
if lhs.insets != rhs.insets {
return false
}
return true
}
final class View: UIView {
private let listContainer: UIView
private let listMaskContainer: UIView
private let maskGradientView: UIImageView
private let pinnedBar = ComponentView<Empty>()
private let listState = AsyncListComponent.ExternalState()
private let list = ComponentView<Empty>()
private let listShadowView: UIView
private var component: StoryContentLiveChatComponent?
private weak var state: EmptyComponentState?
private var isUpdating: Bool = false
private var messagesState: GroupCallMessagesContext.State?
private var stateDisposable: Disposable?
private var isChatExpanded: Bool = false
override init(frame: CGRect) {
self.listContainer = UIView()
self.listMaskContainer = UIView()
self.listContainer.mask = self.listMaskContainer
self.maskGradientView = UIImageView()
do {
let height: CGFloat = 40.0
let baseGradientAlpha: CGFloat = 1.0
let numSteps = 8
let firstStep = 0
let firstLocation = 0.0
let colors = (0 ..< numSteps).map { i -> UIColor in
if i < firstStep {
return UIColor(white: 1.0, alpha: 1.0)
} else {
let step: CGFloat = CGFloat(i - firstStep) / CGFloat(numSteps - firstStep - 1)
let value: CGFloat = 1.0 - bezierPoint(0.42, 0.0, 0.58, 1.0, step)
return UIColor(white: 1.0, alpha: baseGradientAlpha * value)
}
}
let locations = (0 ..< numSteps).map { i -> CGFloat in
if i < firstStep {
return 0.0
} else {
let step: CGFloat = CGFloat(i - firstStep) / CGFloat(numSteps - firstStep - 1)
return (firstLocation + (1.0 - firstLocation) * step)
}
}
let image = generateGradientImage(size: CGSize(width: 8.0, height: height), colors: colors.reversed(), locations: locations.reversed().map { 1.0 - $0 })!
self.maskGradientView.image = generateImage(CGSize(width: image.size.width, height: image.size.height * 2.0), rotatedContext: { size, context in
UIGraphicsPushContext(context)
defer {
UIGraphicsPopContext()
}
context.clear(CGRect(origin: CGPoint(), size: size))
image.draw(in: CGRect(origin: CGPoint(), size: image.size))
let bottomFrame = CGRect(origin: CGPoint(x: 0.0, y: size.height - image.size.height), size: image.size)
context.translateBy(x: bottomFrame.midX, y: bottomFrame.midY)
context.scaleBy(x: 1.0, y: -1.0)
context.translateBy(x: -bottomFrame.midX, y: -bottomFrame.midY)
image.draw(in: bottomFrame)
})!.stretchableImage(withLeftCapWidth: 0, topCapHeight: Int(height - 1.0))
}
self.listMaskContainer.addSubview(self.maskGradientView)
self.listShadowView = UIView()
self.listShadowView.isUserInteractionEnabled = false
super.init(frame: frame)
self.addSubview(self.listShadowView)
self.addSubview(self.listContainer)
self.isChatExpanded = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.stateDisposable?.dispose()
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if !self.bounds.contains(point) {
return nil
}
guard let result = super.hitTest(point, with: event) else {
return nil
}
return result
}
func update(component: StoryContentLiveChatComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.isUpdating = true
defer {
self.isUpdating = false
}
if self.component?.call !== component.call {
self.stateDisposable?.dispose()
if let call = component.call as? PresentationGroupCallImpl {
self.stateDisposable = (call.messagesState
|> deliverOnMainQueue).startStrict(next: { [weak self] state in
guard let self else {
return
}
var updateTransition: ComponentTransition = .easeInOut(duration: 0.2)
if self.messagesState == nil {
updateTransition = .immediate
}
self.messagesState = state
if !self.isUpdating {
self.state?.updated(transition: updateTransition)
}
})
}
}
self.component = component
self.state = state
var listItems: [AnyComponentWithIdentity<Empty>] = []
var topMessageByPeerId: [EnginePeer.Id: GroupCallMessagesContext.Message] = [:]
if let messagesState = self.messagesState {
for message in messagesState.messages.reversed() {
listItems.append(AnyComponentWithIdentity(id: message.id, component: AnyComponent(MessageItemComponent(
context: component.context,
strings: component.strings,
theme: component.theme,
message: message
))))
if let author = message.author, let paidStars = message.paidStars {
if let current = topMessageByPeerId[author.id] {
if let currentPaidStars = current.paidStars, currentPaidStars < paidStars {
topMessageByPeerId[author.id] = message
}
} else {
topMessageByPeerId[author.id] = message
}
}
}
}
let topMessages: [GroupCallMessagesContext.Message] = topMessageByPeerId.values.sorted(by: { lhs, rhs in
let lhsValue = lhs.paidStars ?? 0
let rhsValue = rhs.paidStars ?? 0
if lhsValue != rhsValue {
return lhsValue > rhsValue
}
return lhs.date > rhs.date
})
let pinnedBarSize = self.pinnedBar.update(
transition: transition,
component: AnyComponent(PinnedBarComponent(
context: component.context,
strings: component.strings,
theme: component.theme,
isExpanded: self.isChatExpanded,
messages: topMessages,
toggleExpandedAction: { [weak self] in
guard let self else {
return
}
self.isChatExpanded = !self.isChatExpanded
if !self.isUpdating {
self.state?.updated(transition: .spring(duration: 0.4))
}
}
)),
environment: {},
containerSize: availableSize
)
let pinnedBarFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - component.insets.bottom - pinnedBarSize.height), size: pinnedBarSize)
if let pinnedBarView = self.pinnedBar.view {
if pinnedBarView.superview == nil {
self.addSubview(pinnedBarView)
}
transition.setFrame(view: pinnedBarView, frame: pinnedBarFrame)
transition.setAlpha(view: pinnedBarView, alpha: (listItems.isEmpty && topMessages.isEmpty) ? 0.0 : 1.0)
}
var listInsets = UIEdgeInsets(top: availableSize.height - pinnedBarFrame.minY, left: component.insets.right, bottom: component.insets.top, right: component.insets.left)
listInsets.top += 4.0
let _ = self.list.update(
transition: transition,
component: AnyComponent(AsyncListComponent(
externalState: self.listState,
items: listItems,
itemSetId: AnyHashable(0),
direction: .vertical,
insets: listInsets
)),
environment: {},
containerSize: availableSize
)
let listFrame = CGRect(origin: CGPoint(), size: availableSize)
if let listView = self.list.view {
if listView.superview == nil {
listView.transform = CGAffineTransformMakeRotation(CGFloat.pi)
self.listContainer.addSubview(listView)
}
transition.setPosition(view: listView, position: listFrame.offsetBy(dx: 0.0, dy: self.isChatExpanded ? 0.0 : listFrame.height).center)
transition.setBounds(view: listView, bounds: CGRect(origin: CGPoint(), size: listFrame.size))
}
transition.setFrame(view: self.listContainer, frame: CGRect(origin: CGPoint(), size: availableSize))
transition.setFrame(view: self.listMaskContainer, frame: CGRect(origin: CGPoint(), size: availableSize))
let maskTopInset: CGFloat = component.insets.top - 20.0
let maskBottomInset: CGFloat = availableSize.height - pinnedBarFrame.minY - 26.0
transition.setFrame(view: self.maskGradientView, frame: CGRect(origin: CGPoint(x: 0.0, y: maskTopInset), size: CGSize(width: availableSize.width, height: max(0.0, availableSize.height - maskTopInset - maskBottomInset))))
transition.setFrame(view: self.listShadowView, frame: CGRect(origin: CGPoint(), size: availableSize))
self.listShadowView.backgroundColor = UIColor(white: 0.0, alpha: 0.3)
transition.setAlpha(view: self.listShadowView, alpha: self.isChatExpanded ? 1.0 : 0.0)
return availableSize
}
}
func makeView() -> View {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View File

@ -93,11 +93,13 @@ final class StoryItemContentComponent: Component {
private let imageView: StoryItemImageView
private let overlaysView: StoryItemOverlaysView
private var videoNode: UniversalVideoNode?
private var mediaStreamCall: PresentationGroupCallImpl?
private(set) var mediaStreamCall: PresentationGroupCallImpl?
private var mediaStream: ComponentView<Empty>?
private var loadingEffectView: StoryItemLoadingEffectView?
private var loadingEffectAppearanceTimer: SwiftSignalKit.Timer?
private var liveChat: ComponentView<Empty>?
private var mediaAreasEffectView: StoryItemLoadingEffectView?
private var currentMessageMedia: EngineMedia?
@ -544,6 +546,11 @@ final class StoryItemContentComponent: Component {
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if let liveChatView = self.liveChat?.view {
if let result = liveChatView.hitTest(self.convert(point, to: liveChatView), with: event) {
return result
}
}
if let unsupportedButtonView = self.unsupportedButton?.view {
if let result = unsupportedButtonView.hitTest(self.convert(point, to: unsupportedButtonView), with: event) {
return result
@ -777,6 +784,34 @@ final class StoryItemContentComponent: Component {
})
}
let liveChat: ComponentView<Empty>
if let current = self.liveChat {
liveChat = current
} else {
liveChat = ComponentView()
self.liveChat = liveChat
}
let _ = liveChat.update(
transition: mediaStreamTransition,
component: AnyComponent(StoryContentLiveChatComponent(
context: component.context,
strings: component.strings,
theme: environment.theme,
call: mediaStreamCall,
insets: environment.containerInsets
)),
environment: {},
containerSize: availableSize
)
let liveChatFrame = CGRect(origin: CGPoint(), size: availableSize)
if let liveChatView = liveChat.view {
if liveChatView.superview == nil {
self.insertSubview(liveChatView, aboveSubview: self.imageView)
}
mediaStreamTransition.setFrame(view: liveChatView, frame: liveChatFrame)
}
let _ = mediaStream.update(
transition: mediaStreamTransition,
component: AnyComponent(MediaStreamVideoComponent(
@ -833,6 +868,11 @@ final class StoryItemContentComponent: Component {
mediaStream.view?.removeFromSuperview()
}
if let liveChat = self.liveChat {
self.liveChat = nil
liveChat.view?.removeFromSuperview()
}
if let messageMedia {
var applyState = false
self.imageView.didLoadContents = { [weak self] in

View File

@ -278,6 +278,7 @@ public final class StoryItemSetContainerComponent: Component {
struct ItemLayout {
var containerSize: CGSize
var contentFrame: CGRect
var contentInsets: UIEdgeInsets
var contentMinScale: CGFloat
var contentScaleFraction: CGFloat
var contentOverflowFraction: CGFloat
@ -292,12 +293,14 @@ public final class StoryItemSetContainerComponent: Component {
init(
containerSize: CGSize,
contentFrame: CGRect,
contentInsets: UIEdgeInsets,
contentMinScale: CGFloat,
contentScaleFraction: CGFloat,
contentOverflowFraction: CGFloat
) {
self.containerSize = containerSize
self.contentFrame = contentFrame
self.contentInsets = contentInsets
self.contentMinScale = contentMinScale
self.contentScaleFraction = contentScaleFraction
self.contentOverflowFraction = contentOverflowFraction
@ -1527,6 +1530,7 @@ public final class StoryItemSetContainerComponent: Component {
externalState: visibleItem.externalState,
sharedState: component.storyItemSharedState,
theme: component.theme,
containerInsets: itemLayout.contentInsets,
presentationProgressUpdated: { [weak self, weak visibleItem] progress, isBuffering, canSwitch in
guard let self, let component = self.component else {
return
@ -2575,8 +2579,6 @@ public final class StoryItemSetContainerComponent: Component {
}
let isFirstTime = self.component == nil
let startTime1 = CFAbsoluteTimeGetCurrent()
if self.component == nil {
self.sendMessageContext.setup(context: component.context, view: self, inputPanelExternalState: self.inputPanelExternalState, keyboardInputData: component.keyboardInputData)
@ -2704,6 +2706,11 @@ public final class StoryItemSetContainerComponent: Component {
self.component = component
self.state = state
var isLiveStream = false
if case .liveStream = component.slice.item.storyItem.media {
isLiveStream = true
}
var dismissPanOffset: CGFloat = 0.0
var dismissPanScale: CGFloat = 1.0
var verticalPanFraction: CGFloat = 0.0
@ -2719,8 +2726,6 @@ public final class StoryItemSetContainerComponent: Component {
component.externalState.dismissFraction = dismissFraction
let startTime2 = CFAbsoluteTimeGetCurrent()
transition.setPosition(view: self.componentContainerView, position: CGPoint(x: availableSize.width * 0.5, y: availableSize.height * 0.5 + dismissPanOffset))
transition.setBounds(view: self.componentContainerView, bounds: CGRect(origin: CGPoint(), size: availableSize))
transition.setScale(view: self.componentContainerView, scale: dismissPanScale)
@ -2732,8 +2737,6 @@ public final class StoryItemSetContainerComponent: Component {
transition.setBounds(view: self.overlayContainerView, bounds: CGRect(origin: CGPoint(), size: availableSize))
transition.setScale(view: self.overlayContainerView, scale: dismissPanScale)
let startTime21 = CFAbsoluteTimeGetCurrent()
var bottomContentInset: CGFloat
if !component.safeInsets.bottom.isZero {
bottomContentInset = component.safeInsets.bottom + 1.0
@ -2860,8 +2863,6 @@ public final class StoryItemSetContainerComponent: Component {
}
}
let startTime22 = CFAbsoluteTimeGetCurrent()
var currentHasFirstResponder = false
if let reactionContextNode = self.reactionContextNode {
if hasFirstResponder(reactionContextNode.view) {
@ -2881,8 +2882,6 @@ public final class StoryItemSetContainerComponent: Component {
var inputPanelSize: CGSize?
let _ = inputNodeVisible
let startTime23 = CFAbsoluteTimeGetCurrent()
if showMessageInputPanel {
var haveLikeOptions = false
@ -2902,6 +2901,11 @@ public final class StoryItemSetContainerComponent: Component {
displayAttachmentAction = false
}
var maxInputLength = 4096
if isLiveStream {
maxInputLength = GroupCallMessagesContext.getStarAmountParamMapping(value: self.sendMessageContext.currentLiveStreamMessageStars?.value ?? 0).maxLength
}
inputPanelSize = self.inputPanel.update(
transition: inputPanelTransition,
component: AnyComponent(MessageInputPanelComponent(
@ -2911,8 +2915,8 @@ public final class StoryItemSetContainerComponent: Component {
strings: component.strings,
style: .story,
placeholder: inputPlaceholder,
sendPaidMessageStars: component.slice.additionalPeerData.sendPaidMessageStars,
maxLength: 4096,
sendPaidMessageStars: isLiveStream ? self.sendMessageContext.currentLiveStreamMessageStars : component.slice.additionalPeerData.sendPaidMessageStars,
maxLength: maxInputLength,
queryTypes: [.mention, .hashtag, .emoji],
alwaysDarkWhenHasText: component.metrics.widthClass == .regular,
resetInputContents: resetInputContents,
@ -3020,7 +3024,7 @@ public final class StoryItemSetContainerComponent: Component {
return MessageInputPanelComponent.MyReaction(reaction: value, file: centerAnimation, animationFileId: animationFileId)
},
likeAction: component.slice.effectivePeer.isService ? nil : { [weak self] in
likeAction: (component.slice.effectivePeer.isService || isLiveStream) ? nil : { [weak self] in
guard let self else {
return
}
@ -3045,12 +3049,18 @@ public final class StoryItemSetContainerComponent: Component {
}
},
timeoutAction: nil,
forwardAction: component.slice.item.storyItem.isPublic && !component.slice.item.storyItem.isForwardingDisabled ? { [weak self] in
forwardAction: (!isLiveStream && component.slice.item.storyItem.isPublic && !component.slice.item.storyItem.isForwardingDisabled) ? { [weak self] in
guard let self else {
return
}
self.sendMessageContext.performShareAction(view: self)
} : nil,
paidMessageAction: (isLiveStream && self.sendMessageContext.currentLiveStreamMessageStars == nil) ? { [weak self] in
guard let self else {
return
}
self.sendMessageContext.performPaidMessageAction(view: self)
} : nil,
moreAction: { [weak self] sourceView, gesture in
guard let self else {
return
@ -3129,8 +3139,6 @@ public final class StoryItemSetContainerComponent: Component {
)
}
let startTime3 = CFAbsoluteTimeGetCurrent()
var inputPanelInset: CGFloat = component.containerInsets.bottom
var inputHeight = component.inputHeight
@ -3211,14 +3219,18 @@ public final class StoryItemSetContainerComponent: Component {
inputPanelIsOverlay = true
}
var inputPanelFrameValue: CGRect?
if let inputPanelSize {
let inputPanelFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - inputPanelSize.width) / 2.0), y: availableSize.height - inputPanelBottomInset - inputPanelSize.height), size: inputPanelSize)
inputPanelFrameValue = inputPanelFrame
}
var minimizedBottomContentHeight: CGFloat = 0.0
var maximizedBottomContentHeight: CGFloat = 0.0
let minimizedHeight = max(100.0, availableSize.height - (325.0 + 12.0))
let defaultHeight = 60.0 + component.safeInsets.bottom + 1.0
let startTime4 = CFAbsoluteTimeGetCurrent()
var validViewListIds: [StoryId] = []
var displayViewLists = false
@ -3717,8 +3729,6 @@ public final class StoryItemSetContainerComponent: Component {
self.viewLists.removeValue(forKey: id)
}
let startTime5 = CFAbsoluteTimeGetCurrent()
let itemSize = CGSize(width: availableSize.width, height: ceil(availableSize.width * 1.77778))
let contentDefaultBottomInset: CGFloat = bottomContentInset
@ -3751,6 +3761,10 @@ public final class StoryItemSetContainerComponent: Component {
}
let contentFrame = CGRect(origin: CGPoint(x: 0.0, y: component.containerInsets.top - (contentSize.height - contentVisualHeight) * 0.5 - contentBottomInsetOverflow), size: contentSize)
var contentInsets = UIEdgeInsets(top: 54.0, left: 0.0, bottom: 0.0, right: 0.0)
if let inputPanelFrameValue {
contentInsets.bottom = max(0.0, contentFrame.maxY - (inputPanelFrameValue.minY + 8.0))
}
transition.setFrame(view: self.viewListsContainer, frame: CGRect(origin: CGPoint(x: contentFrame.minX, y: 0.0), size: CGSize(width: contentSize.width, height: availableSize.height)))
let viewListsRadius: CGFloat
@ -3766,6 +3780,7 @@ public final class StoryItemSetContainerComponent: Component {
let itemLayout = ItemLayout(
containerSize: availableSize,
contentFrame: contentFrame,
contentInsets: contentInsets,
contentMinScale: contentMinScale,
contentScaleFraction: contentScaleFraction,
contentOverflowFraction: contentOverflowFraction
@ -3882,8 +3897,6 @@ public final class StoryItemSetContainerComponent: Component {
}
}
let startTime6 = CFAbsoluteTimeGetCurrent()
let soundButtonState = isSilentVideo || component.isAudioMuted
let soundButtonSize = self.soundButton.update(
transition: transition,
@ -4061,11 +4074,6 @@ public final class StoryItemSetContainerComponent: Component {
let focusedItem: StoryContentItem? = component.slice.item
var isLiveStream = false
if case .liveStream = component.slice.item.storyItem.media {
isLiveStream = true
}
var currentLeftInfoItem: InfoItem?
if focusedItem != nil {
let leftInfoComponent = AnyComponent(StoryAvatarInfoComponent(context: component.context, peer: component.slice.effectivePeer, isLiveStream: isLiveStream))
@ -4204,18 +4212,12 @@ public final class StoryItemSetContainerComponent: Component {
}
}
let startTime7 = CFAbsoluteTimeGetCurrent()
let topGradientHeight: CGFloat = 90.0
let topContentGradientRect = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: contentFrame.width, height: topGradientHeight))
transition.setPosition(view: self.topContentGradientView, position: topContentGradientRect.center)
transition.setBounds(view: self.topContentGradientView, bounds: CGRect(origin: CGPoint(), size: topContentGradientRect.size))
var inputPanelFrameValue: CGRect?
if let inputPanelSize {
let inputPanelFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - inputPanelSize.width) / 2.0), y: availableSize.height - inputPanelBottomInset - inputPanelSize.height), size: inputPanelSize)
inputPanelFrameValue = inputPanelFrame
if let inputPanelFrame = inputPanelFrameValue {
var inputPanelAlpha: CGFloat = (component.hideUI || self.isEditingStory || component.slice.item.storyItem.isPending) ? 0.0 : 1.0
if case .liveStream = component.slice.item.storyItem.media {
} else if component.slice.effectivePeer.id == component.context.account.peerId {
@ -4462,7 +4464,7 @@ public final class StoryItemSetContainerComponent: Component {
captionItemTransition.setAlpha(view: captionItemView, alpha: captionAlpha)
}
}
let reactionsAnchorRect: CGRect
if self.inputPanelExternalState.isEditing, let inputPanelFrameValue {
@ -4499,6 +4501,9 @@ public final class StoryItemSetContainerComponent: Component {
if self.sendMessageContext.currentInputMode != .text {
effectiveDisplayReactions = false
}
if case .liveStream = component.slice.item.storyItem.media {
effectiveDisplayReactions = false
}
if let reactionContextNode = self.reactionContextNode, self.willDismissReactionContextNode !== reactionContextNode, (reactionContextNode.isReactionSearchActive && !reactionContextNode.isAnimatingOutToReaction && !reactionContextNode.isAnimatingOut) {
effectiveDisplayReactions = true
@ -4925,6 +4930,9 @@ public final class StoryItemSetContainerComponent: Component {
}
}
var dimAlpha: CGFloat = (inputPanelIsOverlay || self.inputPanelExternalState.isEditing) ? 1.0 : normalDimAlpha
if case .liveStream = component.slice.item.storyItem.media {
dimAlpha = normalDimAlpha
}
if component.hideUI || self.viewListDisplayState != .hidden || self.isEditingStory {
dimAlpha = 0.0
}
@ -4964,14 +4972,10 @@ public final class StoryItemSetContainerComponent: Component {
}
}
let startTime8 = CFAbsoluteTimeGetCurrent()
self.ignoreScrolling = false
self.updateScrolling(transition: itemsTransition)
let startTime9 = CFAbsoluteTimeGetCurrent()
let navigationStripSideInset: CGFloat = 8.0
let navigationStripTopInset: CGFloat = 8.0
if let focusedItem, let visibleItem = self.visibleItems[focusedItem.id], let index = focusedItem.position {
@ -5051,23 +5055,6 @@ public final class StoryItemSetContainerComponent: Component {
}
}
if !"".isEmpty {
print("inner update time:\n" +
" 1: \((CFAbsoluteTimeGetCurrent() - startTime1) * 1000.0) ms\n" +
" 2: \((CFAbsoluteTimeGetCurrent() - startTime2) * 1000.0) ms\n" +
" 2.1: \((CFAbsoluteTimeGetCurrent() - startTime21) * 1000.0) ms\n" +
" 2.2: \((CFAbsoluteTimeGetCurrent() - startTime22) * 1000.0) ms\n" +
" 2.3: \((CFAbsoluteTimeGetCurrent() - startTime23) * 1000.0) ms\n" +
" 3: \((CFAbsoluteTimeGetCurrent() - startTime3) * 1000.0) ms\n" +
" 4: \((CFAbsoluteTimeGetCurrent() - startTime4) * 1000.0) ms\n" +
" 5: \((CFAbsoluteTimeGetCurrent() - startTime5) * 1000.0) ms\n" +
" 6: \((CFAbsoluteTimeGetCurrent() - startTime6) * 1000.0) ms\n" +
" 7: \((CFAbsoluteTimeGetCurrent() - startTime7) * 1000.0) ms\n" +
" 8: \((CFAbsoluteTimeGetCurrent() - startTime8) * 1000.0) ms\n" +
" 9: \((CFAbsoluteTimeGetCurrent() - startTime9) * 1000.0) ms\n"
)
}
if let scheduledStoryUnpinnedUndoOverlay = self.scheduledStoryUnpinnedUndoOverlay {
self.scheduledStoryUnpinnedUndoOverlay = nil
if !self.isAnimatingOut && !component.isDismissed {

View File

@ -51,6 +51,7 @@ import ReactionSelectionNode
import StoryQualityUpgradeSheetScreen
import AudioWaveform
import ChatMessagePaymentAlertController
import ChatSendStarsScreen
private var ObjCKey_DeinitWatcher: Int?
@ -101,6 +102,8 @@ final class StoryItemSetContainerSendMessage {
var currentSpeechHolder: SpeechSynthesizerHolder?
var currentLiveStreamMessageStars: StarsAmount?
private(set) var isMediaRecordingLocked: Bool = false
var wasRecordingDismissed: Bool = false
@ -581,6 +584,43 @@ final class StoryItemSetContainerSendMessage {
silentPosting: Bool = false,
scheduleTime: Int32? = nil
) {
guard let component = view.component else {
return
}
if case .liveStream = component.slice.item.storyItem.media {
if let visibleItem = view.visibleItems[component.slice.item.id], let itemView = visibleItem.view.view as? StoryItemContentComponent.View {
if let call = itemView.mediaStreamCall {
let focusedItem = component.slice.item
guard let peerId = focusedItem.peerId else {
return
}
guard let inputPanelView = view.inputPanel.view as? MessageInputPanelComponent.View else {
return
}
switch inputPanelView.getSendMessageInput() {
case let .text(text):
if !text.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
let entities = generateChatInputTextEntities(text)
call.sendMessage(text: text.string, entities: entities, paidStars: self.currentLiveStreamMessageStars?.value)
component.storyItemSharedState.replyDrafts.removeValue(forKey: StoryId(peerId: peerId, id: focusedItem.storyItem.id))
inputPanelView.clearSendMessageInput(updateState: true)
self.currentInputMode = .text
self.currentLiveStreamMessageStars = nil
view.state?.updated(transition: .spring(duration: 0.3))
let controller = component.controller() as? StoryContainerScreen
controller?.requestLayout(forceUpdate: true, transition: .animated(duration: 0.3, curve: .spring))
}
}
}
}
return
}
self.performWithPossibleStealthModeConfirmation(view: view, action: { [weak self, weak view] in
guard let self, let view else {
return
@ -1201,6 +1241,40 @@ final class StoryItemSetContainerSendMessage {
}
}
func performPaidMessageAction(view: StoryItemSetContainerComponent.View) {
Task { @MainActor [weak view] in
guard let view else {
return
}
guard let component = view.component else {
return
}
guard let controller = component.controller() else {
return
}
let focusedItem = component.slice.item
guard let peerId = focusedItem.peerId else {
return
}
let initialData = await ChatSendStarsScreen.initialDataLiveStreamMessage(context: component.context, peerId: peerId, completion: { [weak self, weak view] amount, _ in
guard let self, let view else {
return
}
self.currentLiveStreamMessageStars = StarsAmount(value: amount, nanos: 0)
view.state?.updated(transition: .spring(duration: 0.4))
}).get()
if let initialData {
controller.push(ChatSendStarsScreen(
context: component.context,
initialData: initialData,
theme: component.theme
))
}
}
}
func performShareTextAction(view: StoryItemSetContainerComponent.View, text: String) {
guard let component = view.component else {
return

View File

@ -369,9 +369,11 @@ public final class TabBarComponent: Component {
if let nativeTabBar = self.nativeTabBar {
if previousComponent?.items.map(\.item.title) != component.items.map(\.item.title) {
nativeTabBar.items = (0 ..< component.items.count).map { i in
let items: [UITabBarItem] = (0 ..< component.items.count).map { i in
return UITabBarItem(title: component.items[i].item.title, image: nil, tag: i)
}
//items.append(UITabBarItem(tabBarSystemItem: .search, tag: 100))
nativeTabBar.items = items
for (_, itemView) in self.itemViews {
itemView.view?.removeFromSuperview()
}