This commit is contained in:
Isaac 2025-10-26 22:05:58 +04:00
parent fcdfd8e00f
commit c880397eca
17 changed files with 194 additions and 58 deletions

View File

@ -1338,9 +1338,9 @@ public final class Transaction {
self.postbox!.setStoryItems(peerId: peerId, items: items) self.postbox!.setStoryItems(peerId: peerId, items: items)
} }
public func setStoryItemsInexactMaxId(peerId: PeerId, id: Int32) { public func setStoryItemsInexactMaxId(peerId: PeerId, id: Int32, hasLiveItems: Bool) {
assert(!self.disposed) assert(!self.disposed)
self.postbox!.setStoryItemsInexactMaxId(peerId: peerId, id: id) self.postbox!.setStoryItemsInexactMaxId(peerId: peerId, id: id, hasLiveItems: hasLiveItems)
} }
public func clearStoryItemsInexactMaxId(peerId: PeerId) { public func clearStoryItemsInexactMaxId(peerId: PeerId) {
@ -2451,10 +2451,10 @@ final class PostboxImpl {
} }
} }
fileprivate func setStoryItemsInexactMaxId(peerId: PeerId, id: Int32) { fileprivate func setStoryItemsInexactMaxId(peerId: PeerId, id: Int32, hasLiveItems: Bool) {
if let value = self.storyTopItemsTable.get(peerId: peerId), value.id >= id { if let value = self.storyTopItemsTable.get(peerId: peerId), value.id >= id {
} else { } else {
self.storyTopItemsTable.set(peerId: peerId, entry: StoryTopItemsTable.Entry(id: id, isExact: false), events: &self.currentStoryTopItemEvents) self.storyTopItemsTable.set(peerId: peerId, entry: StoryTopItemsTable.Entry(id: id, isExact: false, hasLiveItems: hasLiveItems), events: &self.currentStoryTopItemEvents)
} }
} }

View File

@ -48,6 +48,7 @@ final class StoryTopItemsTable: Table {
struct Entry { struct Entry {
var id: Int32 var id: Int32
var isExact: Bool var isExact: Bool
var hasLiveItems: Bool
} }
enum Event { enum Event {
@ -78,10 +79,12 @@ final class StoryTopItemsTable: Table {
} }
var maxId: Int32 = 0 var maxId: Int32 = 0
buffer.read(&maxId, offset: 0, length: 4) buffer.read(&maxId, offset: 0, length: 4)
var isExact: Int8 = 0 var flags: Int8 = 0
buffer.read(&isExact, offset: 0, length: 1) buffer.read(&flags, offset: 0, length: 1)
let isExact = (flags & (1 << 0)) != 0
let hasLiveItems = (flags & (1 << 1)) != 0
return Entry(id: maxId, isExact: isExact != 0) return Entry(id: maxId, isExact: isExact, hasLiveItems: hasLiveItems)
} else { } else {
return nil return nil
} }
@ -95,8 +98,14 @@ final class StoryTopItemsTable: Table {
buffer.write(&version, length: 1) buffer.write(&version, length: 1)
var maxId = entry.id var maxId = entry.id
buffer.write(&maxId, length: 4) buffer.write(&maxId, length: 4)
var isExact: Int8 = entry.isExact ? 1 : 0 var flags: Int8 = 0
buffer.write(&isExact, length: 1) if entry.isExact {
flags |= 1 << 0
}
if entry.hasLiveItems {
flags |= 1 << 1
}
buffer.write(&flags, length: 1)
self.valueBox.set(self.table, key: self.key(Key(peerId: peerId)), value: buffer.readBufferNoCopy()) self.valueBox.set(self.table, key: self.key(Key(peerId: peerId)), value: buffer.readBufferNoCopy())
} else { } else {
@ -382,6 +391,8 @@ final class StoryItemsTable: Table {
self.valueBox.remove(self.table, key: key, secure: true) self.valueBox.remove(self.table, key: key, secure: true)
} }
var hasLiveItems = false
let buffer = WriteBuffer() let buffer = WriteBuffer()
for entry in entries { for entry in entries {
buffer.reset() buffer.reset()
@ -401,6 +412,7 @@ final class StoryItemsTable: Table {
flags |= (1 << 0) flags |= (1 << 0)
} }
if entry.isLiveStream { if entry.isLiveStream {
hasLiveItems = true
flags |= (1 << 1) flags |= (1 << 1)
} }
buffer.write(&flags, length: 1) buffer.write(&flags, length: 1)
@ -410,7 +422,7 @@ final class StoryItemsTable: Table {
events.append(.replace(peerId: peerId)) events.append(.replace(peerId: peerId))
topItemTable.set(peerId: peerId, entry: StoryTopItemsTable.Entry(id: entries.last?.id ?? 0, isExact: true), events: &topItemEvents) topItemTable.set(peerId: peerId, entry: StoryTopItemsTable.Entry(id: entries.last?.id ?? 0, isExact: true, hasLiveItems: hasLiveItems), events: &topItemEvents)
} }
override func clearMemoryCache() { override func clearMemoryCache() {

View File

@ -196,7 +196,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-531931925] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsMentions($0) } dict[-531931925] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsMentions($0) }
dict[-566281095] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsRecent($0) } dict[-566281095] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsRecent($0) }
dict[106343499] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsSearch($0) } dict[106343499] = { return Api.ChannelParticipantsFilter.parse_channelParticipantsSearch($0) }
dict[-26717355] = { return Api.Chat.parse_channel($0) } dict[473084188] = { return Api.Chat.parse_channel($0) }
dict[399807445] = { return Api.Chat.parse_channelForbidden($0) } dict[399807445] = { return Api.Chat.parse_channelForbidden($0) }
dict[1103884886] = { return Api.Chat.parse_chat($0) } dict[1103884886] = { return Api.Chat.parse_chat($0) }
dict[693512293] = { return Api.Chat.parse_chatEmpty($0) } dict[693512293] = { return Api.Chat.parse_chatEmpty($0) }
@ -857,6 +857,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1140172836] = { return Api.RecentMeUrl.parse_recentMeUrlStickerSet($0) } dict[-1140172836] = { return Api.RecentMeUrl.parse_recentMeUrlStickerSet($0) }
dict[1189204285] = { return Api.RecentMeUrl.parse_recentMeUrlUnknown($0) } dict[1189204285] = { return Api.RecentMeUrl.parse_recentMeUrlUnknown($0) }
dict[-1188296222] = { return Api.RecentMeUrl.parse_recentMeUrlUser($0) } dict[-1188296222] = { return Api.RecentMeUrl.parse_recentMeUrlUser($0) }
dict[1897752877] = { return Api.RecentStory.parse_recentStory($0) }
dict[1218642516] = { return Api.ReplyMarkup.parse_replyInlineMarkup($0) } dict[1218642516] = { return Api.ReplyMarkup.parse_replyInlineMarkup($0) }
dict[-2035021048] = { return Api.ReplyMarkup.parse_replyKeyboardForceReply($0) } dict[-2035021048] = { return Api.ReplyMarkup.parse_replyKeyboardForceReply($0) }
dict[-1606526075] = { return Api.ReplyMarkup.parse_replyKeyboardHide($0) } dict[-1606526075] = { return Api.ReplyMarkup.parse_replyKeyboardHide($0) }
@ -1208,7 +1209,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1886646706] = { return Api.UrlAuthResult.parse_urlAuthResultAccepted($0) } dict[-1886646706] = { return Api.UrlAuthResult.parse_urlAuthResultAccepted($0) }
dict[-1445536993] = { return Api.UrlAuthResult.parse_urlAuthResultDefault($0) } dict[-1445536993] = { return Api.UrlAuthResult.parse_urlAuthResultDefault($0) }
dict[-1831650802] = { return Api.UrlAuthResult.parse_urlAuthResultRequest($0) } dict[-1831650802] = { return Api.UrlAuthResult.parse_urlAuthResultRequest($0) }
dict[34280482] = { return Api.User.parse_user($0) } dict[829899656] = { return Api.User.parse_user($0) }
dict[-742634630] = { return Api.User.parse_userEmpty($0) } dict[-742634630] = { return Api.User.parse_userEmpty($0) }
dict[-1607745218] = { return Api.UserFull.parse_userFull($0) } dict[-1607745218] = { return Api.UserFull.parse_userFull($0) }
dict[-2100168954] = { return Api.UserProfilePhoto.parse_userProfilePhoto($0) } dict[-2100168954] = { return Api.UserProfilePhoto.parse_userProfilePhoto($0) }
@ -2126,6 +2127,8 @@ public extension Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.RecentMeUrl: case let _1 as Api.RecentMeUrl:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.RecentStory:
_1.serialize(buffer, boxed)
case let _1 as Api.ReplyMarkup: case let _1 as Api.ReplyMarkup:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.ReportReason: case let _1 as Api.ReportReason:

View File

@ -174,6 +174,46 @@ public extension Api {
} }
} }
public extension Api {
enum RecentStory: TypeConstructorDescription {
case recentStory(flags: Int32, maxId: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .recentStory(let flags, let maxId):
if boxed {
buffer.appendInt32(1897752877)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(maxId!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .recentStory(let flags, let maxId):
return ("recentStory", [("flags", flags as Any), ("maxId", maxId as Any)])
}
}
public static func parse_recentStory(_ reader: BufferReader) -> RecentStory? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
if Int(_1!) & Int(1 << 1) != 0 {_2 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 1) == 0) || _2 != nil
if _c1 && _c2 {
return Api.RecentStory.recentStory(flags: _1!, maxId: _2)
}
else {
return nil
}
}
}
}
public extension Api { public extension Api {
enum ReplyMarkup: TypeConstructorDescription { enum ReplyMarkup: TypeConstructorDescription {
case replyInlineMarkup(rows: [Api.KeyboardButtonRow]) case replyInlineMarkup(rows: [Api.KeyboardButtonRow])

View File

@ -452,14 +452,14 @@ public extension Api {
} }
public extension Api { public extension Api {
enum User: TypeConstructorDescription { enum User: TypeConstructorDescription {
case user(flags: Int32, flags2: Int32, id: Int64, accessHash: Int64?, firstName: String?, lastName: String?, username: String?, phone: String?, photo: Api.UserProfilePhoto?, status: Api.UserStatus?, botInfoVersion: Int32?, restrictionReason: [Api.RestrictionReason]?, botInlinePlaceholder: String?, langCode: String?, emojiStatus: Api.EmojiStatus?, usernames: [Api.Username]?, storiesMaxId: Int32?, color: Api.PeerColor?, profileColor: Api.PeerColor?, botActiveUsers: Int32?, botVerificationIcon: Int64?, sendPaidMessagesStars: Int64?) case user(flags: Int32, flags2: Int32, id: Int64, accessHash: Int64?, firstName: String?, lastName: String?, username: String?, phone: String?, photo: Api.UserProfilePhoto?, status: Api.UserStatus?, botInfoVersion: Int32?, restrictionReason: [Api.RestrictionReason]?, botInlinePlaceholder: String?, langCode: String?, emojiStatus: Api.EmojiStatus?, usernames: [Api.Username]?, storiesMaxId: Api.RecentStory?, color: Api.PeerColor?, profileColor: Api.PeerColor?, botActiveUsers: Int32?, botVerificationIcon: Int64?, sendPaidMessagesStars: Int64?)
case userEmpty(id: Int64) case userEmpty(id: Int64)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .user(let flags, let flags2, let id, let accessHash, let firstName, let lastName, let username, let phone, let photo, let status, let botInfoVersion, let restrictionReason, let botInlinePlaceholder, let langCode, let emojiStatus, let usernames, let storiesMaxId, let color, let profileColor, let botActiveUsers, let botVerificationIcon, let sendPaidMessagesStars): case .user(let flags, let flags2, let id, let accessHash, let firstName, let lastName, let username, let phone, let photo, let status, let botInfoVersion, let restrictionReason, let botInlinePlaceholder, let langCode, let emojiStatus, let usernames, let storiesMaxId, let color, let profileColor, let botActiveUsers, let botVerificationIcon, let sendPaidMessagesStars):
if boxed { if boxed {
buffer.appendInt32(34280482) buffer.appendInt32(829899656)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(flags2, buffer: buffer, boxed: false) serializeInt32(flags2, buffer: buffer, boxed: false)
@ -485,7 +485,7 @@ public extension Api {
for item in usernames! { for item in usernames! {
item.serialize(buffer, true) item.serialize(buffer, true)
}} }}
if Int(flags2) & Int(1 << 5) != 0 {serializeInt32(storiesMaxId!, buffer: buffer, boxed: false)} if Int(flags2) & Int(1 << 5) != 0 {storiesMaxId!.serialize(buffer, true)}
if Int(flags2) & Int(1 << 8) != 0 {color!.serialize(buffer, true)} if Int(flags2) & Int(1 << 8) != 0 {color!.serialize(buffer, true)}
if Int(flags2) & Int(1 << 9) != 0 {profileColor!.serialize(buffer, true)} if Int(flags2) & Int(1 << 9) != 0 {profileColor!.serialize(buffer, true)}
if Int(flags2) & Int(1 << 12) != 0 {serializeInt32(botActiveUsers!, buffer: buffer, boxed: false)} if Int(flags2) & Int(1 << 12) != 0 {serializeInt32(botActiveUsers!, buffer: buffer, boxed: false)}
@ -553,8 +553,10 @@ public extension Api {
if Int(_2!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() { if Int(_2!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() {
_16 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Username.self) _16 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Username.self)
} } } }
var _17: Int32? var _17: Api.RecentStory?
if Int(_2!) & Int(1 << 5) != 0 {_17 = reader.readInt32() } if Int(_2!) & Int(1 << 5) != 0 {if let signature = reader.readInt32() {
_17 = Api.parse(reader, signature: signature) as? Api.RecentStory
} }
var _18: Api.PeerColor? var _18: Api.PeerColor?
if Int(_2!) & Int(1 << 8) != 0 {if let signature = reader.readInt32() { if Int(_2!) & Int(1 << 8) != 0 {if let signature = reader.readInt32() {
_18 = Api.parse(reader, signature: signature) as? Api.PeerColor _18 = Api.parse(reader, signature: signature) as? Api.PeerColor

View File

@ -11816,19 +11816,19 @@ public extension Api.functions.stories {
} }
} }
public extension Api.functions.stories { public extension Api.functions.stories {
static func getPeerMaxIDs(id: [Api.InputPeer]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Int32]>) { static func getPeerMaxIDs(id: [Api.InputPeer]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.RecentStory]>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(1398375363) buffer.appendInt32(2018087280)
buffer.appendInt32(481674261) buffer.appendInt32(481674261)
buffer.appendInt32(Int32(id.count)) buffer.appendInt32(Int32(id.count))
for item in id { for item in id {
item.serialize(buffer, true) item.serialize(buffer, true)
} }
return (FunctionDescription(name: "stories.getPeerMaxIDs", parameters: [("id", String(describing: id))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Int32]? in return (FunctionDescription(name: "stories.getPeerMaxIDs", parameters: [("id", String(describing: id))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.RecentStory]? in
let reader = BufferReader(buffer) let reader = BufferReader(buffer)
var result: [Int32]? var result: [Api.RecentStory]?
if let _ = reader.readInt32() { if let _ = reader.readInt32() {
result = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) result = Api.parseVector(reader, elementSignature: 0, elementType: Api.RecentStory.self)
} }
return result return result
}) })

View File

@ -534,7 +534,7 @@ public extension Api {
} }
public extension Api { public extension Api {
indirect enum Chat: TypeConstructorDescription { indirect enum Chat: TypeConstructorDescription {
case channel(flags: Int32, flags2: Int32, id: Int64, accessHash: Int64?, title: String, username: String?, photo: Api.ChatPhoto, date: Int32, restrictionReason: [Api.RestrictionReason]?, adminRights: Api.ChatAdminRights?, bannedRights: Api.ChatBannedRights?, defaultBannedRights: Api.ChatBannedRights?, participantsCount: Int32?, usernames: [Api.Username]?, storiesMaxId: Int32?, color: Api.PeerColor?, profileColor: Api.PeerColor?, emojiStatus: Api.EmojiStatus?, level: Int32?, subscriptionUntilDate: Int32?, botVerificationIcon: Int64?, sendPaidMessagesStars: Int64?, linkedMonoforumId: Int64?) case channel(flags: Int32, flags2: Int32, id: Int64, accessHash: Int64?, title: String, username: String?, photo: Api.ChatPhoto, date: Int32, restrictionReason: [Api.RestrictionReason]?, adminRights: Api.ChatAdminRights?, bannedRights: Api.ChatBannedRights?, defaultBannedRights: Api.ChatBannedRights?, participantsCount: Int32?, usernames: [Api.Username]?, storiesMaxId: Api.RecentStory?, color: Api.PeerColor?, profileColor: Api.PeerColor?, emojiStatus: Api.EmojiStatus?, level: Int32?, subscriptionUntilDate: Int32?, botVerificationIcon: Int64?, sendPaidMessagesStars: Int64?, linkedMonoforumId: Int64?)
case channelForbidden(flags: Int32, id: Int64, accessHash: Int64, title: String, untilDate: Int32?) case channelForbidden(flags: Int32, id: Int64, accessHash: Int64, title: String, untilDate: Int32?)
case chat(flags: Int32, id: Int64, title: String, photo: Api.ChatPhoto, participantsCount: Int32, date: Int32, version: Int32, migratedTo: Api.InputChannel?, adminRights: Api.ChatAdminRights?, defaultBannedRights: Api.ChatBannedRights?) case chat(flags: Int32, id: Int64, title: String, photo: Api.ChatPhoto, participantsCount: Int32, date: Int32, version: Int32, migratedTo: Api.InputChannel?, adminRights: Api.ChatAdminRights?, defaultBannedRights: Api.ChatBannedRights?)
case chatEmpty(id: Int64) case chatEmpty(id: Int64)
@ -544,7 +544,7 @@ public extension Api {
switch self { switch self {
case .channel(let flags, let flags2, let id, let accessHash, let title, let username, let photo, let date, let restrictionReason, let adminRights, let bannedRights, let defaultBannedRights, let participantsCount, let usernames, let storiesMaxId, let color, let profileColor, let emojiStatus, let level, let subscriptionUntilDate, let botVerificationIcon, let sendPaidMessagesStars, let linkedMonoforumId): case .channel(let flags, let flags2, let id, let accessHash, let title, let username, let photo, let date, let restrictionReason, let adminRights, let bannedRights, let defaultBannedRights, let participantsCount, let usernames, let storiesMaxId, let color, let profileColor, let emojiStatus, let level, let subscriptionUntilDate, let botVerificationIcon, let sendPaidMessagesStars, let linkedMonoforumId):
if boxed { if boxed {
buffer.appendInt32(-26717355) buffer.appendInt32(473084188)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(flags2, buffer: buffer, boxed: false) serializeInt32(flags2, buffer: buffer, boxed: false)
@ -568,7 +568,7 @@ public extension Api {
for item in usernames! { for item in usernames! {
item.serialize(buffer, true) item.serialize(buffer, true)
}} }}
if Int(flags2) & Int(1 << 4) != 0 {serializeInt32(storiesMaxId!, buffer: buffer, boxed: false)} if Int(flags2) & Int(1 << 4) != 0 {storiesMaxId!.serialize(buffer, true)}
if Int(flags2) & Int(1 << 7) != 0 {color!.serialize(buffer, true)} if Int(flags2) & Int(1 << 7) != 0 {color!.serialize(buffer, true)}
if Int(flags2) & Int(1 << 8) != 0 {profileColor!.serialize(buffer, true)} if Int(flags2) & Int(1 << 8) != 0 {profileColor!.serialize(buffer, true)}
if Int(flags2) & Int(1 << 9) != 0 {emojiStatus!.serialize(buffer, true)} if Int(flags2) & Int(1 << 9) != 0 {emojiStatus!.serialize(buffer, true)}
@ -675,8 +675,10 @@ public extension Api {
if Int(_2!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() { if Int(_2!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() {
_14 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Username.self) _14 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Username.self)
} } } }
var _15: Int32? var _15: Api.RecentStory?
if Int(_2!) & Int(1 << 4) != 0 {_15 = reader.readInt32() } if Int(_2!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() {
_15 = Api.parse(reader, signature: signature) as? Api.RecentStory
} }
var _16: Api.PeerColor? var _16: Api.PeerColor?
if Int(_2!) & Int(1 << 7) != 0 {if let signature = reader.readInt32() { if Int(_2!) & Int(1 << 7) != 0 {if let signature = reader.readInt32() {
_16 = Api.parse(reader, signature: signature) as? Api.PeerColor _16 = Api.parse(reader, signature: signature) as? Api.PeerColor

View File

@ -1431,7 +1431,7 @@ public final class AccountViewTracker {
} }
startIndex += batchCount startIndex += batchCount
requests.append(account.network.request(Api.functions.stories.getPeerMaxIDs(id: slice.map(\.1))) requests.append(account.network.request(Api.functions.stories.getPeerMaxIDs(id: slice.map(\.1)))
|> `catch` { _ -> Signal<[Int32], NoError> in |> `catch` { _ -> Signal<[Api.RecentStory], NoError> in
return .single([]) return .single([])
} }
|> mapToSignal { result -> Signal<Never, NoError> in |> mapToSignal { result -> Signal<Never, NoError> in
@ -1439,10 +1439,13 @@ public final class AccountViewTracker {
for i in 0 ..< result.count { for i in 0 ..< result.count {
if i < slice.count { if i < slice.count {
let value = result[i] let value = result[i]
if value <= 0 { switch value {
transaction.clearStoryItemsInexactMaxId(peerId: slice[i].0) case let .recentStory(flags, maxId):
} else { if let maxId {
transaction.setStoryItemsInexactMaxId(peerId: slice[i].0, id: value) transaction.setStoryItemsInexactMaxId(peerId: slice[i].0, id: maxId, hasLiveItems: (flags & (1 << 0)) != 0)
} else {
transaction.clearStoryItemsInexactMaxId(peerId: slice[i].0)
}
} }
} }
} }

View File

@ -3703,6 +3703,7 @@ public final class GroupCallMessagesContext {
} }
public let id: Id public let id: Id
public let stableId: Int
public let author: EnginePeer? public let author: EnginePeer?
public let text: String public let text: String
public let entities: [MessageTextEntity] public let entities: [MessageTextEntity]
@ -3710,8 +3711,9 @@ public final class GroupCallMessagesContext {
public let lifetime: Int32 public let lifetime: Int32
public let paidStars: Int64? public let paidStars: Int64?
public init(id: Id, author: EnginePeer?, text: String, entities: [MessageTextEntity], date: Int32, lifetime: Int32, paidStars: Int64?) { public init(id: Id, stableId: Int, author: EnginePeer?, text: String, entities: [MessageTextEntity], date: Int32, lifetime: Int32, paidStars: Int64?) {
self.id = id self.id = id
self.stableId = stableId
self.author = author self.author = author
self.text = text self.text = text
self.entities = entities self.entities = entities
@ -3723,6 +3725,7 @@ public final class GroupCallMessagesContext {
public func withId(_ id: Id) -> Message { public func withId(_ id: Id) -> Message {
return Message( return Message(
id: id, id: id,
stableId: self.stableId,
author: self.author, author: self.author,
text: self.text, text: self.text,
entities: self.entities, entities: self.entities,
@ -3733,11 +3736,14 @@ public final class GroupCallMessagesContext {
} }
public static func ==(lhs: Message, rhs: Message) -> Bool { public static func ==(lhs: Message, rhs: Message) -> Bool {
if lhs === rhs {
return true
}
if lhs.id != rhs.id { if lhs.id != rhs.id {
return false return false
} }
if lhs === rhs { if lhs.stableId != rhs.stableId {
return true return false
} }
if lhs.author != rhs.author { if lhs.author != rhs.author {
return false return false
@ -3837,6 +3843,7 @@ public final class GroupCallMessagesContext {
let sendMessageDisposables = DisposableSet() let sendMessageDisposables = DisposableSet()
var processedIds = Set<Int64>() var processedIds = Set<Int64>()
var nextStableId: Int = 0
private var messageLifeTimer: SwiftSignalKit.Timer? private var messageLifeTimer: SwiftSignalKit.Timer?
@ -3881,6 +3888,11 @@ public final class GroupCallMessagesContext {
if !addedMessages.isEmpty || !addedOpaqueMessages.isEmpty { if !addedMessages.isEmpty || !addedOpaqueMessages.isEmpty {
let messageLifetime = self.messageLifetime let messageLifetime = self.messageLifetime
let isLiveStream = self.isLiveStream let isLiveStream = self.isLiveStream
let allocatedStableIds = (0 ..< (addedOpaqueMessages.count + addedMessages.count)).map { _ in
let value = self.nextStableId
self.nextStableId += 1
return value
}
let _ = (self.account.postbox.transaction { transaction -> [Message] in let _ = (self.account.postbox.transaction { transaction -> [Message] in
var messages: [Message] = [] var messages: [Message] = []
@ -3907,8 +3919,13 @@ public final class GroupCallMessagesContext {
guard let (randomId, text, entities) = deserializeGroupCallMessage(data: decryptedMessage) else { guard let (randomId, text, entities) = deserializeGroupCallMessage(data: decryptedMessage) else {
continue continue
} }
if allocatedStableIds.count <= messages.count {
assertionFailure()
break
}
messages.append(Message( messages.append(Message(
id: Message.Id(space: .remote, id: randomId), id: Message.Id(space: .remote, id: randomId),
stableId: allocatedStableIds[messages.count],
author: transaction.getPeer(addedOpaqueMessage.authorId).flatMap(EnginePeer.init), author: transaction.getPeer(addedOpaqueMessage.authorId).flatMap(EnginePeer.init),
text: text, text: text,
entities: entities, entities: entities,
@ -3930,16 +3947,21 @@ public final class GroupCallMessagesContext {
lifetime = self.messageLifetime lifetime = self.messageLifetime
} }
let message = Message( if allocatedStableIds.count <= messages.count {
assertionFailure()
break
}
messages.append(Message(
id: Message.Id(space: .remote, id: Int64(addedMessage.messageId)), id: Message.Id(space: .remote, id: Int64(addedMessage.messageId)),
stableId: allocatedStableIds[messages.count],
author: transaction.getPeer(addedMessage.authorId).flatMap(EnginePeer.init), author: transaction.getPeer(addedMessage.authorId).flatMap(EnginePeer.init),
text: addedMessage.text, text: addedMessage.text,
entities: addedMessage.entities, entities: addedMessage.entities,
date: addedMessage.timestamp, date: addedMessage.timestamp,
lifetime: lifetime, lifetime: lifetime,
paidStars: addedMessage.paidMessageStars paidStars: addedMessage.paidMessageStars
) ))
messages.append(message)
} }
} }
return messages return messages
@ -3973,6 +3995,12 @@ public final class GroupCallMessagesContext {
} }
} }
} }
state.messages.sort(by: { lhs, rhs in
if lhs.date != rhs.date {
return lhs.date < rhs.date
}
return lhs.stableId < rhs.stableId
})
self.state = state self.state = state
self.didInitializeTopStars = true self.didInitializeTopStars = true
@ -4203,8 +4231,11 @@ public final class GroupCallMessagesContext {
} }
var state = self.state var state = self.state
let stableId = self.nextStableId
self.nextStableId += 1
let message = Message( let message = Message(
id: Message.Id(space: .local, id: randomId), id: Message.Id(space: .local, id: randomId),
stableId: stableId,
author: fromPeer.flatMap(EnginePeer.init), author: fromPeer.flatMap(EnginePeer.init),
text: text, text: text,
entities: entities, entities: entities,
@ -4403,6 +4434,7 @@ public final class GroupCallMessagesContext {
state.messages.remove(at: index) state.messages.remove(at: index)
state.messages.append(Message( state.messages.append(Message(
id: message.id, id: message.id,
stableId: message.stableId,
author: message.author, author: message.author,
text: message.text, text: message.text,
entities: message.entities, entities: message.entities,
@ -4411,8 +4443,11 @@ public final class GroupCallMessagesContext {
paidStars: totalAmount paidStars: totalAmount
)) ))
} else { } else {
let stableId = self.nextStableId
self.nextStableId += 1
state.messages.append(Message( state.messages.append(Message(
id: Message.Id(space: .local, id: pendingSendStarsValue.messageId), id: Message.Id(space: .local, id: pendingSendStarsValue.messageId),
stableId: stableId,
author: fromPeer.flatMap(EnginePeer.init), author: fromPeer.flatMap(EnginePeer.init),
text: "", text: "",
entities: [], entities: [],
@ -4426,6 +4461,7 @@ public final class GroupCallMessagesContext {
state.pinnedMessages.remove(at: index) state.pinnedMessages.remove(at: index)
state.pinnedMessages.append(Message( state.pinnedMessages.append(Message(
id: message.id, id: message.id,
stableId: message.stableId,
author: message.author, author: message.author,
text: message.text, text: message.text,
entities: message.entities, entities: message.entities,
@ -4434,8 +4470,11 @@ public final class GroupCallMessagesContext {
paidStars: totalAmount paidStars: totalAmount
)) ))
} else { } else {
let stableId = self.nextStableId
self.nextStableId += 1
state.pinnedMessages.append(Message( state.pinnedMessages.append(Message(
id: Message.Id(space: .local, id: pendingSendStarsValue.messageId), id: Message.Id(space: .local, id: pendingSendStarsValue.messageId),
stableId: stableId,
author: fromPeer.flatMap(EnginePeer.init), author: fromPeer.flatMap(EnginePeer.init),
text: "", text: "",
entities: [], entities: [],

View File

@ -55,8 +55,17 @@ func updatePeers(transaction: Transaction, accountPeerId: PeerId, peers: Accumul
let isMin = (flags & (1 << 20)) != 0 let isMin = (flags & (1 << 20)) != 0
let storiesUnavailable = (flags2 & (1 << 4)) != 0 let storiesUnavailable = (flags2 & (1 << 4)) != 0
if let storiesMaxId = storiesMaxId { if let storiesMaxId {
transaction.setStoryItemsInexactMaxId(peerId: user.peerId, id: storiesMaxId) switch storiesMaxId {
case let .recentStory(flags, maxId):
if let maxId {
transaction.setStoryItemsInexactMaxId(peerId: user.peerId, id: maxId, hasLiveItems: (flags & (1 << 0)) != 0)
} else {
if !isMin && storiesUnavailable {
transaction.clearStoryItemsInexactMaxId(peerId: user.peerId)
}
}
}
} else if !isMin && storiesUnavailable { } else if !isMin && storiesUnavailable {
transaction.clearStoryItemsInexactMaxId(peerId: user.peerId) transaction.clearStoryItemsInexactMaxId(peerId: user.peerId)
} }
@ -76,8 +85,17 @@ func updatePeers(transaction: Transaction, accountPeerId: PeerId, peers: Accumul
let isMin = (flags & (1 << 12)) != 0 let isMin = (flags & (1 << 12)) != 0
let storiesUnavailable = (flags2 & (1 << 3)) != 0 let storiesUnavailable = (flags2 & (1 << 3)) != 0
if let storiesMaxId = storiesMaxId { if let storiesMaxId {
transaction.setStoryItemsInexactMaxId(peerId: chat.peerId, id: storiesMaxId) switch storiesMaxId {
case let .recentStory(flags, maxId):
if let maxId {
transaction.setStoryItemsInexactMaxId(peerId: chat.peerId, id: maxId, hasLiveItems: (flags & (1 << 0)) != 0)
} else {
if !isMin && storiesUnavailable {
transaction.clearStoryItemsInexactMaxId(peerId: chat.peerId)
}
}
}
} else if !isMin && storiesUnavailable { } else if !isMin && storiesUnavailable {
transaction.clearStoryItemsInexactMaxId(peerId: chat.peerId) transaction.clearStoryItemsInexactMaxId(peerId: chat.peerId)
} }

View File

@ -993,7 +993,8 @@ private final class AdminUserActionsSheetComponent: Component {
maximumNumberOfLines: 0 maximumNumberOfLines: 0
)), )),
footer: nil, footer: nil,
items: optionsSectionItems items: optionsSectionItems,
isModal: true
)), )),
environment: {}, environment: {},
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 100000.0) containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 100000.0)

View File

@ -424,8 +424,11 @@ public final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode {
let (title, _) = titleAndColorForAction(action, theme: interfaceState.theme, strings: interfaceState.strings) let (title, _) = titleAndColorForAction(action, theme: interfaceState.theme, strings: interfaceState.strings)
var isAccent = false var isAccent = false
if case .join = self.action { switch self.action {
case .join, .joinGroup, .applyToJoin:
isAccent = true isAccent = true
default:
break
} }
centerAction = (title, isAccent) centerAction = (title, isAccent)
} }

View File

@ -1959,6 +1959,7 @@ private final class ChatSendStarsScreenComponent: Component {
space: .local, space: .local,
id: 1 id: 1
), ),
stableId: 0,
author: liveStreamMessage.myPeer, author: liveStreamMessage.myPeer,
text: liveStreamMessage.text.string, text: liveStreamMessage.text.string,
entities: entities, entities: entities,
@ -1972,6 +1973,7 @@ private final class ChatSendStarsScreenComponent: Component {
space: .local, space: .local,
id: 1 id: 1
), ),
stableId: 0,
author: reactData.myPeer, author: reactData.myPeer,
text: "", text: "",
entities: [], entities: [],

View File

@ -409,22 +409,37 @@ public class GlassBackgroundView: UIView {
let innerBackgroundRadius = min(innerBackgroundFrame.width, innerBackgroundFrame.height) * 0.5 let innerBackgroundRadius = min(innerBackgroundFrame.width, innerBackgroundFrame.height) * 0.5
let innerBackgroundView: UIView let innerBackgroundView: UIView
var innerBackgroundTransition = transition
var animateIn = false
if let current = self.innerBackgroundView { if let current = self.innerBackgroundView {
innerBackgroundView = current innerBackgroundView = current
} else { } else {
innerBackgroundView = UIView() innerBackgroundView = UIView()
innerBackgroundTransition = innerBackgroundTransition.withAnimation(.none)
self.innerBackgroundView = innerBackgroundView self.innerBackgroundView = innerBackgroundView
self.contentView.insertSubview(innerBackgroundView, at: 0) self.contentView.insertSubview(innerBackgroundView, at: 0)
innerBackgroundView.frame = innerBackgroundFrame innerBackgroundView.frame = innerBackgroundFrame
innerBackgroundView.layer.cornerRadius = innerBackgroundRadius innerBackgroundView.layer.cornerRadius = innerBackgroundRadius
animateIn = true
} }
innerBackgroundView.backgroundColor = innerColor innerBackgroundView.backgroundColor = innerColor
transition.setFrame(view: innerBackgroundView, frame: innerBackgroundFrame) innerBackgroundTransition.setFrame(view: innerBackgroundView, frame: innerBackgroundFrame)
transition.setCornerRadius(layer: innerBackgroundView.layer, cornerRadius: innerBackgroundRadius) innerBackgroundTransition.setCornerRadius(layer: innerBackgroundView.layer, cornerRadius: innerBackgroundRadius)
if animateIn {
transition.animateAlpha(view: innerBackgroundView, from: 0.0, to: 1.0)
transition.animateScale(view: innerBackgroundView, from: 0.001, to: 1.0)
}
} else if let innerBackgroundView = self.innerBackgroundView { } else if let innerBackgroundView = self.innerBackgroundView {
self.innerBackgroundView = nil self.innerBackgroundView = nil
transition.setAlpha(view: innerBackgroundView, alpha: 0.0, completion: { [weak innerBackgroundView] _ in
innerBackgroundView?.removeFromSuperview()
})
transition.setScale(view: innerBackgroundView, scale: 0.001)
innerBackgroundView.removeFromSuperview() innerBackgroundView.removeFromSuperview()
} }

View File

@ -218,6 +218,13 @@ public final class GlassControlPanelComponent: Component {
if let leftItemFrame { if let leftItemFrame {
centralLeftInset = leftItemFrame.maxX + minSpacing centralLeftInset = leftItemFrame.maxX + minSpacing
} }
if centralRightInset <= 48.0 && centralLeftInset <= 48.0 {
let maxInset = max(centralRightInset, centralLeftInset)
centralLeftInset = maxInset
centralRightInset = maxInset
}
maxCentralItemSize.width = max(1.0, availableSize.width - centralLeftInset - centralRightInset) maxCentralItemSize.width = max(1.0, availableSize.width - centralLeftInset - centralRightInset)
let centralItemSize = centralItemComponent.update( let centralItemSize = centralItemComponent.update(

View File

@ -331,15 +331,9 @@ public final class ListSectionComponent: Component {
case legacy case legacy
} }
public enum BackgroundColor {
case base
case modal
}
public let theme: PresentationTheme public let theme: PresentationTheme
public let style: Style public let style: Style
public let background: Background public let background: Background
public let backgroundColor: BackgroundColor
public let header: AnyComponent<Empty>? public let header: AnyComponent<Empty>?
public let footer: AnyComponent<Empty>? public let footer: AnyComponent<Empty>?
public let items: [AnyComponentWithIdentity<Empty>] public let items: [AnyComponentWithIdentity<Empty>]
@ -351,7 +345,6 @@ public final class ListSectionComponent: Component {
theme: PresentationTheme, theme: PresentationTheme,
style: Style = .legacy, style: Style = .legacy,
background: Background = .all, background: Background = .all,
backgroundColor: BackgroundColor = .base,
header: AnyComponent<Empty>?, header: AnyComponent<Empty>?,
footer: AnyComponent<Empty>?, footer: AnyComponent<Empty>?,
items: [AnyComponentWithIdentity<Empty>], items: [AnyComponentWithIdentity<Empty>],
@ -362,7 +355,6 @@ public final class ListSectionComponent: Component {
self.theme = theme self.theme = theme
self.style = style self.style = style
self.background = background self.background = background
self.backgroundColor = backgroundColor
self.header = header self.header = header
self.footer = footer self.footer = footer
self.items = items self.items = items
@ -381,9 +373,6 @@ public final class ListSectionComponent: Component {
if lhs.background != rhs.background { if lhs.background != rhs.background {
return false return false
} }
if lhs.backgroundColor != rhs.backgroundColor {
return false
}
if lhs.header != rhs.header { if lhs.header != rhs.header {
return false return false
} }

View File

@ -798,7 +798,7 @@ final class StoryContentLiveChatComponent: Component {
if let messagesState = self.messagesState { if let messagesState = self.messagesState {
for message in messagesState.messages.reversed() { for message in messagesState.messages.reversed() {
let messageId = message.id let messageId = message.id
listItems.append(AnyComponentWithIdentity(id: message.id, component: AnyComponent(StoryLiveChatMessageComponent( listItems.append(AnyComponentWithIdentity(id: message.stableId, component: AnyComponent(StoryLiveChatMessageComponent(
context: component.context, context: component.context,
strings: component.strings, strings: component.strings,
theme: component.theme, theme: component.theme,