Update API

This commit is contained in:
Ilya Laktyushin 2026-02-10 12:58:04 +04:00
parent 25952cfef6
commit 189d25c32e
59 changed files with 983 additions and 393 deletions

View file

@ -15762,6 +15762,7 @@ Error: %8$@";
"LeaveGroup.Title" = "Leave %@";
"LeaveGroup.Text" = "If you leave, **%1$@** will become the owner of **%2$@** in **1 week**.";
"LeaveGroup.LegacyGroupText" = "If you leave, **%1$@** will immediately become the owner of **%2$@**.";
"LeaveGroup.AppointAnotherOwner" = "Appoint Another Owner";
"LeaveGroup.Proceed" = "Leave Group";
"AppointAnotherOwner.Title" = "Choose New Owner";
@ -15770,6 +15771,8 @@ Error: %8$@";
"Group.OwnershipTransfer.DescriptionShortInfo" = "This will transfer the full **owner rights** for **%1$@** to **%2$@**.";
"FormattedDate.InSeconds_1" = "in %@ second";
"FormattedDate.InSeconds_any" = "in %@ seconds";
"FormattedDate.InMinutes_1" = "in %@ minute";
"FormattedDate.InMinutes_any" = "in %@ minutes";
"FormattedDate.InHours_1" = "in %@ hour";
@ -15777,9 +15780,24 @@ Error: %8$@";
"FormattedDate.InDays_1" = "in %@ day";
"FormattedDate.InDays_any" = "in %@ days";
"FormattedDate.SecondsAgo_1" = "%@ second ago";
"FormattedDate.SecondsAgo_any" = "%@ seconds ago";
"FormattedDate.MinutesAgo_1" = "%@ minute ago";
"FormattedDate.MinutesAgo_any" = "%@ minutes ago";
"FormattedDate.HoursAgo_1" = "%@ hour ago";
"FormattedDate.HoursAgo_any" = "%@ hours ago";
"FormattedDate.DaysAgo_1" = "%@ day ago";
"FormattedDate.DaysAgo_any" = "%@ days ago";
"FormattedDate.LongDate_m1" = "January %1$@, %2$@";
"FormattedDate.LongDate_m2" = "February %1$@, %2$@";
"FormattedDate.LongDate_m3" = "March %1$@, %2$@";
"FormattedDate.LongDate_m4" = "April %1$@, %2$@";
"FormattedDate.LongDate_m5" = "May %1$@, %2$@";
"FormattedDate.LongDate_m6" = "June %1$@, %2$@";
"FormattedDate.LongDate_m7" = "July %1$@, %2$@";
"FormattedDate.LongDate_m8" = "August %1$@, %2$@";
"FormattedDate.LongDate_m9" = "September %1$@, %2$@";
"FormattedDate.LongDate_m10" = "October %1$@, %2$@";
"FormattedDate.LongDate_m11" = "November %1$@, %2$@";
"FormattedDate.LongDate_m12" = "December %1$@, %2$@";

View file

@ -57,10 +57,18 @@ extension ChatListControllerImpl {
AlertTitleComponent(title: self.presentationData.strings.LeaveGroup_Title(peer.compactDisplayTitle).string)
)
))
let text: String
if case .legacyGroup = peer {
text = self.presentationData.strings.LeaveGroup_LegacyGroupText(nextCreator.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), peer.compactDisplayTitle).string
} else {
text = self.presentationData.strings.LeaveGroup_Text(nextCreator.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), peer.compactDisplayTitle).string
}
content.append(AnyComponentWithIdentity(
id: "text",
component: AnyComponent(
AlertTextComponent(content: .plain(self.presentationData.strings.LeaveGroup_Text(nextCreator.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), peer.compactDisplayTitle).string))
AlertTextComponent(content: .plain(text))
)
))

View file

@ -10,12 +10,13 @@ swift_library(
"-warnings-as-errors",
],
deps = [
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/Display:Display",
"//submodules/TelegramPresentationData:TelegramPresentationData",
"//submodules/TelegramStringFormatting:TelegramStringFormatting",
"//submodules/SegmentedControlNode:SegmentedControlNode",
"//submodules/DirectionalPanGesture:DirectionalPanGesture",
"//submodules/AsyncDisplayKit",
"//submodules/Display",
"//submodules/TelegramPresentationData",
"//submodules/TelegramStringFormatting",
"//submodules/SegmentedControlNode",
"//submodules/DirectionalPanGesture",
"//submodules/TextFormat",
],
visibility = [
"//visibility:public",

View file

@ -4,6 +4,7 @@ import UIKit
import AsyncDisplayKit
import TelegramPresentationData
import TelegramStringFormatting
import TextFormat
import SegmentedControlNode
import DirectionalPanGesture

View file

@ -9,6 +9,7 @@ import TelegramPresentationData
import ItemListUI
import PresentationDataUtils
import TelegramStringFormatting
import TextFormat
public class ItemListCallListItem: ListViewItem, ItemListItem {
let presentationData: ItemListPresentationData

View file

@ -6,6 +6,7 @@ import SwiftSignalKit
import TelegramCore
import AccountContext
import TelegramStringFormatting
import TextFormat
import TelegramPresentationData
import ComponentFlow
import AlertComponent

View file

@ -9,6 +9,7 @@ import TelegramUIPreferences
import ItemListUI
import PresentationDataUtils
import TelegramStringFormatting
import TextFormat
import AccountContext
import DeviceLocationManager
import Geocoding

View file

@ -183,12 +183,12 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1078612597] = { return Api.ChannelLocation.parse_channelLocationEmpty($0) }
dict[-847783593] = { return Api.ChannelMessagesFilter.parse_channelMessagesFilter($0) }
dict[-1798033689] = { return Api.ChannelMessagesFilter.parse_channelMessagesFilterEmpty($0) }
dict[-885426663] = { return Api.ChannelParticipant.parse_channelParticipant($0) }
dict[466961494] = { return Api.ChannelParticipant.parse_channelParticipant($0) }
dict[885242707] = { return Api.ChannelParticipant.parse_channelParticipantAdmin($0) }
dict[1844969806] = { return Api.ChannelParticipant.parse_channelParticipantBanned($0) }
dict[803602899] = { return Api.ChannelParticipant.parse_channelParticipantCreator($0) }
dict[453242886] = { return Api.ChannelParticipant.parse_channelParticipantLeft($0) }
dict[1331723247] = { return Api.ChannelParticipant.parse_channelParticipantSelf($0) }
dict[-1454929382] = { return Api.ChannelParticipant.parse_channelParticipantSelf($0) }
dict[-1268741783] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsAdmins($0) }
dict[338142689] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsBanned($0) }
dict[-1328445861] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsBots($0) }
@ -212,9 +212,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1634294960] = { return Api.ChatInvite.parse_chatInvitePeek($0) }
dict[-1940201511] = { return Api.ChatInviteImporter.parse_chatInviteImporter($0) }
dict[-264117680] = { return Api.ChatOnlines.parse_chatOnlines($0) }
dict[-1070776313] = { return Api.ChatParticipant.parse_chatParticipant($0) }
dict[-1600962725] = { return Api.ChatParticipant.parse_chatParticipantAdmin($0) }
dict[-462696732] = { return Api.ChatParticipant.parse_chatParticipantCreator($0) }
dict[954703838] = { return Api.ChatParticipant.parse_chatParticipant($0) }
dict[56677842] = { return Api.ChatParticipant.parse_chatParticipantAdmin($0) }
dict[-503814216] = { return Api.ChatParticipant.parse_chatParticipantCreator($0) }
dict[1018991608] = { return Api.ChatParticipants.parse_chatParticipants($0) }
dict[-2023500831] = { return Api.ChatParticipants.parse_chatParticipantsForbidden($0) }
dict[476978193] = { return Api.ChatPhoto.parse_chatPhoto($0) }
@ -575,7 +575,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1098720356] = { return Api.MediaArea.parse_mediaAreaVenue($0) }
dict[1235637404] = { return Api.MediaArea.parse_mediaAreaWeather($0) }
dict[-808853502] = { return Api.MediaAreaCoordinates.parse_mediaAreaCoordinates($0) }
dict[-1665888023] = { return Api.Message.parse_message($0) }
dict[988112002] = { return Api.Message.parse_message($0) }
dict[-1868117372] = { return Api.Message.parse_messageEmpty($0) }
dict[2055212554] = { return Api.Message.parse_messageService($0) }
dict[-872240531] = { return Api.MessageAction.parse_messageActionBoostApply($0) }
@ -1119,6 +1119,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1037718609] = { return Api.Update.parse_updateChatParticipantAdd($0) }
dict[-674602590] = { return Api.Update.parse_updateChatParticipantAdmin($0) }
dict[-483443337] = { return Api.Update.parse_updateChatParticipantDelete($0) }
dict[-1115461703] = { return Api.Update.parse_updateChatParticipantRank($0) }
dict[125178264] = { return Api.Update.parse_updateChatParticipants($0) }
dict[-2092401936] = { return Api.Update.parse_updateChatUserTyping($0) }
dict[-1574314746] = { return Api.Update.parse_updateConfig($0) }

View file

@ -1023,6 +1023,7 @@ public extension Api {
public var id: Int32
public var fromId: Api.Peer?
public var fromBoostsApplied: Int32?
public var fromRank: String?
public var peerId: Api.Peer
public var savedPeerId: Api.Peer?
public var fwdFrom: Api.MessageFwdHeader?
@ -1051,12 +1052,13 @@ public extension Api {
public var suggestedPost: Api.SuggestedPost?
public var scheduleRepeatPeriod: Int32?
public var summaryFromLanguage: String?
public init(flags: Int32, flags2: Int32, id: Int32, fromId: Api.Peer?, fromBoostsApplied: Int32?, peerId: Api.Peer, savedPeerId: Api.Peer?, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int64?, viaBusinessBotId: Int64?, replyTo: Api.MessageReplyHeader?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, forwards: Int32?, replies: Api.MessageReplies?, editDate: Int32?, postAuthor: String?, groupedId: Int64?, reactions: Api.MessageReactions?, restrictionReason: [Api.RestrictionReason]?, ttlPeriod: Int32?, quickReplyShortcutId: Int32?, effect: Int64?, factcheck: Api.FactCheck?, reportDeliveryUntilDate: Int32?, paidMessageStars: Int64?, suggestedPost: Api.SuggestedPost?, scheduleRepeatPeriod: Int32?, summaryFromLanguage: String?) {
public init(flags: Int32, flags2: Int32, id: Int32, fromId: Api.Peer?, fromBoostsApplied: Int32?, fromRank: String?, peerId: Api.Peer, savedPeerId: Api.Peer?, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int64?, viaBusinessBotId: Int64?, replyTo: Api.MessageReplyHeader?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, forwards: Int32?, replies: Api.MessageReplies?, editDate: Int32?, postAuthor: String?, groupedId: Int64?, reactions: Api.MessageReactions?, restrictionReason: [Api.RestrictionReason]?, ttlPeriod: Int32?, quickReplyShortcutId: Int32?, effect: Int64?, factcheck: Api.FactCheck?, reportDeliveryUntilDate: Int32?, paidMessageStars: Int64?, suggestedPost: Api.SuggestedPost?, scheduleRepeatPeriod: Int32?, summaryFromLanguage: String?) {
self.flags = flags
self.flags2 = flags2
self.id = id
self.fromId = fromId
self.fromBoostsApplied = fromBoostsApplied
self.fromRank = fromRank
self.peerId = peerId
self.savedPeerId = savedPeerId
self.fwdFrom = fwdFrom
@ -1129,7 +1131,7 @@ public extension Api {
switch self {
case .message(let _data):
if boxed {
buffer.appendInt32(-1665888023)
buffer.appendInt32(988112002)
}
serializeInt32(_data.flags, buffer: buffer, boxed: false)
serializeInt32(_data.flags2, buffer: buffer, boxed: false)
@ -1140,6 +1142,9 @@ public extension Api {
if Int(_data.flags) & Int(1 << 29) != 0 {
serializeInt32(_data.fromBoostsApplied!, buffer: buffer, boxed: false)
}
if Int(_data.flags2) & Int(1 << 12) != 0 {
serializeString(_data.fromRank!, buffer: buffer, boxed: false)
}
_data.peerId.serialize(buffer, true)
if Int(_data.flags) & Int(1 << 28) != 0 {
_data.savedPeerId!.serialize(buffer, true)
@ -1268,7 +1273,7 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .message(let _data):
return ("message", [("flags", _data.flags as Any), ("flags2", _data.flags2 as Any), ("id", _data.id as Any), ("fromId", _data.fromId as Any), ("fromBoostsApplied", _data.fromBoostsApplied as Any), ("peerId", _data.peerId as Any), ("savedPeerId", _data.savedPeerId as Any), ("fwdFrom", _data.fwdFrom as Any), ("viaBotId", _data.viaBotId as Any), ("viaBusinessBotId", _data.viaBusinessBotId as Any), ("replyTo", _data.replyTo as Any), ("date", _data.date as Any), ("message", _data.message as Any), ("media", _data.media as Any), ("replyMarkup", _data.replyMarkup as Any), ("entities", _data.entities as Any), ("views", _data.views as Any), ("forwards", _data.forwards as Any), ("replies", _data.replies as Any), ("editDate", _data.editDate as Any), ("postAuthor", _data.postAuthor as Any), ("groupedId", _data.groupedId as Any), ("reactions", _data.reactions as Any), ("restrictionReason", _data.restrictionReason as Any), ("ttlPeriod", _data.ttlPeriod as Any), ("quickReplyShortcutId", _data.quickReplyShortcutId as Any), ("effect", _data.effect as Any), ("factcheck", _data.factcheck as Any), ("reportDeliveryUntilDate", _data.reportDeliveryUntilDate as Any), ("paidMessageStars", _data.paidMessageStars as Any), ("suggestedPost", _data.suggestedPost as Any), ("scheduleRepeatPeriod", _data.scheduleRepeatPeriod as Any), ("summaryFromLanguage", _data.summaryFromLanguage as Any)])
return ("message", [("flags", _data.flags as Any), ("flags2", _data.flags2 as Any), ("id", _data.id as Any), ("fromId", _data.fromId as Any), ("fromBoostsApplied", _data.fromBoostsApplied as Any), ("fromRank", _data.fromRank as Any), ("peerId", _data.peerId as Any), ("savedPeerId", _data.savedPeerId as Any), ("fwdFrom", _data.fwdFrom as Any), ("viaBotId", _data.viaBotId as Any), ("viaBusinessBotId", _data.viaBusinessBotId as Any), ("replyTo", _data.replyTo as Any), ("date", _data.date as Any), ("message", _data.message as Any), ("media", _data.media as Any), ("replyMarkup", _data.replyMarkup as Any), ("entities", _data.entities as Any), ("views", _data.views as Any), ("forwards", _data.forwards as Any), ("replies", _data.replies as Any), ("editDate", _data.editDate as Any), ("postAuthor", _data.postAuthor as Any), ("groupedId", _data.groupedId as Any), ("reactions", _data.reactions as Any), ("restrictionReason", _data.restrictionReason as Any), ("ttlPeriod", _data.ttlPeriod as Any), ("quickReplyShortcutId", _data.quickReplyShortcutId as Any), ("effect", _data.effect as Any), ("factcheck", _data.factcheck as Any), ("reportDeliveryUntilDate", _data.reportDeliveryUntilDate as Any), ("paidMessageStars", _data.paidMessageStars as Any), ("suggestedPost", _data.suggestedPost as Any), ("scheduleRepeatPeriod", _data.scheduleRepeatPeriod as Any), ("summaryFromLanguage", _data.summaryFromLanguage as Any)])
case .messageEmpty(let _data):
return ("messageEmpty", [("flags", _data.flags as Any), ("id", _data.id as Any), ("peerId", _data.peerId as Any)])
case .messageService(let _data):
@ -1293,171 +1298,176 @@ public extension Api {
if Int(_1!) & Int(1 << 29) != 0 {
_5 = reader.readInt32()
}
var _6: Api.Peer?
if let signature = reader.readInt32() {
_6 = Api.parse(reader, signature: signature) as? Api.Peer
var _6: String?
if Int(_2!) & Int(1 << 12) != 0 {
_6 = parseString(reader)
}
var _7: Api.Peer?
if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _8: Api.Peer?
if Int(_1!) & Int(1 << 28) != 0 {
if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.Peer
_8 = Api.parse(reader, signature: signature) as? Api.Peer
}
}
var _8: Api.MessageFwdHeader?
var _9: Api.MessageFwdHeader?
if Int(_1!) & Int(1 << 2) != 0 {
if let signature = reader.readInt32() {
_8 = Api.parse(reader, signature: signature) as? Api.MessageFwdHeader
_9 = Api.parse(reader, signature: signature) as? Api.MessageFwdHeader
}
}
var _9: Int64?
if Int(_1!) & Int(1 << 11) != 0 {
_9 = reader.readInt64()
}
var _10: Int64?
if Int(_2!) & Int(1 << 0) != 0 {
if Int(_1!) & Int(1 << 11) != 0 {
_10 = reader.readInt64()
}
var _11: Api.MessageReplyHeader?
var _11: Int64?
if Int(_2!) & Int(1 << 0) != 0 {
_11 = reader.readInt64()
}
var _12: Api.MessageReplyHeader?
if Int(_1!) & Int(1 << 3) != 0 {
if let signature = reader.readInt32() {
_11 = Api.parse(reader, signature: signature) as? Api.MessageReplyHeader
_12 = Api.parse(reader, signature: signature) as? Api.MessageReplyHeader
}
}
var _12: Int32?
_12 = reader.readInt32()
var _13: String?
_13 = parseString(reader)
var _14: Api.MessageMedia?
var _13: Int32?
_13 = reader.readInt32()
var _14: String?
_14 = parseString(reader)
var _15: Api.MessageMedia?
if Int(_1!) & Int(1 << 9) != 0 {
if let signature = reader.readInt32() {
_14 = Api.parse(reader, signature: signature) as? Api.MessageMedia
_15 = Api.parse(reader, signature: signature) as? Api.MessageMedia
}
}
var _15: Api.ReplyMarkup?
var _16: Api.ReplyMarkup?
if Int(_1!) & Int(1 << 6) != 0 {
if let signature = reader.readInt32() {
_15 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup
_16 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup
}
}
var _16: [Api.MessageEntity]?
var _17: [Api.MessageEntity]?
if Int(_1!) & Int(1 << 7) != 0 {
if let _ = reader.readInt32() {
_16 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
_17 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
}
}
var _17: Int32?
if Int(_1!) & Int(1 << 10) != 0 {
_17 = reader.readInt32()
}
var _18: Int32?
if Int(_1!) & Int(1 << 10) != 0 {
_18 = reader.readInt32()
}
var _19: Api.MessageReplies?
var _19: Int32?
if Int(_1!) & Int(1 << 10) != 0 {
_19 = reader.readInt32()
}
var _20: Api.MessageReplies?
if Int(_1!) & Int(1 << 23) != 0 {
if let signature = reader.readInt32() {
_19 = Api.parse(reader, signature: signature) as? Api.MessageReplies
_20 = Api.parse(reader, signature: signature) as? Api.MessageReplies
}
}
var _20: Int32?
var _21: Int32?
if Int(_1!) & Int(1 << 15) != 0 {
_20 = reader.readInt32()
_21 = reader.readInt32()
}
var _21: String?
var _22: String?
if Int(_1!) & Int(1 << 16) != 0 {
_21 = parseString(reader)
_22 = parseString(reader)
}
var _22: Int64?
var _23: Int64?
if Int(_1!) & Int(1 << 17) != 0 {
_22 = reader.readInt64()
_23 = reader.readInt64()
}
var _23: Api.MessageReactions?
var _24: Api.MessageReactions?
if Int(_1!) & Int(1 << 20) != 0 {
if let signature = reader.readInt32() {
_23 = Api.parse(reader, signature: signature) as? Api.MessageReactions
_24 = Api.parse(reader, signature: signature) as? Api.MessageReactions
}
}
var _24: [Api.RestrictionReason]?
var _25: [Api.RestrictionReason]?
if Int(_1!) & Int(1 << 22) != 0 {
if let _ = reader.readInt32() {
_24 = Api.parseVector(reader, elementSignature: 0, elementType: Api.RestrictionReason.self)
_25 = Api.parseVector(reader, elementSignature: 0, elementType: Api.RestrictionReason.self)
}
}
var _25: Int32?
if Int(_1!) & Int(1 << 25) != 0 {
_25 = reader.readInt32()
}
var _26: Int32?
if Int(_1!) & Int(1 << 30) != 0 {
if Int(_1!) & Int(1 << 25) != 0 {
_26 = reader.readInt32()
}
var _27: Int64?
if Int(_2!) & Int(1 << 2) != 0 {
_27 = reader.readInt64()
var _27: Int32?
if Int(_1!) & Int(1 << 30) != 0 {
_27 = reader.readInt32()
}
var _28: Api.FactCheck?
var _28: Int64?
if Int(_2!) & Int(1 << 2) != 0 {
_28 = reader.readInt64()
}
var _29: Api.FactCheck?
if Int(_2!) & Int(1 << 3) != 0 {
if let signature = reader.readInt32() {
_28 = Api.parse(reader, signature: signature) as? Api.FactCheck
_29 = Api.parse(reader, signature: signature) as? Api.FactCheck
}
}
var _29: Int32?
var _30: Int32?
if Int(_2!) & Int(1 << 5) != 0 {
_29 = reader.readInt32()
_30 = reader.readInt32()
}
var _30: Int64?
var _31: Int64?
if Int(_2!) & Int(1 << 6) != 0 {
_30 = reader.readInt64()
_31 = reader.readInt64()
}
var _31: Api.SuggestedPost?
var _32: Api.SuggestedPost?
if Int(_2!) & Int(1 << 7) != 0 {
if let signature = reader.readInt32() {
_31 = Api.parse(reader, signature: signature) as? Api.SuggestedPost
_32 = Api.parse(reader, signature: signature) as? Api.SuggestedPost
}
}
var _32: Int32?
var _33: Int32?
if Int(_2!) & Int(1 << 10) != 0 {
_32 = reader.readInt32()
_33 = reader.readInt32()
}
var _33: String?
var _34: String?
if Int(_2!) & Int(1 << 11) != 0 {
_33 = parseString(reader)
_34 = parseString(reader)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 8) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 29) == 0) || _5 != nil
let _c6 = _6 != nil
let _c7 = (Int(_1!) & Int(1 << 28) == 0) || _7 != nil
let _c8 = (Int(_1!) & Int(1 << 2) == 0) || _8 != nil
let _c9 = (Int(_1!) & Int(1 << 11) == 0) || _9 != nil
let _c10 = (Int(_2!) & Int(1 << 0) == 0) || _10 != nil
let _c11 = (Int(_1!) & Int(1 << 3) == 0) || _11 != nil
let _c12 = _12 != nil
let _c6 = (Int(_2!) & Int(1 << 12) == 0) || _6 != nil
let _c7 = _7 != nil
let _c8 = (Int(_1!) & Int(1 << 28) == 0) || _8 != nil
let _c9 = (Int(_1!) & Int(1 << 2) == 0) || _9 != nil
let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil
let _c11 = (Int(_2!) & Int(1 << 0) == 0) || _11 != nil
let _c12 = (Int(_1!) & Int(1 << 3) == 0) || _12 != nil
let _c13 = _13 != nil
let _c14 = (Int(_1!) & Int(1 << 9) == 0) || _14 != nil
let _c15 = (Int(_1!) & Int(1 << 6) == 0) || _15 != nil
let _c16 = (Int(_1!) & Int(1 << 7) == 0) || _16 != nil
let _c17 = (Int(_1!) & Int(1 << 10) == 0) || _17 != nil
let _c14 = _14 != nil
let _c15 = (Int(_1!) & Int(1 << 9) == 0) || _15 != nil
let _c16 = (Int(_1!) & Int(1 << 6) == 0) || _16 != nil
let _c17 = (Int(_1!) & Int(1 << 7) == 0) || _17 != nil
let _c18 = (Int(_1!) & Int(1 << 10) == 0) || _18 != nil
let _c19 = (Int(_1!) & Int(1 << 23) == 0) || _19 != nil
let _c20 = (Int(_1!) & Int(1 << 15) == 0) || _20 != nil
let _c21 = (Int(_1!) & Int(1 << 16) == 0) || _21 != nil
let _c22 = (Int(_1!) & Int(1 << 17) == 0) || _22 != nil
let _c23 = (Int(_1!) & Int(1 << 20) == 0) || _23 != nil
let _c24 = (Int(_1!) & Int(1 << 22) == 0) || _24 != nil
let _c25 = (Int(_1!) & Int(1 << 25) == 0) || _25 != nil
let _c26 = (Int(_1!) & Int(1 << 30) == 0) || _26 != nil
let _c27 = (Int(_2!) & Int(1 << 2) == 0) || _27 != nil
let _c28 = (Int(_2!) & Int(1 << 3) == 0) || _28 != nil
let _c29 = (Int(_2!) & Int(1 << 5) == 0) || _29 != nil
let _c30 = (Int(_2!) & Int(1 << 6) == 0) || _30 != nil
let _c31 = (Int(_2!) & Int(1 << 7) == 0) || _31 != nil
let _c32 = (Int(_2!) & Int(1 << 10) == 0) || _32 != nil
let _c33 = (Int(_2!) & Int(1 << 11) == 0) || _33 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 && _c27 && _c28 && _c29 && _c30 && _c31 && _c32 && _c33 {
return Api.Message.message(Cons_message(flags: _1!, flags2: _2!, id: _3!, fromId: _4, fromBoostsApplied: _5, peerId: _6!, savedPeerId: _7, fwdFrom: _8, viaBotId: _9, viaBusinessBotId: _10, replyTo: _11, date: _12!, message: _13!, media: _14, replyMarkup: _15, entities: _16, views: _17, forwards: _18, replies: _19, editDate: _20, postAuthor: _21, groupedId: _22, reactions: _23, restrictionReason: _24, ttlPeriod: _25, quickReplyShortcutId: _26, effect: _27, factcheck: _28, reportDeliveryUntilDate: _29, paidMessageStars: _30, suggestedPost: _31, scheduleRepeatPeriod: _32, summaryFromLanguage: _33))
let _c19 = (Int(_1!) & Int(1 << 10) == 0) || _19 != nil
let _c20 = (Int(_1!) & Int(1 << 23) == 0) || _20 != nil
let _c21 = (Int(_1!) & Int(1 << 15) == 0) || _21 != nil
let _c22 = (Int(_1!) & Int(1 << 16) == 0) || _22 != nil
let _c23 = (Int(_1!) & Int(1 << 17) == 0) || _23 != nil
let _c24 = (Int(_1!) & Int(1 << 20) == 0) || _24 != nil
let _c25 = (Int(_1!) & Int(1 << 22) == 0) || _25 != nil
let _c26 = (Int(_1!) & Int(1 << 25) == 0) || _26 != nil
let _c27 = (Int(_1!) & Int(1 << 30) == 0) || _27 != nil
let _c28 = (Int(_2!) & Int(1 << 2) == 0) || _28 != nil
let _c29 = (Int(_2!) & Int(1 << 3) == 0) || _29 != nil
let _c30 = (Int(_2!) & Int(1 << 5) == 0) || _30 != nil
let _c31 = (Int(_2!) & Int(1 << 6) == 0) || _31 != nil
let _c32 = (Int(_2!) & Int(1 << 7) == 0) || _32 != nil
let _c33 = (Int(_2!) & Int(1 << 10) == 0) || _33 != nil
let _c34 = (Int(_2!) & Int(1 << 11) == 0) || _34 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 && _c27 && _c28 && _c29 && _c30 && _c31 && _c32 && _c33 && _c34 {
return Api.Message.message(Cons_message(flags: _1!, flags2: _2!, id: _3!, fromId: _4, fromBoostsApplied: _5, fromRank: _6, peerId: _7!, savedPeerId: _8, fwdFrom: _9, viaBotId: _10, viaBusinessBotId: _11, replyTo: _12, date: _13!, message: _14!, media: _15, replyMarkup: _16, entities: _17, views: _18, forwards: _19, replies: _20, editDate: _21, postAuthor: _22, groupedId: _23, reactions: _24, restrictionReason: _25, ttlPeriod: _26, quickReplyShortcutId: _27, effect: _28, factcheck: _29, reportDeliveryUntilDate: _30, paidMessageStars: _31, suggestedPost: _32, scheduleRepeatPeriod: _33, summaryFromLanguage: _34))
}
else {
return nil

View file

@ -517,6 +517,18 @@ public extension Api {
self.version = version
}
}
public class Cons_updateChatParticipantRank {
public var chatId: Int64
public var userId: Int64
public var rank: String
public var version: Int32
public init(chatId: Int64, userId: Int64, rank: String, version: Int32) {
self.chatId = chatId
self.userId = userId
self.rank = rank
self.version = version
}
}
public class Cons_updateChatParticipants {
public var participants: Api.ChatParticipants
public init(participants: Api.ChatParticipants) {
@ -1485,6 +1497,7 @@ public extension Api {
case updateChatParticipantAdd(Cons_updateChatParticipantAdd)
case updateChatParticipantAdmin(Cons_updateChatParticipantAdmin)
case updateChatParticipantDelete(Cons_updateChatParticipantDelete)
case updateChatParticipantRank(Cons_updateChatParticipantRank)
case updateChatParticipants(Cons_updateChatParticipants)
case updateChatUserTyping(Cons_updateChatUserTyping)
case updateConfig
@ -2017,6 +2030,15 @@ public extension Api {
serializeInt64(_data.userId, buffer: buffer, boxed: false)
serializeInt32(_data.version, buffer: buffer, boxed: false)
break
case .updateChatParticipantRank(let _data):
if boxed {
buffer.appendInt32(-1115461703)
}
serializeInt64(_data.chatId, buffer: buffer, boxed: false)
serializeInt64(_data.userId, buffer: buffer, boxed: false)
serializeString(_data.rank, buffer: buffer, boxed: false)
serializeInt32(_data.version, buffer: buffer, boxed: false)
break
case .updateChatParticipants(let _data):
if boxed {
buffer.appendInt32(125178264)
@ -3100,6 +3122,8 @@ public extension Api {
return ("updateChatParticipantAdmin", [("chatId", _data.chatId as Any), ("userId", _data.userId as Any), ("isAdmin", _data.isAdmin as Any), ("version", _data.version as Any)])
case .updateChatParticipantDelete(let _data):
return ("updateChatParticipantDelete", [("chatId", _data.chatId as Any), ("userId", _data.userId as Any), ("version", _data.version as Any)])
case .updateChatParticipantRank(let _data):
return ("updateChatParticipantRank", [("chatId", _data.chatId as Any), ("userId", _data.userId as Any), ("rank", _data.rank as Any), ("version", _data.version as Any)])
case .updateChatParticipants(let _data):
return ("updateChatParticipants", [("participants", _data.participants as Any)])
case .updateChatUserTyping(let _data):
@ -4233,6 +4257,26 @@ public extension Api {
return nil
}
}
public static func parse_updateChatParticipantRank(_ reader: BufferReader) -> Update? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int64?
_2 = reader.readInt64()
var _3: String?
_3 = parseString(reader)
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.Update.updateChatParticipantRank(Cons_updateChatParticipantRank(chatId: _1!, userId: _2!, rank: _3!, version: _4!))
}
else {
return nil
}
}
public static func parse_updateChatParticipants(_ reader: BufferReader) -> Update? {
var _1: Api.ChatParticipants?
if let signature = reader.readInt32() {

View file

@ -170,11 +170,13 @@ public extension Api {
public var userId: Int64
public var date: Int32
public var subscriptionUntilDate: Int32?
public init(flags: Int32, userId: Int64, date: Int32, subscriptionUntilDate: Int32?) {
public var rank: String?
public init(flags: Int32, userId: Int64, date: Int32, subscriptionUntilDate: Int32?, rank: String?) {
self.flags = flags
self.userId = userId
self.date = date
self.subscriptionUntilDate = subscriptionUntilDate
self.rank = rank
}
}
public class Cons_channelParticipantAdmin {
@ -233,12 +235,14 @@ public extension Api {
public var inviterId: Int64
public var date: Int32
public var subscriptionUntilDate: Int32?
public init(flags: Int32, userId: Int64, inviterId: Int64, date: Int32, subscriptionUntilDate: Int32?) {
public var rank: String?
public init(flags: Int32, userId: Int64, inviterId: Int64, date: Int32, subscriptionUntilDate: Int32?, rank: String?) {
self.flags = flags
self.userId = userId
self.inviterId = inviterId
self.date = date
self.subscriptionUntilDate = subscriptionUntilDate
self.rank = rank
}
}
case channelParticipant(Cons_channelParticipant)
@ -252,7 +256,7 @@ public extension Api {
switch self {
case .channelParticipant(let _data):
if boxed {
buffer.appendInt32(-885426663)
buffer.appendInt32(466961494)
}
serializeInt32(_data.flags, buffer: buffer, boxed: false)
serializeInt64(_data.userId, buffer: buffer, boxed: false)
@ -260,6 +264,9 @@ public extension Api {
if Int(_data.flags) & Int(1 << 0) != 0 {
serializeInt32(_data.subscriptionUntilDate!, buffer: buffer, boxed: false)
}
if Int(_data.flags) & Int(1 << 2) != 0 {
serializeString(_data.rank!, buffer: buffer, boxed: false)
}
break
case .channelParticipantAdmin(let _data):
if boxed {
@ -306,7 +313,7 @@ public extension Api {
break
case .channelParticipantSelf(let _data):
if boxed {
buffer.appendInt32(1331723247)
buffer.appendInt32(-1454929382)
}
serializeInt32(_data.flags, buffer: buffer, boxed: false)
serializeInt64(_data.userId, buffer: buffer, boxed: false)
@ -315,6 +322,9 @@ public extension Api {
if Int(_data.flags) & Int(1 << 1) != 0 {
serializeInt32(_data.subscriptionUntilDate!, buffer: buffer, boxed: false)
}
if Int(_data.flags) & Int(1 << 2) != 0 {
serializeString(_data.rank!, buffer: buffer, boxed: false)
}
break
}
}
@ -322,7 +332,7 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .channelParticipant(let _data):
return ("channelParticipant", [("flags", _data.flags as Any), ("userId", _data.userId as Any), ("date", _data.date as Any), ("subscriptionUntilDate", _data.subscriptionUntilDate as Any)])
return ("channelParticipant", [("flags", _data.flags as Any), ("userId", _data.userId as Any), ("date", _data.date as Any), ("subscriptionUntilDate", _data.subscriptionUntilDate as Any), ("rank", _data.rank as Any)])
case .channelParticipantAdmin(let _data):
return ("channelParticipantAdmin", [("flags", _data.flags as Any), ("userId", _data.userId as Any), ("inviterId", _data.inviterId as Any), ("promotedBy", _data.promotedBy as Any), ("date", _data.date as Any), ("adminRights", _data.adminRights as Any), ("rank", _data.rank as Any)])
case .channelParticipantBanned(let _data):
@ -332,7 +342,7 @@ public extension Api {
case .channelParticipantLeft(let _data):
return ("channelParticipantLeft", [("peer", _data.peer as Any)])
case .channelParticipantSelf(let _data):
return ("channelParticipantSelf", [("flags", _data.flags as Any), ("userId", _data.userId as Any), ("inviterId", _data.inviterId as Any), ("date", _data.date as Any), ("subscriptionUntilDate", _data.subscriptionUntilDate as Any)])
return ("channelParticipantSelf", [("flags", _data.flags as Any), ("userId", _data.userId as Any), ("inviterId", _data.inviterId as Any), ("date", _data.date as Any), ("subscriptionUntilDate", _data.subscriptionUntilDate as Any), ("rank", _data.rank as Any)])
}
}
@ -347,12 +357,17 @@ public extension Api {
if Int(_1!) & Int(1 << 0) != 0 {
_4 = reader.readInt32()
}
var _5: String?
if Int(_1!) & Int(1 << 2) != 0 {
_5 = 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.ChannelParticipant.channelParticipant(Cons_channelParticipant(flags: _1!, userId: _2!, date: _3!, subscriptionUntilDate: _4))
let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.ChannelParticipant.channelParticipant(Cons_channelParticipant(flags: _1!, userId: _2!, date: _3!, subscriptionUntilDate: _4, rank: _5))
}
else {
return nil
@ -470,13 +485,18 @@ public extension Api {
if Int(_1!) & Int(1 << 1) != 0 {
_5 = reader.readInt32()
}
var _6: String?
if Int(_1!) & Int(1 << 2) != 0 {
_6 = 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
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.ChannelParticipant.channelParticipantSelf(Cons_channelParticipantSelf(flags: _1!, userId: _2!, inviterId: _3!, date: _4!, subscriptionUntilDate: _5))
let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.ChannelParticipant.channelParticipantSelf(Cons_channelParticipantSelf(flags: _1!, userId: _2!, inviterId: _3!, date: _4!, subscriptionUntilDate: _5, rank: _6))
}
else {
return nil

View file

@ -5743,6 +5743,23 @@ public extension Api.functions.messages {
})
}
}
public extension Api.functions.messages {
static func editChatParticipantRank(peer: Api.InputPeer, participant: Api.InputPeer, rank: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
buffer.appendInt32(-1609616720)
peer.serialize(buffer, true)
participant.serialize(buffer, true)
serializeString(rank, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.editChatParticipantRank", parameters: [("peer", String(describing: peer)), ("participant", String(describing: participant)), ("rank", String(describing: rank))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
let reader = BufferReader(buffer)
var result: Api.Updates?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Updates
}
return result
})
}
}
public extension Api.functions.messages {
static func editChatPhoto(chatId: Int64, photo: Api.InputChatPhoto) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
@ -9443,6 +9460,22 @@ public extension Api.functions.messages {
})
}
}
public extension Api.functions.messages {
static func toggleChatCustomRanks(peer: Api.InputPeer, enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
buffer.appendInt32(874013158)
peer.serialize(buffer, true)
enabled.serialize(buffer, true)
return (FunctionDescription(name: "messages.toggleChatCustomRanks", parameters: [("peer", String(describing: peer)), ("enabled", String(describing: enabled))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
let reader = BufferReader(buffer)
var result: Api.Updates?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Updates
}
return result
})
}
}
public extension Api.functions.messages {
static func toggleDialogFilterTags(enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()

View file

@ -115,29 +115,41 @@ public extension Api {
public extension Api {
enum ChatParticipant: TypeConstructorDescription {
public class Cons_chatParticipant {
public var flags: Int32
public var userId: Int64
public var inviterId: Int64
public var date: Int32
public init(userId: Int64, inviterId: Int64, date: Int32) {
public var rank: String?
public init(flags: Int32, userId: Int64, inviterId: Int64, date: Int32, rank: String?) {
self.flags = flags
self.userId = userId
self.inviterId = inviterId
self.date = date
self.rank = rank
}
}
public class Cons_chatParticipantAdmin {
public var flags: Int32
public var userId: Int64
public var inviterId: Int64
public var date: Int32
public init(userId: Int64, inviterId: Int64, date: Int32) {
public var rank: String?
public init(flags: Int32, userId: Int64, inviterId: Int64, date: Int32, rank: String?) {
self.flags = flags
self.userId = userId
self.inviterId = inviterId
self.date = date
self.rank = rank
}
}
public class Cons_chatParticipantCreator {
public var flags: Int32
public var userId: Int64
public init(userId: Int64) {
public var rank: String?
public init(flags: Int32, userId: Int64, rank: String?) {
self.flags = flags
self.userId = userId
self.rank = rank
}
}
case chatParticipant(Cons_chatParticipant)
@ -148,25 +160,37 @@ public extension Api {
switch self {
case .chatParticipant(let _data):
if boxed {
buffer.appendInt32(-1070776313)
buffer.appendInt32(954703838)
}
serializeInt32(_data.flags, buffer: buffer, boxed: false)
serializeInt64(_data.userId, buffer: buffer, boxed: false)
serializeInt64(_data.inviterId, buffer: buffer, boxed: false)
serializeInt32(_data.date, buffer: buffer, boxed: false)
if Int(_data.flags) & Int(1 << 0) != 0 {
serializeString(_data.rank!, buffer: buffer, boxed: false)
}
break
case .chatParticipantAdmin(let _data):
if boxed {
buffer.appendInt32(-1600962725)
buffer.appendInt32(56677842)
}
serializeInt32(_data.flags, buffer: buffer, boxed: false)
serializeInt64(_data.userId, buffer: buffer, boxed: false)
serializeInt64(_data.inviterId, buffer: buffer, boxed: false)
serializeInt32(_data.date, buffer: buffer, boxed: false)
if Int(_data.flags) & Int(1 << 0) != 0 {
serializeString(_data.rank!, buffer: buffer, boxed: false)
}
break
case .chatParticipantCreator(let _data):
if boxed {
buffer.appendInt32(-462696732)
buffer.appendInt32(-503814216)
}
serializeInt32(_data.flags, buffer: buffer, boxed: false)
serializeInt64(_data.userId, buffer: buffer, boxed: false)
if Int(_data.flags) & Int(1 << 0) != 0 {
serializeString(_data.rank!, buffer: buffer, boxed: false)
}
break
}
}
@ -174,54 +198,78 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .chatParticipant(let _data):
return ("chatParticipant", [("userId", _data.userId as Any), ("inviterId", _data.inviterId as Any), ("date", _data.date as Any)])
return ("chatParticipant", [("flags", _data.flags as Any), ("userId", _data.userId as Any), ("inviterId", _data.inviterId as Any), ("date", _data.date as Any), ("rank", _data.rank as Any)])
case .chatParticipantAdmin(let _data):
return ("chatParticipantAdmin", [("userId", _data.userId as Any), ("inviterId", _data.inviterId as Any), ("date", _data.date as Any)])
return ("chatParticipantAdmin", [("flags", _data.flags as Any), ("userId", _data.userId as Any), ("inviterId", _data.inviterId as Any), ("date", _data.date as Any), ("rank", _data.rank as Any)])
case .chatParticipantCreator(let _data):
return ("chatParticipantCreator", [("userId", _data.userId as Any)])
return ("chatParticipantCreator", [("flags", _data.flags as Any), ("userId", _data.userId as Any), ("rank", _data.rank as Any)])
}
}
public static func parse_chatParticipant(_ reader: BufferReader) -> ChatParticipant? {
var _1: Int64?
_1 = reader.readInt64()
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
var _3: Int32?
_3 = reader.readInt32()
var _3: Int64?
_3 = reader.readInt64()
var _4: Int32?
_4 = reader.readInt32()
var _5: String?
if Int(_1!) & Int(1 << 0) != 0 {
_5 = parseString(reader)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.ChatParticipant.chatParticipant(Cons_chatParticipant(userId: _1!, inviterId: _2!, date: _3!))
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.ChatParticipant.chatParticipant(Cons_chatParticipant(flags: _1!, userId: _2!, inviterId: _3!, date: _4!, rank: _5))
}
else {
return nil
}
}
public static func parse_chatParticipantAdmin(_ reader: BufferReader) -> ChatParticipant? {
var _1: Int64?
_1 = reader.readInt64()
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
var _3: Int32?
_3 = reader.readInt32()
var _3: Int64?
_3 = reader.readInt64()
var _4: Int32?
_4 = reader.readInt32()
var _5: String?
if Int(_1!) & Int(1 << 0) != 0 {
_5 = parseString(reader)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.ChatParticipant.chatParticipantAdmin(Cons_chatParticipantAdmin(userId: _1!, inviterId: _2!, date: _3!))
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.ChatParticipant.chatParticipantAdmin(Cons_chatParticipantAdmin(flags: _1!, userId: _2!, inviterId: _3!, date: _4!, rank: _5))
}
else {
return nil
}
}
public static func parse_chatParticipantCreator(_ reader: BufferReader) -> ChatParticipant? {
var _1: Int64?
_1 = reader.readInt64()
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
var _3: String?
if Int(_1!) & Int(1 << 0) != 0 {
_3 = parseString(reader)
}
let _c1 = _1 != nil
if _c1 {
return Api.ChatParticipant.chatParticipantCreator(Cons_chatParticipantCreator(userId: _1!))
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
if _c1 && _c2 && _c3 {
return Api.ChatParticipant.chatParticipantCreator(Cons_chatParticipantCreator(flags: _1!, userId: _2!, rank: _3))
}
else {
return nil

View file

@ -12,6 +12,7 @@ import MultilineTextComponent
import BalancedTextComponent
import TelegramPresentationData
import TelegramStringFormatting
import TextFormat
import Markdown
import GlassControls

View file

@ -115,6 +115,7 @@ private var declaredEncodables: Void = {
declareEncodable(ViewCountMessageAttribute.self, f: { ViewCountMessageAttribute(decoder: $0) })
declareEncodable(ForwardCountMessageAttribute.self, f: { ForwardCountMessageAttribute(decoder: $0) })
declareEncodable(BoostCountMessageAttribute.self, f: { BoostCountMessageAttribute(decoder: $0) })
declareEncodable(ParticipantRankMessageAttribute.self, f: { ParticipantRankMessageAttribute(decoder: $0) })
declareEncodable(NotificationInfoMessageAttribute.self, f: { NotificationInfoMessageAttribute(decoder: $0) })
declareEncodable(TelegramMediaAction.self, f: { TelegramMediaAction(decoder: $0) })
declareEncodable(TelegramPeerNotificationSettings.self, f: { TelegramPeerNotificationSettings(decoder: $0) })

View file

@ -59,6 +59,9 @@ func parseTelegramGroupOrChannel(chat: Api.Chat) -> Peer? {
if (flags & Int32(1 << 25)) != 0 {
groupFlags.insert(.copyProtectionEnabled)
}
if (flags & Int32(1 << 19)) != 0 {
groupFlags.insert(.customRanksEnabled)
}
return TelegramGroup(id: PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(id)), title: title, photo: imageRepresentationsForApiChatPhoto(photo), participantCount: Int(participantsCount), role: role, membership: left ? .Left : .Member, flags: groupFlags, defaultBannedRights: defaultBannedRights.flatMap(TelegramChatBannedRights.init(apiBannedRights:)), migrationReference: migrationReference, creationDate: date, version: Int(version))
case let .chatEmpty(chatEmptyData):
let id = chatEmptyData.id
@ -149,7 +152,9 @@ func parseTelegramGroupOrChannel(chat: Api.Chat) -> Peer? {
if (flags2 & Int32(1 << 19)) != 0 {
channelFlags.insert(.displayForumAsTabs)
}
if (flags2 & Int32(1 << 20)) != 0 {
channelFlags.insert(.customRanksEnabled)
}
var storiesHidden: Bool?
if flags2 & (1 << 2) == 0 { // stories_hidden_min
if flags2 & (1 << 1) != 0 {

View file

@ -206,8 +206,8 @@ extension ChannelParticipant {
init(apiParticipant: Api.ChannelParticipant) {
switch apiParticipant {
case let .channelParticipant(channelParticipantData):
let (_, userId, date, subscriptionUntilDate) = (channelParticipantData.flags, channelParticipantData.userId, channelParticipantData.date, channelParticipantData.subscriptionUntilDate)
self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), invitedAt: date, adminInfo: nil, banInfo: nil, rank: nil, subscriptionUntilDate: subscriptionUntilDate)
let (_, userId, date, subscriptionUntilDate, rank) = (channelParticipantData.flags, channelParticipantData.userId, channelParticipantData.date, channelParticipantData.subscriptionUntilDate, channelParticipantData.rank)
self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), invitedAt: date, adminInfo: nil, banInfo: nil, rank: rank, subscriptionUntilDate: subscriptionUntilDate)
case let .channelParticipantCreator(channelParticipantCreatorData):
let (_, userId, adminRights, rank) = (channelParticipantCreatorData.flags, channelParticipantCreatorData.userId, channelParticipantCreatorData.adminRights, channelParticipantCreatorData.rank)
self = .creator(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), adminInfo: ChannelParticipantAdminInfo(rights: TelegramChatAdminRights(apiAdminRights: adminRights) ?? TelegramChatAdminRights(rights: []), promotedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), canBeEditedByAccountPeer: true), rank: rank)
@ -220,8 +220,8 @@ extension ChannelParticipant {
let (flags, userId, _, promotedBy, date, adminRights, rank) = (channelParticipantAdminData.flags, channelParticipantAdminData.userId, channelParticipantAdminData.inviterId, channelParticipantAdminData.promotedBy, channelParticipantAdminData.date, channelParticipantAdminData.adminRights, channelParticipantAdminData.rank)
self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), invitedAt: date, adminInfo: ChannelParticipantAdminInfo(rights: TelegramChatAdminRights(apiAdminRights: adminRights) ?? TelegramChatAdminRights(rights: []), promotedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(promotedBy)), canBeEditedByAccountPeer: (flags & (1 << 0)) != 0), banInfo: nil, rank: rank, subscriptionUntilDate: nil)
case let .channelParticipantSelf(channelParticipantSelfData):
let (_, userId, _, date, subscriptionUntilDate) = (channelParticipantSelfData.flags, channelParticipantSelfData.userId, channelParticipantSelfData.inviterId, channelParticipantSelfData.date, channelParticipantSelfData.subscriptionUntilDate)
self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), invitedAt: date, adminInfo: nil, banInfo: nil, rank: nil, subscriptionUntilDate: subscriptionUntilDate)
let (_, userId, _, date, subscriptionUntilDate, rank) = (channelParticipantSelfData.flags, channelParticipantSelfData.userId, channelParticipantSelfData.inviterId, channelParticipantSelfData.date, channelParticipantSelfData.subscriptionUntilDate, channelParticipantSelfData.rank)
self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), invitedAt: date, adminInfo: nil, banInfo: nil, rank: rank, subscriptionUntilDate: subscriptionUntilDate)
case let .channelParticipantLeft(channelParticipantLeftData):
let (userId) = (channelParticipantLeftData.peer)
self = .member(id: userId.peerId, invitedAt: 0, adminInfo: nil, banInfo: nil, rank: nil, subscriptionUntilDate: nil)

View file

@ -7,14 +7,14 @@ extension GroupParticipant {
init(apiParticipant: Api.ChatParticipant) {
switch apiParticipant {
case let .chatParticipantCreator(chatParticipantCreatorData):
let userId = chatParticipantCreatorData.userId
self = .creator(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)))
let (userId, rank) = (chatParticipantCreatorData.userId, chatParticipantCreatorData.rank)
self = .creator(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), rank: rank)
case let .chatParticipantAdmin(chatParticipantAdminData):
let (userId, inviterId, date) = (chatParticipantAdminData.userId, chatParticipantAdminData.inviterId, chatParticipantAdminData.date)
self = .admin(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), invitedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(inviterId)), invitedAt: date)
let (userId, inviterId, date, rank) = (chatParticipantAdminData.userId, chatParticipantAdminData.inviterId, chatParticipantAdminData.date, chatParticipantAdminData.rank)
self = .admin(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), invitedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(inviterId)), invitedAt: date, rank: rank)
case let .chatParticipant(chatParticipantData):
let (userId, inviterId, date) = (chatParticipantData.userId, chatParticipantData.inviterId, chatParticipantData.date)
self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), invitedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(inviterId)), invitedAt: date)
let (userId, inviterId, date, rank) = (chatParticipantData.userId, chatParticipantData.inviterId, chatParticipantData.date, chatParticipantData.rank)
self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), invitedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(inviterId)), invitedAt: date, rank: rank)
}
}
}

View file

@ -787,8 +787,10 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .CustomEmoji(stickerPack: nil, fileId: documentId)))
case let .messageEntityFormattedDate(messageEntityFormattedDateData):
let (flags, offset, length, date) = (messageEntityFormattedDateData.flags, messageEntityFormattedDateData.offset, messageEntityFormattedDateData.length, messageEntityFormattedDateData.date)
let format: MessageTextEntityType.DateTimeFormat
if (flags & (1 << 0)) != 0 {
let format: MessageTextEntityType.DateTimeFormat?
if flags == 0 {
format = nil
} else if (flags & (1 << 0)) != 0 {
format = .relative
} else {
let timeFormat: MessageTextEntityType.DateTimeFormat.TimeFormat?
@ -819,7 +821,7 @@ extension StoreMessage {
convenience init?(apiMessage: Api.Message, accountPeerId: PeerId, peerIsForum: Bool, namespace: MessageId.Namespace = Namespaces.Message.Cloud) {
switch apiMessage {
case let .message(messageData):
let (flags, flags2, id, fromId, boosts, chatPeerId, savedPeerId, fwdFrom, viaBotId, viaBusinessBotId, replyTo, date, message, media, replyMarkup, entities, views, forwards, replies, editDate, postAuthor, groupingId, reactions, restrictionReason, ttlPeriod, quickReplyShortcutId, messageEffectId, factCheck, reportDeliveryUntilDate, paidMessageStars, suggestedPost, scheduledRepeatPeriod, summaryFromLanguage) = (messageData.flags, messageData.flags2, messageData.id, messageData.fromId, messageData.fromBoostsApplied, messageData.peerId, messageData.savedPeerId, messageData.fwdFrom, messageData.viaBotId, messageData.viaBusinessBotId, messageData.replyTo, messageData.date, messageData.message, messageData.media, messageData.replyMarkup, messageData.entities, messageData.views, messageData.forwards, messageData.replies, messageData.editDate, messageData.postAuthor, messageData.groupedId, messageData.reactions, messageData.restrictionReason, messageData.ttlPeriod, messageData.quickReplyShortcutId, messageData.effect, messageData.factcheck, messageData.reportDeliveryUntilDate, messageData.paidMessageStars, messageData.suggestedPost, messageData.scheduleRepeatPeriod, messageData.summaryFromLanguage)
let (flags, flags2, id, fromId, boosts, rank, chatPeerId, savedPeerId, fwdFrom, viaBotId, viaBusinessBotId, replyTo, date, message, media, replyMarkup, entities, views, forwards, replies, editDate, postAuthor, groupingId, reactions, restrictionReason, ttlPeriod, quickReplyShortcutId, messageEffectId, factCheck, reportDeliveryUntilDate, paidMessageStars, suggestedPost, scheduledRepeatPeriod, summaryFromLanguage) = (messageData.flags, messageData.flags2, messageData.id, messageData.fromId, messageData.fromBoostsApplied, messageData.fromRank, messageData.peerId, messageData.savedPeerId, messageData.fwdFrom, messageData.viaBotId, messageData.viaBusinessBotId, messageData.replyTo, messageData.date, messageData.message, messageData.media, messageData.replyMarkup, messageData.entities, messageData.views, messageData.forwards, messageData.replies, messageData.editDate, messageData.postAuthor, messageData.groupedId, messageData.reactions, messageData.restrictionReason, messageData.ttlPeriod, messageData.quickReplyShortcutId, messageData.effect, messageData.factcheck, messageData.reportDeliveryUntilDate, messageData.paidMessageStars, messageData.suggestedPost, messageData.scheduleRepeatPeriod, messageData.summaryFromLanguage)
var attributes: [MessageAttribute] = []
if (flags2 & (1 << 4)) != 0 {
@ -1069,6 +1071,10 @@ extension StoreMessage {
}
}
if let rank {
attributes.append(ParticipantRankMessageAttribute(rank: rank))
}
if let editDate = editDate {
attributes.append(EditedMessageAttribute(date: editDate, isHidden: (flags & (1 << 21)) != 0))
}

View file

@ -76,6 +76,8 @@ func apiEntitiesFromMessageTextEntities(_ entities: [MessageTextEntity], associa
default:
break
}
default:
break
}
apiEntities.append(.messageEntityFormattedDate(.init(flags: flags, offset: offset, length: length, date: date)))
case .Custom:

View file

@ -1332,7 +1332,7 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
if let current = current as? CachedGroupData, let participants = current.participants {
var updatedParticipants = participants.participants
if updatedParticipants.firstIndex(where: { $0.peerId == userPeerId }) == nil {
updatedParticipants.append(.member(id: userPeerId, invitedBy: inviterPeerId, invitedAt: date))
updatedParticipants.append(.member(id: userPeerId, invitedBy: inviterPeerId, invitedAt: date, rank: nil))
}
return current.withUpdatedParticipants(CachedGroupParticipants(participants: updatedParticipants, version: participants.version))
} else {
@ -1363,12 +1363,12 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
var updatedParticipants = participants.participants
if let index = updatedParticipants.firstIndex(where: { $0.peerId == userPeerId }) {
if isAdmin == .boolTrue {
if case let .member(id, invitedBy, invitedAt) = updatedParticipants[index] {
updatedParticipants[index] = .admin(id: id, invitedBy: invitedBy, invitedAt: invitedAt)
if case let .member(id, invitedBy, invitedAt, rank) = updatedParticipants[index] {
updatedParticipants[index] = .admin(id: id, invitedBy: invitedBy, invitedAt: invitedAt, rank: rank)
}
} else {
if case let .admin(id, invitedBy, invitedAt) = updatedParticipants[index] {
updatedParticipants[index] = .member(id: id, invitedBy: invitedBy, invitedAt: invitedAt)
if case let .admin(id, invitedBy, invitedAt, rank) = updatedParticipants[index] {
updatedParticipants[index] = .member(id: id, invitedBy: invitedBy, invitedAt: invitedAt, rank: rank)
}
}
}
@ -1377,6 +1377,21 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
return current
}
})
case let .updateChatParticipantRank(updateChatParticipantRankData):
let (chatId, userId, rank) = (updateChatParticipantRankData.chatId, updateChatParticipantRankData.userId, updateChatParticipantRankData.rank)
let groupPeerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatId))
let userPeerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
updatedState.updateCachedPeerData(groupPeerId, { current in
if let current = current as? CachedGroupData, let participants = current.participants {
var updatedParticipants = participants.participants
if let index = updatedParticipants.firstIndex(where: { $0.peerId == userPeerId }) {
updatedParticipants[index] = updatedParticipants[index].withUpdated(rank: rank)
}
return current.withUpdatedParticipants(CachedGroupParticipants(participants: updatedParticipants, version: participants.version))
} else {
return current
}
})
case let .updateChatDefaultBannedRights(updateChatDefaultBannedRightsData):
let (peer, defaultBannedRights, version) = (updateChatDefaultBannedRightsData.peer, updateChatDefaultBannedRightsData.defaultBannedRights, updateChatDefaultBannedRightsData.version)
updatedState.updatePeer(peer.peerId, { peer in

View file

@ -62,7 +62,7 @@ class UpdateMessageService: NSObject, MTMessageService {
}
case let .updateShortChatMessage(updateShortChatMessageData):
let (flags, id, fromId, chatId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyHeader, entities, ttlPeriod) = (updateShortChatMessageData.flags, updateShortChatMessageData.id, updateShortChatMessageData.fromId, updateShortChatMessageData.chatId, updateShortChatMessageData.message, updateShortChatMessageData.pts, updateShortChatMessageData.ptsCount, updateShortChatMessageData.date, updateShortChatMessageData.fwdFrom, updateShortChatMessageData.viaBotId, updateShortChatMessageData.replyTo, updateShortChatMessageData.entities, updateShortChatMessageData.ttlPeriod)
let generatedMessage = Api.Message.message(.init(flags: flags, flags2: 0, id: id, fromId: .peerUser(.init(userId: fromId)), fromBoostsApplied: nil, peerId: Api.Peer.peerChat(.init(chatId: chatId)), savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, viaBusinessBotId: nil, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod, quickReplyShortcutId: nil, effect: nil, factcheck: nil, reportDeliveryUntilDate: nil, paidMessageStars: nil, suggestedPost: nil, scheduleRepeatPeriod: nil, summaryFromLanguage: nil))
let generatedMessage = Api.Message.message(.init(flags: flags, flags2: 0, id: id, fromId: .peerUser(.init(userId: fromId)), fromBoostsApplied: nil, fromRank: nil, peerId: Api.Peer.peerChat(.init(chatId: chatId)), savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, viaBusinessBotId: nil, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod, quickReplyShortcutId: nil, effect: nil, factcheck: nil, reportDeliveryUntilDate: nil, paidMessageStars: nil, suggestedPost: nil, scheduleRepeatPeriod: nil, summaryFromLanguage: nil))
let update = Api.Update.updateNewMessage(.init(message: generatedMessage, pts: pts, ptsCount: ptsCount))
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
if groups.count != 0 {
@ -79,7 +79,7 @@ class UpdateMessageService: NSObject, MTMessageService {
let generatedPeerId = Api.Peer.peerUser(.init(userId: userId))
let generatedMessage = Api.Message.message(.init(flags: flags, flags2: 0, id: id, fromId: generatedFromId, fromBoostsApplied: nil, peerId: generatedPeerId, savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, viaBusinessBotId: nil, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod, quickReplyShortcutId: nil, effect: nil, factcheck: nil, reportDeliveryUntilDate: nil, paidMessageStars: nil, suggestedPost: nil, scheduleRepeatPeriod: nil, summaryFromLanguage: nil))
let generatedMessage = Api.Message.message(.init(flags: flags, flags2: 0, id: id, fromId: generatedFromId, fromBoostsApplied: nil, fromRank: nil, peerId: generatedPeerId, savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, viaBusinessBotId: nil, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod, quickReplyShortcutId: nil, effect: nil, factcheck: nil, reportDeliveryUntilDate: nil, paidMessageStars: nil, suggestedPost: nil, scheduleRepeatPeriod: nil, summaryFromLanguage: nil))
let update = Api.Update.updateNewMessage(.init(message: generatedMessage, pts: pts, ptsCount: ptsCount))
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
if groups.count != 0 {

View file

@ -0,0 +1,20 @@
import Foundation
import Postbox
public class ParticipantRankMessageAttribute: MessageAttribute {
public let rank: String
public var associatedMessageIds: [MessageId] = []
public init(rank: String) {
self.rank = rank
}
required public init(decoder: PostboxDecoder) {
self.rank = decoder.decodeStringForKey("r", orElse: "")
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeString(self.rank, forKey: "r")
}
}

View file

@ -1,17 +1,17 @@
import Postbox
public enum GroupParticipant: PostboxCoding, Equatable {
case member(id: PeerId, invitedBy: PeerId, invitedAt: Int32)
case creator(id: PeerId)
case admin(id: PeerId, invitedBy: PeerId, invitedAt: Int32)
case member(id: PeerId, invitedBy: PeerId, invitedAt: Int32, rank: String?)
case creator(id: PeerId, rank: String?)
case admin(id: PeerId, invitedBy: PeerId, invitedAt: Int32, rank: String?)
public var peerId: PeerId {
switch self {
case let .member(id, _, _):
case let .member(id, _, _, _):
return id
case let .creator(id):
case let .creator(id, _):
return id
case let .admin(id, _, _):
case let .admin(id, _, _, _):
return id
}
}
@ -19,44 +19,70 @@ public enum GroupParticipant: PostboxCoding, Equatable {
public init(decoder: PostboxDecoder) {
switch decoder.decodeInt32ForKey("v", orElse: 0) {
case 0:
self = .member(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedBy: PeerId(decoder.decodeInt64ForKey("b", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0))
self = .member(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedBy: PeerId(decoder.decodeInt64ForKey("b", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0), rank: decoder.decodeOptionalStringForKey("r"))
case 1:
self = .creator(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)))
self = .creator(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), rank: decoder.decodeOptionalStringForKey("r"))
case 2:
self = .admin(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedBy: PeerId(decoder.decodeInt64ForKey("b", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0))
self = .admin(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedBy: PeerId(decoder.decodeInt64ForKey("b", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0), rank: decoder.decodeOptionalStringForKey("r"))
default:
self = .member(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedBy: PeerId(decoder.decodeInt64ForKey("b", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0))
self = .member(id: PeerId(decoder.decodeInt64ForKey("i", orElse: 0)), invitedBy: PeerId(decoder.decodeInt64ForKey("b", orElse: 0)), invitedAt: decoder.decodeInt32ForKey("t", orElse: 0), rank: decoder.decodeOptionalStringForKey("r"))
}
}
public func encode(_ encoder: PostboxEncoder) {
switch self {
case let .member(id, invitedBy, invitedAt):
case let .member(id, invitedBy, invitedAt, rank):
encoder.encodeInt32(0, forKey: "v")
encoder.encodeInt64(id.toInt64(), forKey: "i")
encoder.encodeInt64(invitedBy.toInt64(), forKey: "b")
encoder.encodeInt32(invitedAt, forKey: "t")
case let .creator(id):
if let rank {
encoder.encodeString(rank, forKey: "r")
} else {
encoder.encodeNil(forKey: "r")
}
case let .creator(id, rank):
encoder.encodeInt32(1, forKey: "v")
encoder.encodeInt64(id.toInt64(), forKey: "i")
case let .admin(id, invitedBy, invitedAt):
if let rank {
encoder.encodeString(rank, forKey: "r")
} else {
encoder.encodeNil(forKey: "r")
}
case let .admin(id, invitedBy, invitedAt, rank):
encoder.encodeInt32(2, forKey: "v")
encoder.encodeInt64(id.toInt64(), forKey: "i")
encoder.encodeInt64(invitedBy.toInt64(), forKey: "b")
encoder.encodeInt32(invitedAt, forKey: "t")
if let rank {
encoder.encodeString(rank, forKey: "r")
} else {
encoder.encodeNil(forKey: "r")
}
}
}
public var invitedBy: PeerId {
switch self {
case let .admin(_, invitedBy, _):
case let .admin(_, invitedBy, _, _):
return invitedBy
case let .member(_, invitedBy, _):
case let .member(_, invitedBy, _, _):
return invitedBy
case let .creator(id):
case let .creator(id, _):
return id
}
}
func withUpdated(rank: String?) -> GroupParticipant {
switch self {
case let .member(id, invitedBy, invitedAt, _):
return .member(id: id, invitedBy: invitedBy, invitedAt: invitedAt, rank: rank)
case let .admin(id, invitedBy, invitedAt, _):
return .admin(id: id, invitedBy: invitedBy, invitedAt: invitedAt, rank: rank)
case let .creator(id, _):
return .creator(id: id, rank: rank)
}
}
}
public final class CachedGroupParticipants: PostboxCoding, Equatable {

View file

@ -185,6 +185,7 @@ public struct TelegramChannelFlags: OptionSet {
public static let autoTranslateEnabled = TelegramChannelFlags(rawValue: 1 << 12)
public static let isMonoforum = TelegramChannelFlags(rawValue: 1 << 13)
public static let displayForumAsTabs = TelegramChannelFlags(rawValue: 1 << 14)
public static let customRanksEnabled = TelegramChannelFlags(rawValue: 1 << 15)
}
public final class TelegramChannel: Peer, Equatable {

View file

@ -120,6 +120,7 @@ public struct TelegramGroupFlags: OptionSet {
public static let hasVoiceChat = TelegramGroupFlags(rawValue: 1 << 2)
public static let hasActiveVoiceChat = TelegramGroupFlags(rawValue: 1 << 3)
public static let copyProtectionEnabled = TelegramGroupFlags(rawValue: 1 << 4)
public static let customRanksEnabled = TelegramGroupFlags(rawValue: 1 << 5)
}
public struct TelegramGroupToChannelMigrationReference: Equatable {

View file

@ -88,7 +88,7 @@ public enum MessageTextEntityType: Equatable {
case BankCard
case Spoiler
case CustomEmoji(stickerPack: StickerPackReference?, fileId: Int64)
case FormattedDate(format: DateTimeFormat, date: Int32)
case FormattedDate(format: DateTimeFormat?, date: Int32)
case Custom(type: CustomEntityType)
}
@ -143,7 +143,7 @@ public struct MessageTextEntity: PostboxCoding, Codable, Equatable {
let stickerPack = decoder.decodeObjectForKey("s", decoder: { StickerPackReference(decoder: $0) }) as? StickerPackReference
self.type = .CustomEmoji(stickerPack: stickerPack, fileId: decoder.decodeInt64ForKey("f", orElse: 0))
case 19:
self.type = .FormattedDate(format: MessageTextEntityType.DateTimeFormat(rawValue: decoder.decodeInt32ForKey("format", orElse: 0)), date: decoder.decodeInt32ForKey("date", orElse: 0))
self.type = .FormattedDate(format: decoder.decodeOptionalInt32ForKey("format").flatMap { MessageTextEntityType.DateTimeFormat(rawValue: $0) }, date: decoder.decodeInt32ForKey("date", orElse: 0))
case Int32.max:
self.type = .Custom(type: decoder.decodeInt32ForKey("type", orElse: 0))
default:
@ -202,7 +202,7 @@ public struct MessageTextEntity: PostboxCoding, Codable, Equatable {
case 18:
self.type = .CustomEmoji(stickerPack: try container.decodeIfPresent(StickerPackReference.self, forKey: "s"), fileId: try container.decode(Int64.self, forKey: "f"))
case 19:
self.type = .FormattedDate(format: MessageTextEntityType.DateTimeFormat(rawValue: try container.decode(Int32.self, forKey: "format")), date: try container.decode(Int32.self, forKey: "date"))
self.type = .FormattedDate(format: try container.decodeIfPresent(Int32.self, forKey: "format").flatMap { MessageTextEntityType.DateTimeFormat(rawValue: $0) }, date: try container.decode(Int32.self, forKey: "date"))
case Int32.max:
let customType: Int32 = (try? container.decode(Int32.self, forKey: "type")) ?? 0
self.type = .Custom(type: customType)
@ -269,7 +269,11 @@ public struct MessageTextEntity: PostboxCoding, Codable, Equatable {
encoder.encodeInt64(fileId, forKey: "f")
case let .FormattedDate(format, date):
encoder.encodeInt32(19, forKey: "_rawValue")
encoder.encodeInt32(format.rawValue, forKey: "format")
if let format {
encoder.encodeInt32(format.rawValue, forKey: "format")
} else {
encoder.encodeNil(forKey: "format")
}
encoder.encodeInt32(date, forKey: "date")
case let .Custom(type):
encoder.encodeInt32(Int32.max, forKey: "_rawValue")
@ -329,7 +333,7 @@ public struct MessageTextEntity: PostboxCoding, Codable, Equatable {
try container.encode(fileId, forKey: "f")
case let .FormattedDate(format, date):
try container.encode(19 as Int32, forKey: "_rawValue")
try container.encode(format.rawValue, forKey: "format")
try container.encodeIfPresent(format?.rawValue, forKey: "format")
try container.encode(date, forKey: "date")
case let .Custom(type):
try container.encode(Int32.max as Int32, forKey: "_rawValue")

View file

@ -81,42 +81,53 @@ public extension EngineChannelParticipant {
}
public enum EngineLegacyGroupParticipant: Equatable {
case member(id: EnginePeer.Id, invitedBy: EnginePeer.Id, invitedAt: Int32)
case creator(id: EnginePeer.Id)
case admin(id: EnginePeer.Id, invitedBy: EnginePeer.Id, invitedAt: Int32)
case member(id: EnginePeer.Id, invitedBy: EnginePeer.Id, invitedAt: Int32, rank: String?)
case creator(id: EnginePeer.Id, rank: String?)
case admin(id: EnginePeer.Id, invitedBy: EnginePeer.Id, invitedAt: Int32, rank: String?)
public var peerId: EnginePeer.Id {
switch self {
case let .member(id, _, _):
case let .member(id, _, _, _):
return id
case let .creator(id):
case let .creator(id, _):
return id
case let .admin(id, _, _):
case let .admin(id, _, _, _):
return id
}
}
public var rank: String? {
switch self {
case let .member(_, _, _, rank):
return rank
case let .creator(_, rank):
return rank
case let .admin(_, _, _, rank):
return rank
}
}
}
public extension EngineLegacyGroupParticipant {
init(_ participant: GroupParticipant) {
switch participant {
case let .member(id, invitedBy, invitedAt):
self = .member(id: id, invitedBy: invitedBy, invitedAt: invitedAt)
case let .creator(id):
self = .creator(id: id)
case let .admin(id, invitedBy, invitedAt):
self = .admin(id: id, invitedBy: invitedBy, invitedAt: invitedAt)
case let .member(id, invitedBy, invitedAt, rank):
self = .member(id: id, invitedBy: invitedBy, invitedAt: invitedAt, rank: rank)
case let .creator(id, rank):
self = .creator(id: id, rank: rank)
case let .admin(id, invitedBy, invitedAt, rank):
self = .admin(id: id, invitedBy: invitedBy, invitedAt: invitedAt, rank: rank)
}
}
func _asParticipant() -> GroupParticipant {
switch self {
case let .member(id, invitedBy, invitedAt):
return .member(id: id, invitedBy: invitedBy, invitedAt: invitedAt)
case let .creator(id):
return .creator(id: id)
case let .admin(id, invitedBy, invitedAt):
return .admin(id: id, invitedBy: invitedBy, invitedAt: invitedAt)
case let .member(id, invitedBy, invitedAt, rank):
return .member(id: id, invitedBy: invitedBy, invitedAt: invitedAt, rank: rank)
case let .creator(id, rank):
return .creator(id: id, rank: rank)
case let .admin(id, invitedBy, invitedAt, rank):
return .admin(id: id, invitedBy: invitedBy, invitedAt: invitedAt, rank: rank)
}
}
}
@ -2278,17 +2289,19 @@ public extension TelegramEngine.EngineData.Item {
}
var key: PostboxViewKey {
return .basicPeer(self.id)
return .peer(peerId: self.id, components: [.cachedData])
}
func extract(view: PostboxView) -> Result {
guard let view = view as? BasicPeerView else {
guard let view = view as? PeerView else {
preconditionFailure()
}
guard let peer = view.peer else {
guard let peer = peerViewMainPeer(view) else {
return false
}
if let group = peer as? TelegramGroup {
if let cachedPeerData = view.cachedData as? CachedUserData {
return cachedPeerData.flags.contains(.copyProtectionEnabled)
} else if let group = peer as? TelegramGroup {
return group.flags.contains(.copyProtectionEnabled)
} else if let channel = peer as? TelegramChannel {
return channel.flags.contains(.copyProtectionEnabled)

View file

@ -92,7 +92,7 @@ func _internal_addGroupMember(account: Account, peerId: PeerId, memberId: PeerId
}
}
if !found {
updatedParticipants.append(.member(id: memberId, invitedBy: account.peerId, invitedAt: timestamp))
updatedParticipants.append(.member(id: memberId, invitedBy: account.peerId, invitedAt: timestamp, rank: nil))
}
return cachedData.withUpdatedParticipants(CachedGroupParticipants(participants: updatedParticipants, version: participants.version))
} else {

View file

@ -24,8 +24,8 @@ func _internal_removeGroupAdmin(account: Account, peerId: PeerId, adminId: PeerI
for i in 0 ..< updatedParticipants.count {
if updatedParticipants[i].peerId == adminId {
switch updatedParticipants[i] {
case let .admin(id, invitedBy, invitedAt):
updatedParticipants[i] = .member(id: id, invitedBy: invitedBy, invitedAt: invitedAt)
case let .admin(id, invitedBy, invitedAt, rank):
updatedParticipants[i] = .member(id: id, invitedBy: invitedBy, invitedAt: invitedAt, rank: rank)
default:
break
}
@ -93,8 +93,8 @@ func _internal_addGroupAdmin(account: Account, peerId: PeerId, adminId: PeerId)
for i in 0 ..< updatedParticipants.count {
if updatedParticipants[i].peerId == adminId {
switch updatedParticipants[i] {
case let .member(id, invitedBy, invitedAt):
updatedParticipants[i] = .admin(id: id, invitedBy: invitedBy, invitedAt: invitedAt)
case let .member(id, invitedBy, invitedAt, rank):
updatedParticipants[i] = .admin(id: id, invitedBy: invitedBy, invitedAt: invitedAt, rank: rank)
default:
break
}

View file

@ -0,0 +1,46 @@
import Foundation
import Postbox
import SwiftSignalKit
import TelegramApi
import MtProtoKit
func _internal_toggleChatCustomRanks(account: Account, peerId: PeerId, enabled: Bool) -> Signal<Void, NoError> {
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
return account.network.request(Api.functions.messages.toggleChatCustomRanks(peer: inputPeer, enabled: enabled ? .boolTrue : .boolFalse))
|> `catch` { _ in
return .complete()
}
|> map { updates -> Void in
account.stateManager.addUpdates(updates)
}
} else {
return .complete()
}
} |> switchToLatest
}
public enum UpdateChatRankError {
case generic
}
func _internal_updateChatRank(account: Account, peerId: PeerId, userId: PeerId, rank: String?) -> Signal<Never, UpdateChatRankError> {
return account.postbox.transaction { transaction -> Signal<Void, UpdateChatRankError> in
if let user = transaction.getPeer(userId), let inputUser = apiInputPeer(user), let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
return account.network.request(Api.functions.messages.editChatParticipantRank(peer: inputPeer, participant: inputUser, rank: rank ?? ""))
|> mapError { _ -> UpdateChatRankError in
return .generic
}
|> map { updates -> Void in
account.stateManager.addUpdates(updates)
}
} else {
return .fail(.generic)
}
}
|> mapError { _ -> UpdateChatRankError in }
|> switchToLatest
|> ignoreValues
}

View file

@ -616,6 +616,14 @@ public extension TelegramEngine {
public func getFutureCreatorAfterLeave(peerId: EnginePeer.Id) -> Signal<EnginePeer?, NoError> {
return _internal_getFutureCreatorAfterLeave(account: self.account, peerId: peerId)
}
public func toggleChatCustomRanks(peerId: PeerId, enabled: Bool) -> Signal<Void, NoError> {
return _internal_toggleChatCustomRanks(account: self.account, peerId: peerId, enabled: enabled)
}
public func updateChatRank(account: Account, peerId: PeerId, userId: PeerId, rank: String?) -> Signal<Never, UpdateChatRankError> {
return _internal_updateChatRank(account: account, peerId: peerId, userId: userId, rank: rank)
}
public func terminateSecretChat(peerId: PeerId, requestRemoteHistoryRemoval: Bool) -> Signal<Never, NoError> {
return self.account.postbox.transaction { transaction -> Void in

View file

@ -2,111 +2,7 @@ import Foundation
import TelegramCore
import TelegramPresentationData
import TelegramUIPreferences
public func stringForEntityFormattedDate(timestamp: Int32, format: MessageTextEntityType.DateTimeFormat, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> String {
switch format {
case .relative:
let currentTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
let value = currentTimestamp - timestamp
if value > 0 {
if value <= 1 * 60 * 60 {
return strings.FormattedDate_MinutesAgo(Int32(round(Float(value) / 60)))
} else if value <= 24 * 60 * 60 {
return strings.FormattedDate_HoursAgo(Int32(round(Float(value) / (60 * 60))))
} else {
return strings.FormattedDate_DaysAgo(Int32(round(Float(value) / (24 * 60 * 60))))
}
} else {
let value = abs(value)
if value <= 1 * 60 * 60 {
return strings.FormattedDate_InMinutes(Int32(round(Float(value) / 60)))
} else if value <= 24 * 60 * 60 {
return strings.FormattedDate_InHours(Int32(round(Float(value) / (60 * 60))))
} else {
return strings.FormattedDate_InDays(Int32(round(Float(value) / (24 * 60 * 60))))
}
}
case let .full(timeFormat, dateFormat):
var string = ""
if let dateFormat {
switch dateFormat {
case .short:
string += stringForMediumDate(timestamp: timestamp, strings: strings, dateTimeFormat: dateTimeFormat, withTime: false)
case .long:
string += stringForFullDate(timestamp: timestamp, strings: strings, dateTimeFormat: dateTimeFormat)
}
}
if let timeFormat {
let timeString: String
switch timeFormat {
case .short:
timeString = stringForMessageTimestamp(timestamp: timestamp, dateTimeFormat: dateTimeFormat)
case .long:
timeString = stringForMessageTimestamp(timestamp: timestamp, dateTimeFormat: dateTimeFormat, withSeconds: true)
}
if !string.isEmpty {
string = strings.Time_AtPreciseDate(string, timeString).string
} else {
string = timeString
}
}
return string
}
}
public func stringForShortTimestamp(hours: Int32, minutes: Int32, seconds: Int32? = nil, dateTimeFormat: PresentationDateTimeFormat, formatAsPlainText: Bool = false) -> String {
switch dateTimeFormat.timeFormat {
case .regular:
let hourString: String
if hours == 0 {
hourString = "12"
} else if hours > 12 {
hourString = "\(hours - 12)"
} else {
hourString = "\(hours)"
}
let periodString: String
if hours >= 12 {
periodString = "PM"
} else {
periodString = "AM"
}
let spaceCharacter: String
if formatAsPlainText {
spaceCharacter = " "
} else {
spaceCharacter = "\u{00a0}"
}
let minuteString = String(format: "%02d", arguments: [Int(minutes)])
if let seconds {
let secondString = String(format: "%02d", arguments: [Int(seconds)])
return "\(hourString):\(minuteString):\(secondString)\(spaceCharacter)\(periodString)"
} else {
return "\(hourString):\(minuteString)\(spaceCharacter)\(periodString)"
}
case .military:
if let seconds {
return String(format: "%02d:%02d:%02d", arguments: [Int(hours), Int(minutes), Int(seconds)])
} else {
return String(format: "%02d:%02d", arguments: [Int(hours), Int(minutes)])
}
}
}
public func stringForMessageTimestamp(timestamp: Int32, dateTimeFormat: PresentationDateTimeFormat, withSeconds: Bool = false, local: Bool = true) -> String {
var t = Int(timestamp)
var timeinfo = tm()
if local {
localtime_r(&t, &timeinfo)
} else {
gmtime_r(&t, &timeinfo)
}
return stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, seconds: withSeconds ? timeinfo.tm_sec : nil, dateTimeFormat: dateTimeFormat)
}
import TextFormat
public func getDateTimeComponents(timestamp: Int32) -> (day: Int32, month: Int32, year: Int32, hour: Int32, minutes: Int32) {
var t: time_t = Int(timestamp)

View file

@ -1,6 +1,7 @@
import Foundation
import TelegramCore
import TelegramPresentationData
import TextFormat
public func stringForTimestamp(day: Int32, month: Int32, year: Int32, dateTimeFormat: PresentationDateTimeFormat) -> String {
let separator = dateTimeFormat.dateSeparator

View file

@ -20,6 +20,7 @@ swift_library(
"//submodules/AccountContext",
"//submodules/AppBundle",
"//submodules/TelegramStringFormatting",
"//submodules/TextFormat",
"//submodules/LocalizedPeerData",
"//submodules/Components/ReactionButtonListComponent",
"//submodules/Components/ReactionImageComponent",

View file

@ -4,6 +4,7 @@ import TelegramCore
import TelegramPresentationData
import TelegramUIPreferences
import TelegramStringFormatting
import TextFormat
import LocalizedPeerData
import AccountContext

View file

@ -147,6 +147,8 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
private var textRevealLink: SharedDisplayLinkDriver.Link?
private var textRevealAnimationState: TextRevealAnimationState?
private var relativeDateTimer: (timer: SwiftSignalKit.Timer, period: Int32)?
override public var visibility: ListViewItemNodeVisibility {
didSet {
if oldValue != self.visibility {
@ -232,6 +234,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
self.linkPreviewOptionsDisposable?.dispose()
self.linkProgressDisposable?.dispose()
self.codeHighlightState?.disposable.dispose()
self.relativeDateTimer?.timer.invalidate()
}
override public func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
@ -484,6 +487,23 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
}
}
var formattedDateUpdatePeriod: Int32?
if let messageEntities {
for entity in messageEntities {
if case let .FormattedDate(format, timestamp) = entity.type, case .relative = format {
let currentTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
let value = abs(currentTimestamp - timestamp)
if value < 120 {
formattedDateUpdatePeriod = 1
} else if value <= 60 * 60 {
formattedDateUpdatePeriod = 60
} else {
formattedDateUpdatePeriod = 30 * 60
}
}
}
}
var entities: [MessageTextEntity]?
var updatedCachedChatMessageText: CachedChatMessageText?
if let cached = currentCachedChatMessageText, cached.matches(text: rawText, inputEntities: messageEntities) {
@ -616,7 +636,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
}
}
attributedText = stringWithAppliedEntities(rawText, entities: entities, baseColor: messageTheme.primaryTextColor, linkColor: messageTheme.linkTextColor, baseQuoteTintColor: mainColor, baseQuoteSecondaryTintColor: secondaryColor, baseQuoteTertiaryTintColor: tertiaryColor, codeBlockTitleColor: codeBlockTitleColor, codeBlockAccentColor: codeBlockAccentColor, codeBlockBackgroundColor: codeBlockBackgroundColor, baseFont: textFont, linkFont: textFont, boldFont: item.presentationData.messageBoldFont, italicFont: item.presentationData.messageItalicFont, boldItalicFont: item.presentationData.messageBoldItalicFont, fixedFont: item.presentationData.messageFixedFont, blockQuoteFont: item.presentationData.messageBlockQuoteFont, underlineLinks: underlineLinks, message: item.message, adjustQuoteFontSize: true, cachedMessageSyntaxHighlight: cachedMessageSyntaxHighlight)
attributedText = stringWithAppliedEntities(rawText, entities: entities, strings: item.presentationData.strings, dateTimeFormat: item.presentationData.dateTimeFormat, baseColor: messageTheme.primaryTextColor, linkColor: messageTheme.linkTextColor, baseQuoteTintColor: mainColor, baseQuoteSecondaryTintColor: secondaryColor, baseQuoteTertiaryTintColor: tertiaryColor, codeBlockTitleColor: codeBlockTitleColor, codeBlockAccentColor: codeBlockAccentColor, codeBlockBackgroundColor: codeBlockBackgroundColor, baseFont: textFont, linkFont: textFont, boldFont: item.presentationData.messageBoldFont, italicFont: item.presentationData.messageItalicFont, boldItalicFont: item.presentationData.messageBoldItalicFont, fixedFont: item.presentationData.messageFixedFont, blockQuoteFont: item.presentationData.messageBlockQuoteFont, underlineLinks: underlineLinks, message: item.message, adjustQuoteFontSize: true, cachedMessageSyntaxHighlight: cachedMessageSyntaxHighlight)
} else if !rawText.isEmpty {
attributedText = NSAttributedString(string: rawText, font: textFont, textColor: messageTheme.primaryTextColor)
} else {
@ -807,6 +827,20 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
animation.animator.updateFrame(layer: strongSelf.containerNode.layer, frame: CGRect(origin: CGPoint(), size: boundingSize), completion: nil)
if let formattedDateUpdatePeriod {
if strongSelf.relativeDateTimer?.period != formattedDateUpdatePeriod {
strongSelf.relativeDateTimer?.timer.invalidate()
strongSelf.relativeDateTimer = nil
}
strongSelf.relativeDateTimer = (SwiftSignalKit.Timer(timeout: Double(formattedDateUpdatePeriod), repeat: true, completion: { [weak self] in
self?.requestFullUpdate?()
}, queue: Queue.mainQueue()), formattedDateUpdatePeriod)
strongSelf.relativeDateTimer?.timer.start()
} else if let (timer, _) = strongSelf.relativeDateTimer {
strongSelf.relativeDateTimer = nil
timer.invalidate()
}
if strongSelf.isSummaryApplied != isSummaryApplied {
strongSelf.isSummaryApplied = isSummaryApplied
itemApply?.setInvertOffsetDirection()

View file

@ -18,6 +18,7 @@ swift_library(
"//submodules/AccountContext",
"//submodules/TelegramPresentationData",
"//submodules/TelegramStringFormatting",
"//submodules/TextFormat",
"//submodules/SolidRoundedButtonNode",
"//submodules/PresentationDataUtils",
"//submodules/UIKitRuntimeUtils",

View file

@ -6,6 +6,7 @@ import Postbox
import TelegramCore
import TelegramPresentationData
import TelegramStringFormatting
import TextFormat
import AccountContext
import SolidRoundedButtonNode
import PresentationDataUtils

View file

@ -7,6 +7,7 @@ import TelegramCore
import ViewControllerComponent
import TelegramPresentationData
import TelegramStringFormatting
import TextFormat
import AccountContext
import SheetComponent
import ButtonComponent

View file

@ -69,6 +69,7 @@ private final class CraftGiftPageContent: Component {
let starsTopUpOptionsPromise: Promise<[StarsTopUpOption]?>
let selectGift: (Int32, GiftItem) -> Void
let removeGift: (Int32) -> Void
let craftAnotherGift: () -> Void
let dismiss: () -> Void
init(
@ -86,6 +87,7 @@ private final class CraftGiftPageContent: Component {
starsTopUpOptionsPromise: Promise<[StarsTopUpOption]?>,
selectGift: @escaping (Int32, GiftItem) -> Void,
removeGift: @escaping (Int32) -> Void,
craftAnotherGift: @escaping () -> Void,
dismiss: @escaping () -> Void
) {
self.context = context
@ -102,6 +104,7 @@ private final class CraftGiftPageContent: Component {
self.starsTopUpOptionsPromise = starsTopUpOptionsPromise
self.selectGift = selectGift
self.removeGift = removeGift
self.craftAnotherGift = craftAnotherGift
self.dismiss = dismiss
}
@ -1203,7 +1206,14 @@ private final class CraftGiftPageContent: Component {
}
if let _ = view {
if case let .gift(gift) = component.result {
let giftController = GiftViewScreen(context: component.context, subject: .profileGift(component.context.account.peerId, gift))
//TODO:localize
let giftController = GiftViewScreen(
context: component.context,
subject: .profileGift(component.context.account.peerId, gift),
customAction: .init(title: environment.strings.Gift_Craft_CraftingFailed_CraftAnotherGift, action: {
component.craftAnotherGift()
})
)
if let navigationController = controller.navigationController {
navigationController.pushViewController(giftController, animated: true)
@ -1548,6 +1558,36 @@ private final class SheetContainerComponent: CombinedComponent {
}
}
let navigationController = environment.controller()?.navigationController as? NavigationController
let profileGiftsContext = (environment.controller() as? GiftCraftScreen)?.profileGiftsContext
let resaleContext = state.resaleContext
let starsTopUpOptionsPromise = state.starsTopUpOptionsPromise
let craftAnotherGift = { [weak navigationController] in
guard let navigationController else {
return
}
if let genericGift = externalState.starGiftsMap[component.gift.giftId] {
HapticFeedback().impact(.light)
let selectController = SelectCraftGiftScreen(
context: component.context,
craftContext: component.craftContext,
resaleContext: resaleContext,
gift: component.gift,
genericGift: genericGift,
selectedGiftIds: Set(),
starsTopUpOptions: starsTopUpOptionsPromise.get(),
selectGift: { [weak navigationController] item in
if let navigationController{
let craftController = GiftCraftScreen(context: component.context, gift: item.gift, profileGiftsContext: profileGiftsContext)
navigationController.pushViewController(craftController)
}
}
)
navigationController.pushViewController(selectController)
}
}
let theme = environment.theme
var colors: (UIColor, UIColor, UIColor, UIColor, UIColor) = (
@ -1720,6 +1760,7 @@ private final class SheetContainerComponent: CombinedComponent {
state.selectedGiftIds[index] = nil
state.updated(transition: .spring(duration: 0.4))
},
craftAnotherGift: craftAnotherGift,
dismiss: {
dismiss(true)
}
@ -1791,26 +1832,8 @@ private final class SheetContainerComponent: CombinedComponent {
if state.displayInfo {
state.displayInfo = false
state.updated(transition: .spring(duration: 0.3))
} else if state.displayFailure, let genericGift = externalState.starGiftsMap[component.gift.giftId] {
HapticFeedback().impact(.light)
let selectController = SelectCraftGiftScreen(
context: component.context,
craftContext: component.craftContext,
resaleContext: state.resaleContext,
gift: component.gift,
genericGift: genericGift,
selectedGiftIds: Set(),
starsTopUpOptions: state.starsTopUpOptionsPromise.get(),
selectGift: { item in
if let controller = controller() as? GiftCraftScreen, let navigationController = controller.navigationController as? NavigationController {
let craftController = GiftCraftScreen(context: component.context, gift: item.gift, profileGiftsContext: controller.profileGiftsContext)
controller.dismissAnimated()
navigationController.pushViewController(craftController)
}
}
)
environment.controller()?.push(selectController)
} else if state.displayFailure {
craftAnotherGift()
} else {
HapticFeedback().impact(.medium)

View file

@ -153,6 +153,8 @@ final class SelectGiftPageContent: Component {
}
transition.setFrame(view: self.loadingView, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight - 170.0), size: loadingSize))
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
var itemFrame = CGRect(origin: CGPoint(x: itemSideInset, y: contentHeight), size: itemSize)
var itemsHeight: CGFloat = 0.0
var validIds: [AnyHashable] = []
@ -245,6 +247,12 @@ final class SelectGiftPageContent: Component {
}
}
itemTransition.setFrame(view: itemView, frame: itemFrame)
var canCraft = true
if let profileGift = self.giftMap[gift.gift.id], let canCraftDate = profileGift.canCraftAt, currentTime < canCraftDate {
canCraft = false
}
transition.setAlpha(view: itemView, alpha: canCraft ? 1.0 : 0.5)
}
}
@ -414,6 +422,7 @@ final class SelectGiftPageContent: Component {
contentHeight += 32.0
contentHeight = self.updateScrolling(interactive: false, transition: transition)
let originalContentHeight = contentHeight
let resaleCount = component.genericGift.availability?.resale ?? 0
let saleTitle = environment.strings.Gift_Craft_Select_SaleGiftsCount(Int32(clamping: resaleCount)).uppercased()
@ -483,7 +492,11 @@ final class SelectGiftPageContent: Component {
}
transition.setFrame(view: storeGiftsView, frame: storeGiftsFrame)
storeGiftsView.updateScrolling(bounds: CGRect(origin: .zero, size: availableSize), transition: .immediate)
var effectiveBounds = CGRect(origin: .zero, size: CGSize(width: availableSize.width, height: 1000.0))
if let bounds = self.currentBounds {
effectiveBounds = bounds.offsetBy(dx: 0.0, dy: -originalContentHeight)
}
storeGiftsView.updateScrolling(bounds: effectiveBounds, transition: .immediate)
}
contentHeight += storeGiftsSize.height
contentHeight += 90.0

View file

@ -183,7 +183,7 @@ public final class GiftStoreContentComponent: Component {
if let initialCount = self.initialCount, initialCount < minimumCountToDisplayFilters {
topInset = component.navigationHeight
}
let visibleBounds = bounds.insetBy(dx: 0.0, dy: -10.0)
if let starGifts = self.effectiveGifts {
let sideInset: CGFloat = 16.0 + component.safeInsets.left
@ -1269,8 +1269,10 @@ final class GiftStoreScreenComponent: Component {
guard let self, let component = self.component, let environment = self.environment else {
return
}
let controller = component.context.sharedContext.makeStarsTransactionsScreen(context: component.context, starsContext: starsContext)
environment.controller()?.push(controller)
Queue.mainQueue().after(0.3) {
let controller = component.context.sharedContext.makeStarsTransactionsScreen(context: component.context, starsContext: starsContext)
environment.controller()?.push(controller)
}
}
)))
@ -1283,8 +1285,10 @@ final class GiftStoreScreenComponent: Component {
guard let self, let component = self.component, let environment = self.environment else {
return
}
let controller = component.context.sharedContext.makeStarsTransactionsScreen(context: component.context, starsContext: tonContext)
environment.controller()?.push(controller)
Queue.mainQueue().after(0.3) {
let controller = component.context.sharedContext.makeStarsTransactionsScreen(context: component.context, starsContext: tonContext)
environment.controller()?.push(controller)
}
}
)))

View file

@ -4677,7 +4677,26 @@ private final class GiftViewSheetContent: CombinedComponent {
)
let buttonChild: _UpdatedChildComponent
if state.canSkip {
if let controller = controller() as? GiftViewScreen, let customAction = controller.customAction {
buttonChild = button.update(
component: ButtonComponent(
background: buttonBackground,
content: AnyComponentWithIdentity(
id: AnyHashable("custom"),
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: customAction.title, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center))))
),
isEnabled: true,
displaysProgress: state.inProgress,
action: { [weak state] in
if let state {
customAction.action()
state.dismiss(animated: true)
}
}),
availableSize: buttonSize,
transition: context.transition
)
} else if state.canSkip {
buttonChild = button.update(
component: ButtonComponent(
background: buttonBackground,
@ -5630,6 +5649,16 @@ public class GiftViewScreen: ViewControllerComponentContainer {
}
}
public struct CustomAction {
public let title: String
public let action: () -> Void
public init(title: String, action: @escaping () -> Void) {
self.title = title
self.action = action
}
}
private let context: AccountContext
private let subject: GiftViewScreen.Subject
@ -5671,6 +5700,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
fileprivate let togglePinnedToTop: ((StarGiftReference, Bool) -> Bool)?
fileprivate let shareStory: ((StarGift.UniqueGift) -> Void)?
fileprivate let openChatTheme: (() -> Void)?
fileprivate let customAction: CustomAction?
public var disposed: () -> Void = {}
@ -5690,7 +5720,8 @@ public class GiftViewScreen: ViewControllerComponentContainer {
updateResellStars: ((StarGiftReference, CurrencyAmount?) -> Signal<Never, UpdateStarGiftPriceError>)? = nil,
togglePinnedToTop: ((StarGiftReference, Bool) -> Bool)? = nil,
shareStory: ((StarGift.UniqueGift) -> Void)? = nil,
openChatTheme: (() -> Void)? = nil
openChatTheme: (() -> Void)? = nil,
customAction: CustomAction? = nil
) {
self.context = context
self.subject = subject
@ -5706,6 +5737,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
self.togglePinnedToTop = togglePinnedToTop
self.shareStory = shareStory
self.openChatTheme = openChatTheme
self.customAction = customAction
if case let .unique(gift) = subject.arguments?.gift, gift.resellForTonOnly {
self.balanceCurrency = .ton

View file

@ -2289,7 +2289,7 @@ func availableActionsForMemberOfPeer(accountPeerId: PeerId, peer: Peer?, member:
result.insert(.promote)
case .admin:
switch member {
case let .legacyGroupMember(_, _, invitedBy, _, _):
case let .legacyGroupMember(_, _, invitedBy, _, _, _):
result.insert(.restrict)
if invitedBy == accountPeerId {
result.insert(.promote)
@ -2301,7 +2301,7 @@ func availableActionsForMemberOfPeer(accountPeerId: PeerId, peer: Peer?, member:
}
case .member:
switch member {
case let .legacyGroupMember(_, _, invitedBy, _, _):
case let .legacyGroupMember(_, _, invitedBy, _, _, _):
if invitedBy == accountPeerId {
result.insert(.restrict)
}

View file

@ -13,14 +13,14 @@ enum PeerInfoMemberRole {
enum PeerInfoMember: Equatable {
case channelMember(participant: RenderedChannelParticipant, storyStats: PeerStoryStats?)
case legacyGroupMember(peer: RenderedPeer, role: PeerInfoMemberRole, invitedBy: PeerId?, presence: TelegramUserPresence?, storyStats: PeerStoryStats?)
case legacyGroupMember(peer: RenderedPeer, role: PeerInfoMemberRole, invitedBy: PeerId?, presence: TelegramUserPresence?, storyStats: PeerStoryStats?, rank: String?)
case account(peer: RenderedPeer)
var id: PeerId {
switch self {
case let .channelMember(participant, _):
return participant.peer.id
case let .legacyGroupMember(peer, _, _, _, _):
case let .legacyGroupMember(peer, _, _, _, _, _):
return peer.peerId
case let .account(peer):
return peer.peerId
@ -31,7 +31,7 @@ enum PeerInfoMember: Equatable {
switch self {
case let .channelMember(participant, _):
return participant.peer
case let .legacyGroupMember(peer, _, _, _, _):
case let .legacyGroupMember(peer, _, _, _, _, _):
return peer.peers[peer.peerId]!
case let .account(peer):
return peer.peers[peer.peerId]!
@ -42,7 +42,7 @@ enum PeerInfoMember: Equatable {
switch self {
case let .channelMember(participant, _):
return participant.presences[participant.peer.id] as? TelegramUserPresence
case let .legacyGroupMember(_, _, _, presence, _):
case let .legacyGroupMember(_, _, _, presence, _, _):
return presence
case .account:
return nil
@ -62,7 +62,7 @@ enum PeerInfoMember: Equatable {
return .member
}
}
case let .legacyGroupMember(_, role, _, _, _):
case let .legacyGroupMember(_, role, _, _, _, _):
return role
case .account:
return .member
@ -78,8 +78,8 @@ enum PeerInfoMember: Equatable {
case let .member(_, _, _, _, rank, _):
return rank
}
case .legacyGroupMember:
return nil
case let .legacyGroupMember(_, _, _, _, _, rank):
return rank
case .account:
return nil
}
@ -89,7 +89,7 @@ enum PeerInfoMember: Equatable {
switch self {
case let .channelMember(_, value):
return value
case let .legacyGroupMember(_, _, _, _, value):
case let .legacyGroupMember(_, _, _, _, value, _):
return value
case .account:
return nil
@ -232,18 +232,22 @@ private final class PeerInfoMembersContextImpl {
if let peer = view.peers[participant.peerId] {
let role: PeerInfoMemberRole
let invitedBy: PeerId?
let rank: String?
switch participant {
case .creator:
case let .creator(_, rankValue):
role = .creator
invitedBy = nil
case let .admin(_, invitedByValue, _):
rank = rankValue
case let .admin(_, invitedByValue, _, rankValue):
role = .admin
invitedBy = invitedByValue
case let .member(_, invitedByValue, _):
rank = rankValue
case let .member(_, invitedByValue, _, rankValue):
role = .member
invitedBy = invitedByValue
rank = rankValue
}
unsortedMembers.append(.legacyGroupMember(peer: RenderedPeer(peer: peer), role: role, invitedBy: invitedBy, presence: view.peerPresences[participant.peerId] as? TelegramUserPresence, storyStats: view.memberStoryStats[participant.peerId]))
unsortedMembers.append(.legacyGroupMember(peer: RenderedPeer(peer: peer), role: role, invitedBy: invitedBy, presence: view.peerPresences[participant.peerId] as? TelegramUserPresence, storyStats: view.memberStoryStats[participant.peerId], rank: rank))
}
}

View file

@ -123,7 +123,7 @@ extension PeerInfoScreenNode {
strongSelf.enqueueMediaMessageDisposable.set((legacyAssetPickerEnqueueMessages(context: strongSelf.context, account: strongSelf.context.account, signals: signals!)
|> deliverOnMainQueue).startStrict(next: { [weak self] messages in
if let strongSelf = self {
let _ = enqueueMessages(account: strongSelf.context.account, peerId: strongSelf.peerId, messages: messages.map { $0.message }).startStandalone()
let _ = enqueueMessages(account: strongSelf.context.account, peerId: strongSelf.peerId, messages: messages.map { $0.message.withUpdatedReplyToMessageId(.init(messageId: message.id, quote: nil, todoItemId: nil)) }).startStandalone()
}
}))
}

View file

@ -508,12 +508,8 @@ final class GiftsListView: UIView {
ribbonColor = .green
ribbonOutline = params.presentationData.theme.list.blocksBackgroundColor
} else {
if product.pinnedToTop || self.canSelect || self.isCollection {
ribbonFont = .monospaced
ribbonText = "#\(gift.number)"
} else {
ribbonText = params.presentationData.strings.PeerInfo_Gifts_OneOf(compactNumericCountString(Int(gift.availability.issued), decimalSeparator: params.presentationData.dateTimeFormat.decimalSeparator)).string
}
ribbonFont = .monospaced
ribbonText = "#\(gift.number)"
for attribute in gift.attributes {
if case let .backdrop(_, _, innerColor, outerColor, _, _, _) = attribute {
ribbonColor = .custom(outerColor, innerColor)

View file

@ -27,6 +27,7 @@ import ListItemSliderSelectorComponent
import DateSelectionUI
import PlainButtonComponent
import TelegramStringFormatting
import TextFormat
import TimeSelectionActionSheet
private let checkIcon: UIImage = {

View file

@ -33,6 +33,7 @@ swift_library(
"//submodules/LocationUI",
"//submodules/AppBundle",
"//submodules/TelegramStringFormatting",
"//submodules/TextFormat",
"//submodules/UIKitRuntimeUtils",
"//submodules/TelegramUI/Components/Settings/TimezoneSelectionScreen",
"//submodules/TelegramUI/Components/TimeSelectionActionSheet",

View file

@ -20,6 +20,7 @@ import LottieComponent
import Markdown
import LocationUI
import TelegramStringFormatting
import TextFormat
import PlainButtonComponent
import TimeSelectionActionSheet

View file

@ -21,6 +21,7 @@ import Markdown
import LocationUI
import TelegramStringFormatting
import TimezoneSelectionScreen
import TextFormat
private func wrappedMinuteRange(range: Range<Int>, dayIndexOffset: Int = 0) -> IndexSet {
let mappedRange = (range.lowerBound + dayIndexOffset * 24 * 60) ..< (range.upperBound + dayIndexOffset * 24 * 60)

View file

@ -13,6 +13,7 @@ import ChatMessageItemCommon
import ChatControllerInteraction
import EventKit
import EventKitUI
import ChatScheduleTimeController
extension ChatControllerImpl: EKEventEditViewDelegate {
func openDateContextMenu(date: Int32, params: ChatControllerInteraction.LongTapParams) -> Void {
@ -55,7 +56,7 @@ extension ChatControllerImpl: EKEventEditViewDelegate {
UIPasteboard.general.string = "\(date)"
self.present(UndoOverlayController(presentationData: self.presentationData, content: .copy(text: presentationData.strings.Conversation_CardNumberCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
self.present(UndoOverlayController(presentationData: self.presentationData, content: .copy(text: "Date copied to clipboard."), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
}))
)
items.append(
@ -81,6 +82,37 @@ extension ChatControllerImpl: EKEventEditViewDelegate {
}
}))
)
items.append(
.action(ContextMenuActionItem(text: "Set a Reminder", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Unmute"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
f(.default)
guard let self else {
return
}
let controller = ChatScheduleTimeScreen(
context: self.context,
mode: .reminders,
currentTime: date,
currentRepeatPeriod: nil,
minimalTime: nil,
isDark: false,
completion: { [weak self] result in
guard let self else {
return
}
let attributes: [MessageAttribute] = [
OutgoingScheduleInfoMessageAttribute(scheduleTime: result.time, repeatPeriod: result.repeatPeriod)
]
let forwardMessage: EnqueueMessage = .forward(source: message.id, threadId: nil, grouping: .auto, attributes: attributes, correlationId: nil)
let _ = forwardMessage
let _ = enqueueMessages(account: self.context.account, peerId: self.context.account.peerId, messages: [forwardMessage]).start()
self.present(UndoOverlayController(presentationData: self.presentationData, content: .forward(savedMessages: true, text: "You have set a reminder in [Saved Messages]()."), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
}
)
self.push(controller)
}))
)
self.canReadHistory.set(false)

View file

@ -91,11 +91,17 @@ extension ChatControllerImpl {
if self.presentationInterfaceState.copyProtectionEnabled && !isAction && !isAd {
if case .scheduledMessages = self.subject {
} else {
var isChannel = false
if let channel = self.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, case .broadcast = channel.info {
isChannel = true
if let peer = self.presentationInterfaceState.renderedPeer?.peer {
if peer is TelegramUser {
} else {
var isChannel = false
if let channel = self.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, case .broadcast = channel.info {
isChannel = true
}
tip = .messageCopyProtection(isChannel: isChannel)
}
}
tip = .messageCopyProtection(isChannel: isChannel)
}
} else {
let numberOfComponents = message.text.components(separatedBy: CharacterSet.whitespacesAndNewlines).count

View file

@ -1587,7 +1587,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if isCaptionAbove {
parameters = ChatSendMessageActionSheetController.SendParameters(effect: nil, textIsAboveMedia: true)
}
self.enqueueMediaMessages(signals: signals, silentPosting: false, parameters: parameters)
self.enqueueMediaMessages(signals: signals, silentPosting: false, replyToSubject: .init(messageId: message.id, quote: nil, todoItemId: nil), parameters: parameters)
}
}, present: { [weak self] c, a in
self?.present(c, in: .window(.root), with: a)
@ -8353,17 +8353,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
}
func enqueueMediaMessages(fromGallery: Bool = false, signals: [Any]?, silentPosting: Bool, scheduleTime: Int32? = nil, parameters: ChatSendMessageActionSheetController.SendParameters? = nil, getAnimatedTransitionSource: ((String) -> UIView?)? = nil, completion: @escaping () -> Void = {}) {
func enqueueMediaMessages(fromGallery: Bool = false, signals: [Any]?, silentPosting: Bool, scheduleTime: Int32? = nil, replyToSubject: ChatInterfaceState.ReplyMessageSubject? = nil, parameters: ChatSendMessageActionSheetController.SendParameters? = nil, getAnimatedTransitionSource: ((String) -> UIView?)? = nil, completion: @escaping () -> Void = {}) {
if let _ = self.presentationInterfaceState.sendPaidMessageStars {
self.presentPaidMessageAlertIfNeeded(count: Int32(signals?.count ?? 1), forceDark: fromGallery, completion: { [weak self] postpone in
self?.commitEnqueueMediaMessages(signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime, postpone: postpone, parameters: parameters, getAnimatedTransitionSource: getAnimatedTransitionSource, completion: completion)
})
} else {
self.commitEnqueueMediaMessages(signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime, parameters: parameters, getAnimatedTransitionSource: getAnimatedTransitionSource, completion: completion)
self.commitEnqueueMediaMessages(signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime, replyToSubject: replyToSubject, parameters: parameters, getAnimatedTransitionSource: getAnimatedTransitionSource, completion: completion)
}
}
private func commitEnqueueMediaMessages(signals: [Any]?, silentPosting: Bool, scheduleTime: Int32? = nil, postpone: Bool = false, parameters: ChatSendMessageActionSheetController.SendParameters? = nil, getAnimatedTransitionSource: ((String) -> UIView?)? = nil, completion: @escaping () -> Void = {}) {
private func commitEnqueueMediaMessages(signals: [Any]?, silentPosting: Bool, scheduleTime: Int32? = nil, postpone: Bool = false, replyToSubject: ChatInterfaceState.ReplyMessageSubject? = nil, parameters: ChatSendMessageActionSheetController.SendParameters? = nil, getAnimatedTransitionSource: ((String) -> UIView?)? = nil, completion: @escaping () -> Void = {}) {
self.enqueueMediaMessageDisposable.set((legacyAssetPickerEnqueueMessages(context: self.context, account: self.context.account, signals: signals!)
|> deliverOnMainQueue).startStrict(next: { [weak self] items in
guard let strongSelf = self else {
@ -8503,7 +8503,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
let messages = strongSelf.transformEnqueueMessages(mappedMessages, silentPosting: silentPosting, scheduleTime: scheduleTime, postpone: postpone)
let replyMessageSubject = strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject
let replyMessageSubject = replyToSubject ?? strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()

View file

@ -893,7 +893,11 @@ extension ChatControllerImpl {
peerVerification = cachedChannelData.verification
}
}
copyProtectionEnabled = peer.isCopyProtectionEnabled
if let cachedUserData = peerView.cachedData as? CachedUserData {
copyProtectionEnabled = cachedUserData.flags.contains(.copyProtectionEnabled)
} else {
copyProtectionEnabled = peer.isCopyProtectionEnabled
}
if let cachedGroupData = peerView.cachedData as? CachedGroupData {
if !cachedGroupData.botInfos.isEmpty {
hasBots = true

View file

@ -0,0 +1,177 @@
import Foundation
import TelegramCore
import TelegramPresentationData
import TelegramUIPreferences
public func stringForEntityFormattedDate(timestamp: Int32, format: MessageTextEntityType.DateTimeFormat, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> String {
switch format {
case .relative:
let currentTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
let value = currentTimestamp - timestamp
if value > 0 {
if value < 60 {
return strings.FormattedDate_SecondsAgo(value)
} else if value <= 1 * 60 * 60 {
return strings.FormattedDate_MinutesAgo(Int32(round(Float(value) / 60)))
} else if value <= 24 * 60 * 60 {
return strings.FormattedDate_HoursAgo(Int32(round(Float(value) / (60 * 60))))
} else {
return strings.FormattedDate_DaysAgo(Int32(round(Float(value) / (24 * 60 * 60))))
}
} else {
let value = abs(value)
if value < 60 {
return strings.FormattedDate_InSeconds(value)
} else if value <= 1 * 60 * 60 {
return strings.FormattedDate_InMinutes(Int32(round(Float(value) / 60)))
} else if value <= 24 * 60 * 60 {
return strings.FormattedDate_InHours(Int32(round(Float(value) / (60 * 60))))
} else {
return strings.FormattedDate_InDays(Int32(round(Float(value) / (24 * 60 * 60))))
}
}
case let .full(timeFormat, dateFormat):
var string = ""
if let dateFormat {
switch dateFormat {
case .short:
string += stringForShortDate(timestamp: timestamp, strings: strings, dateTimeFormat: dateTimeFormat)
case .long:
string += stringForFullDate(timestamp: timestamp, strings: strings, dateTimeFormat: dateTimeFormat)
}
}
if let timeFormat {
let timeString: String
switch timeFormat {
case .short:
timeString = stringForMessageTimestamp(timestamp: timestamp, dateTimeFormat: dateTimeFormat)
case .long:
timeString = stringForMessageTimestamp(timestamp: timestamp, dateTimeFormat: dateTimeFormat, withSeconds: true)
}
if !string.isEmpty {
string = strings.Time_AtPreciseDate(string, timeString).string
} else {
string = timeString
}
}
return string
}
}
public func stringForShortTimestamp(hours: Int32, minutes: Int32, seconds: Int32? = nil, dateTimeFormat: PresentationDateTimeFormat, formatAsPlainText: Bool = false) -> String {
switch dateTimeFormat.timeFormat {
case .regular:
let hourString: String
if hours == 0 {
hourString = "12"
} else if hours > 12 {
hourString = "\(hours - 12)"
} else {
hourString = "\(hours)"
}
let periodString: String
if hours >= 12 {
periodString = "PM"
} else {
periodString = "AM"
}
let spaceCharacter: String
if formatAsPlainText {
spaceCharacter = " "
} else {
spaceCharacter = "\u{00a0}"
}
let minuteString = String(format: "%02d", arguments: [Int(minutes)])
if let seconds {
let secondString = String(format: "%02d", arguments: [Int(seconds)])
return "\(hourString):\(minuteString):\(secondString)\(spaceCharacter)\(periodString)"
} else {
return "\(hourString):\(minuteString)\(spaceCharacter)\(periodString)"
}
case .military:
if let seconds {
return String(format: "%02d:%02d:%02d", arguments: [Int(hours), Int(minutes), Int(seconds)])
} else {
return String(format: "%02d:%02d", arguments: [Int(hours), Int(minutes)])
}
}
}
public func stringForMessageTimestamp(timestamp: Int32, dateTimeFormat: PresentationDateTimeFormat, withSeconds: Bool = false, local: Bool = true) -> String {
var t = Int(timestamp)
var timeinfo = tm()
if local {
localtime_r(&t, &timeinfo)
} else {
gmtime_r(&t, &timeinfo)
}
return stringForShortTimestamp(hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, seconds: withSeconds ? timeinfo.tm_sec : nil, dateTimeFormat: dateTimeFormat)
}
private func stringForShortDate(timestamp: Int32, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, withTime: Bool = true) -> String {
var t: time_t = Int(timestamp)
var timeinfo = tm()
localtime_r(&t, &timeinfo);
let day = timeinfo.tm_mday
let month = timeinfo.tm_mon + 1
let year = timeinfo.tm_year
let dateString: String
let separator = dateTimeFormat.dateSeparator
let suffix = dateTimeFormat.dateSuffix
let displayYear = dateTimeFormat.requiresFullYear ? year - 100 + 2000 : year - 100
switch dateTimeFormat.dateFormat {
case .monthFirst:
dateString = String(format: "%02d%@%02d%@%02d%@", month, separator, day, separator, displayYear, suffix)
case .dayFirst:
dateString = String(format: "%02d%@%02d%@%02d%@", day, separator, month, separator, displayYear, suffix)
}
return dateString
}
private func stringForFullDate(timestamp: Int32, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> String {
var t: time_t = Int(timestamp)
var timeinfo = tm()
localtime_r(&t, &timeinfo);
let dayString = "\(timeinfo.tm_mday)"
let yearString = "\(2000 + timeinfo.tm_year - 100)"
let monthFormat: (String, String) -> PresentationStrings.FormattedString
switch timeinfo.tm_mon + 1 {
case 1:
monthFormat = strings.FormattedDate_LongDate_m1
case 2:
monthFormat = strings.FormattedDate_LongDate_m2
case 3:
monthFormat = strings.FormattedDate_LongDate_m3
case 4:
monthFormat = strings.FormattedDate_LongDate_m4
case 5:
monthFormat = strings.FormattedDate_LongDate_m5
case 6:
monthFormat = strings.FormattedDate_LongDate_m6
case 7:
monthFormat = strings.FormattedDate_LongDate_m7
case 8:
monthFormat = strings.FormattedDate_LongDate_m8
case 9:
monthFormat = strings.FormattedDate_LongDate_m9
case 10:
monthFormat = strings.FormattedDate_LongDate_m10
case 11:
monthFormat = strings.FormattedDate_LongDate_m11
case 12:
monthFormat = strings.FormattedDate_LongDate_m12
default:
return ""
}
return monthFormat(dayString, yearString).string
}

View file

@ -299,7 +299,30 @@ public func generateTextEntities(_ text: String, enabledTypes: EnabledEntityType
type = .Url
} else if result.resultType == NSTextCheckingResult.CheckingType.date, let date = result.date?.timeIntervalSince1970 {
type = .FormattedDate(format: .relative, date: Int32(date))
#if DEBUG
var format: MessageTextEntityType.DateTimeFormat?
if text.contains("[rel]") {
format = .relative
}
var timeFormat: MessageTextEntityType.DateTimeFormat.TimeFormat?
if text.contains("[st]") {
timeFormat = .short
} else if text.contains("[lt]") {
timeFormat = .long
}
var dateFormat: MessageTextEntityType.DateTimeFormat.DateFormat?
if text.contains("[sd]") {
dateFormat = .short
} else if text.contains("[ld]") {
dateFormat = .long
}
if timeFormat != nil || dateFormat != nil {
format = .full(timeFormat: timeFormat, dateFormat: dateFormat)
}
type = .FormattedDate(format: format, date: Int32(date))
#else
type = .FormattedDate(format: nil, date: Int32(date))
#endif
} else {
type = .PhoneNumber
}

View file

@ -5,6 +5,7 @@ import TelegramCore
import Display
import libprisma
import SwiftSignalKit
import TelegramPresentationData
public func chatInputStateStringWithAppliedEntities(_ text: String, entities: [MessageTextEntity]) -> NSAttributedString {
var nsString: NSString?
@ -80,7 +81,7 @@ public func chatInputStateStringWithAppliedEntities(_ text: String, entities: [M
private let syntaxHighlighter = Syntaxer()
public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEntity], baseColor: UIColor, linkColor: UIColor, baseQuoteTintColor: UIColor? = nil, baseQuoteSecondaryTintColor: UIColor? = nil, baseQuoteTertiaryTintColor: UIColor? = nil, codeBlockTitleColor: UIColor? = nil, codeBlockAccentColor: UIColor? = nil, codeBlockBackgroundColor: UIColor? = nil, baseFont: UIFont, linkFont: UIFont, boldFont: UIFont, italicFont: UIFont, boldItalicFont: UIFont, fixedFont: UIFont, blockQuoteFont: UIFont, underlineLinks: Bool = true, external: Bool = false, message: Message?, entityFiles: [MediaId: TelegramMediaFile] = [:], adjustQuoteFontSize: Bool = false, cachedMessageSyntaxHighlight: CachedMessageSyntaxHighlight? = nil, paragraphAlignment: NSTextAlignment? = nil) -> NSAttributedString {
public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEntity], strings: PresentationStrings? = nil, dateTimeFormat: PresentationDateTimeFormat? = nil, baseColor: UIColor, linkColor: UIColor, baseQuoteTintColor: UIColor? = nil, baseQuoteSecondaryTintColor: UIColor? = nil, baseQuoteTertiaryTintColor: UIColor? = nil, codeBlockTitleColor: UIColor? = nil, codeBlockAccentColor: UIColor? = nil, codeBlockBackgroundColor: UIColor? = nil, baseFont: UIFont, linkFont: UIFont, boldFont: UIFont, italicFont: UIFont, boldItalicFont: UIFont, fixedFont: UIFont, blockQuoteFont: UIFont, underlineLinks: Bool = true, external: Bool = false, message: Message?, entityFiles: [MediaId: TelegramMediaFile] = [:], adjustQuoteFontSize: Bool = false, cachedMessageSyntaxHighlight: CachedMessageSyntaxHighlight? = nil, paragraphAlignment: NSTextAlignment? = nil) -> NSAttributedString {
let baseQuoteTintColor = baseQuoteTintColor ?? baseColor
var nsString: NSString?
@ -94,7 +95,7 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti
var adjustedRanges: [NSRange?] = []
adjustedRanges.reserveCapacity(entities.count)
let rangeDelta = 0
var rangeDelta = 0
for entity in entities {
let originalRange = NSRange(location: entity.range.lowerBound, length: entity.range.upperBound - entity.range.lowerBound)
var range = NSRange(location: originalRange.location + rangeDelta, length: originalRange.length)
@ -106,23 +107,22 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti
range.length = stringLength - range.location
}
// switch entity.type {
// case let .FormattedDate(format, date):
// let replacement = stringForEntityFormattedDate()
// switch format {
// case .relative:
// replacement = relative
// case let .full(timeFormat, dateFormat):
// }
//
// let replacementString = NSAttributedString(string: replacement, attributes: baseAttributes)
// string.replaceCharacters(in: range, with: replacementString)
// let newRange = NSRange(location: range.location, length: (replacement as NSString).length)
// adjustedRanges.append(newRange)
// rangeDelta += newRange.length - range.length
// default:
switch entity.type {
case let .FormattedDate(format, date):
if let format, let strings, let dateTimeFormat {
let replacement = stringForEntityFormattedDate(timestamp: date, format: format, strings: strings, dateTimeFormat: dateTimeFormat)
let replacementString = NSAttributedString(string: replacement, attributes: baseAttributes)
string.replaceCharacters(in: range, with: replacementString)
let newRange = NSRange(location: range.location, length: (replacement as NSString).length)
adjustedRanges.append(newRange)
rangeDelta += newRange.length - range.length
} else {
adjustedRanges.append(range)
}
default:
adjustedRanges.append(range)
// }
}
}
var fontAttributeMask: [ChatTextFontAttributes] = Array(repeating: [], count: string.length)