mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-06 17:00:13 +00:00
Refactoring
This commit is contained in:
parent
1a0dc56953
commit
7e6eb2b3bd
@ -22,9 +22,7 @@ private func setupSharedLogger(rootPath: String, path: String) {
|
||||
}
|
||||
}
|
||||
|
||||
private let accountAuxiliaryMethods = AccountAuxiliaryMethods(updatePeerChatInputState: { interfaceState, inputState -> PeerChatInterfaceState? in
|
||||
return interfaceState
|
||||
}, fetchResource: { account, resource, ranges, _ in
|
||||
private let accountAuxiliaryMethods = AccountAuxiliaryMethods(fetchResource: { account, resource, ranges, _ in
|
||||
return nil
|
||||
}, fetchResourceMediaReferenceHash: { resource in
|
||||
return .single(nil)
|
||||
|
||||
@ -50,9 +50,7 @@ private func setupSharedLogger(rootPath: String, path: String) {
|
||||
}
|
||||
}
|
||||
|
||||
private let accountAuxiliaryMethods = AccountAuxiliaryMethods(updatePeerChatInputState: { interfaceState, inputState -> PeerChatInterfaceState? in
|
||||
return interfaceState
|
||||
}, fetchResource: { account, resource, ranges, _ in
|
||||
private let accountAuxiliaryMethods = AccountAuxiliaryMethods(fetchResource: { account, resource, ranges, _ in
|
||||
return nil
|
||||
}, fetchResourceMediaReferenceHash: { resource in
|
||||
return .single(nil)
|
||||
|
||||
@ -339,37 +339,6 @@ public enum ChatControllerPresentationMode: Equatable {
|
||||
case inline(NavigationController?)
|
||||
}
|
||||
|
||||
public final class ChatEmbeddedInterfaceState: PeerChatListEmbeddedInterfaceState {
|
||||
public let timestamp: Int32
|
||||
public let text: NSAttributedString
|
||||
|
||||
public init(timestamp: Int32, text: NSAttributedString) {
|
||||
self.timestamp = timestamp
|
||||
self.text = text
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
self.timestamp = (try? container.decode(Int32.self, forKey: "d")) ?? 0
|
||||
self.text = ((try? container.decode(ChatTextInputStateText.self, forKey: "at")) ?? ChatTextInputStateText()).attributedText()
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encode(self.timestamp, forKey: "d")
|
||||
try container.encode(ChatTextInputStateText(attributedText: self.text), forKey: "at")
|
||||
}
|
||||
|
||||
public func isEqual(to: PeerChatListEmbeddedInterfaceState) -> Bool {
|
||||
if let to = to as? ChatEmbeddedInterfaceState {
|
||||
return self.timestamp == to.timestamp && self.text.isEqual(to: to.text)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ChatPresentationInputQueryResult: Equatable {
|
||||
case stickers([FoundStickerItem])
|
||||
case hashtags([String])
|
||||
|
||||
@ -7,9 +7,6 @@ swift_library(
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
||||
@ -1,14 +1,4 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
|
||||
public enum ChatHistoryImportTasks {
|
||||
public final class Context {
|
||||
|
||||
}
|
||||
|
||||
public static func importState(peerId: PeerId) -> Signal<Float?, NoError> {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import Postbox
|
||||
import TelegramCore
|
||||
import TextFormat
|
||||
import AccountContext
|
||||
import SwiftSignalKit
|
||||
|
||||
public enum ChatTextInputMediaRecordingButtonMode: Int32 {
|
||||
case audio = 0
|
||||
@ -31,7 +32,6 @@ public struct ChatInterfaceSelectionState: Codable, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
@ -40,20 +40,6 @@ public struct ChatInterfaceSelectionState: Codable, Equatable {
|
||||
|
||||
try container.encode(buffer.makeData(), forKey: "i")
|
||||
}
|
||||
|
||||
/*public init(decoder: PostboxDecoder) {
|
||||
if let data = decoder.decodeBytesForKeyNoCopy("i") {
|
||||
self.selectedIds = Set(MessageId.decodeArrayFromBuffer(data))
|
||||
} else {
|
||||
self.selectedIds = Set()
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
let buffer = WriteBuffer()
|
||||
MessageId.encodeArrayToBuffer(Array(selectedIds), buffer: buffer)
|
||||
encoder.encodeBytes(buffer, forKey: "i")
|
||||
}*/
|
||||
}
|
||||
|
||||
public struct ChatEditMessageState: Codable, Equatable {
|
||||
@ -102,34 +88,6 @@ public struct ChatEditMessageState: Codable, Equatable {
|
||||
try container.encodeIfPresent(self.inputTextMaxLength, forKey: "tl")
|
||||
}
|
||||
|
||||
/*public init(decoder: PostboxDecoder) {
|
||||
self.messageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("mp", orElse: 0)), namespace: decoder.decodeInt32ForKey("mn", orElse: 0), id: decoder.decodeInt32ForKey("mi", orElse: 0))
|
||||
if let inputState = decoder.decodeObjectForKey("is", decoder: { return ChatTextInputState(decoder: $0) }) as? ChatTextInputState {
|
||||
self.inputState = inputState
|
||||
} else {
|
||||
self.inputState = ChatTextInputState()
|
||||
}
|
||||
self.disableUrlPreview = decoder.decodeOptionalStringForKey("dup")
|
||||
self.inputTextMaxLength = decoder.decodeOptionalInt32ForKey("tl")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeInt64(self.messageId.peerId.toInt64(), forKey: "mp")
|
||||
encoder.encodeInt32(self.messageId.namespace, forKey: "mn")
|
||||
encoder.encodeInt32(self.messageId.id, forKey: "mi")
|
||||
encoder.encodeObject(self.inputState, forKey: "is")
|
||||
if let disableUrlPreview = self.disableUrlPreview {
|
||||
encoder.encodeString(disableUrlPreview, forKey: "dup")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "dup")
|
||||
}
|
||||
if let inputTextMaxLength = self.inputTextMaxLength {
|
||||
encoder.encodeInt32(inputTextMaxLength, forKey: "ml")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "ml")
|
||||
}
|
||||
}*/
|
||||
|
||||
public static func ==(lhs: ChatEditMessageState, rhs: ChatEditMessageState) -> Bool {
|
||||
return lhs.messageId == rhs.messageId && lhs.inputState == rhs.inputState && lhs.disableUrlPreview == rhs.disableUrlPreview && lhs.inputTextMaxLength == rhs.inputTextMaxLength
|
||||
}
|
||||
@ -143,7 +101,7 @@ public struct ChatEditMessageState: Codable, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
||||
public struct ChatInterfaceMessageActionsState: Codable, Equatable {
|
||||
public var closedButtonKeyboardMessageId: MessageId?
|
||||
public var dismissedButtonKeyboardMessageId: MessageId?
|
||||
public var processedSetupReplyMessageId: MessageId?
|
||||
@ -173,86 +131,92 @@ public struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
||||
self.dismissedAddContactPhoneNumber = dismissedAddContactPhoneNumber
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
if let closedMessageIdPeerId = decoder.decodeOptionalInt64ForKey("cb.p"), let closedMessageIdNamespace = decoder.decodeOptionalInt32ForKey("cb.n"), let closedMessageIdId = decoder.decodeOptionalInt32ForKey("cb.i") {
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
if let closedMessageIdPeerId = try? container.decodeIfPresent(Int64.self, forKey: "cb.p"), let closedMessageIdNamespace = try? container.decodeIfPresent(Int32.self, forKey: "cb.n"), let closedMessageIdId = try? container.decodeIfPresent(Int32.self, forKey: "cb.i") {
|
||||
self.closedButtonKeyboardMessageId = MessageId(peerId: PeerId(closedMessageIdPeerId), namespace: closedMessageIdNamespace, id: closedMessageIdId)
|
||||
} else {
|
||||
self.closedButtonKeyboardMessageId = nil
|
||||
}
|
||||
|
||||
if let messageIdPeerId = decoder.decodeOptionalInt64ForKey("dismissedbuttons.p"), let messageIdNamespace = decoder.decodeOptionalInt32ForKey("dismissedbuttons.n"), let messageIdId = decoder.decodeOptionalInt32ForKey("dismissedbuttons.i") {
|
||||
if let messageIdPeerId = try? container.decodeIfPresent(Int64.self, forKey: "dismissedbuttons.p"), let messageIdNamespace = try? container.decodeIfPresent(Int32.self, forKey: "dismissedbuttons.n"), let messageIdId = try? container.decodeIfPresent(Int32.self, forKey: "dismissedbuttons.i") {
|
||||
self.dismissedButtonKeyboardMessageId = MessageId(peerId: PeerId(messageIdPeerId), namespace: messageIdNamespace, id: messageIdId)
|
||||
} else {
|
||||
self.dismissedButtonKeyboardMessageId = nil
|
||||
}
|
||||
|
||||
if let processedMessageIdPeerId = decoder.decodeOptionalInt64ForKey("pb.p"), let processedMessageIdNamespace = decoder.decodeOptionalInt32ForKey("pb.n"), let processedMessageIdId = decoder.decodeOptionalInt32ForKey("pb.i") {
|
||||
if let processedMessageIdPeerId = try? container.decodeIfPresent(Int64.self, forKey: "pb.p"), let processedMessageIdNamespace = try? container.decodeIfPresent(Int32.self, forKey: "pb.n"), let processedMessageIdId = try? container.decodeIfPresent(Int32.self, forKey: "pb.i") {
|
||||
self.processedSetupReplyMessageId = MessageId(peerId: PeerId(processedMessageIdPeerId), namespace: processedMessageIdNamespace, id: processedMessageIdId)
|
||||
} else {
|
||||
self.processedSetupReplyMessageId = nil
|
||||
}
|
||||
|
||||
if let closedPinnedMessageIdPeerId = decoder.decodeOptionalInt64ForKey("cp.p"), let closedPinnedMessageIdNamespace = decoder.decodeOptionalInt32ForKey("cp.n"), let closedPinnedMessageIdId = decoder.decodeOptionalInt32ForKey("cp.i") {
|
||||
if let closedPinnedMessageIdPeerId = try? container.decodeIfPresent(Int64.self, forKey: "cp.p"), let closedPinnedMessageIdNamespace = try? container.decodeIfPresent(Int32.self, forKey: "cp.n"), let closedPinnedMessageIdId = try? container.decodeIfPresent(Int32.self, forKey: "cp.i") {
|
||||
self.closedPinnedMessageId = MessageId(peerId: PeerId(closedPinnedMessageIdPeerId), namespace: closedPinnedMessageIdNamespace, id: closedPinnedMessageIdId)
|
||||
} else {
|
||||
self.closedPinnedMessageId = nil
|
||||
}
|
||||
|
||||
self.closedPeerSpecificPackSetup = decoder.decodeInt32ForKey("cpss", orElse: 0) != 0
|
||||
self.closedPeerSpecificPackSetup = ((try? container.decode(Int32.self, forKey: "cpss")) ?? 0) != 0
|
||||
|
||||
self.dismissedAddContactPhoneNumber = try? container.decodeIfPresent(String.self, forKey: "dismissedAddContactPhoneNumber")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
if let closedButtonKeyboardMessageId = self.closedButtonKeyboardMessageId {
|
||||
encoder.encodeInt64(closedButtonKeyboardMessageId.peerId.toInt64(), forKey: "cb.p")
|
||||
encoder.encodeInt32(closedButtonKeyboardMessageId.namespace, forKey: "cb.n")
|
||||
encoder.encodeInt32(closedButtonKeyboardMessageId.id, forKey: "cb.i")
|
||||
try container.encode(closedButtonKeyboardMessageId.peerId.toInt64(), forKey: "cb.p")
|
||||
try container.encode(closedButtonKeyboardMessageId.namespace, forKey: "cb.n")
|
||||
try container.encode(closedButtonKeyboardMessageId.id, forKey: "cb.i")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "cb.p")
|
||||
encoder.encodeNil(forKey: "cb.n")
|
||||
encoder.encodeNil(forKey: "cb.i")
|
||||
try container.encodeNil(forKey: "cb.p")
|
||||
try container.encodeNil(forKey: "cb.n")
|
||||
try container.encodeNil(forKey: "cb.i")
|
||||
}
|
||||
|
||||
if let dismissedButtonKeyboardMessageId = self.dismissedButtonKeyboardMessageId {
|
||||
encoder.encodeInt64(dismissedButtonKeyboardMessageId.peerId.toInt64(), forKey: "dismissedbuttons.p")
|
||||
encoder.encodeInt32(dismissedButtonKeyboardMessageId.namespace, forKey: "dismissedbuttons.n")
|
||||
encoder.encodeInt32(dismissedButtonKeyboardMessageId.id, forKey: "dismissedbuttons.i")
|
||||
try container.encode(dismissedButtonKeyboardMessageId.peerId.toInt64(), forKey: "dismissedbuttons.p")
|
||||
try container.encode(dismissedButtonKeyboardMessageId.namespace, forKey: "dismissedbuttons.n")
|
||||
try container.encode(dismissedButtonKeyboardMessageId.id, forKey: "dismissedbuttons.i")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "dismissedbuttons.p")
|
||||
encoder.encodeNil(forKey: "dismissedbuttons.n")
|
||||
encoder.encodeNil(forKey: "dismissedbuttons.i")
|
||||
try container.encodeNil(forKey: "dismissedbuttons.p")
|
||||
try container.encodeNil(forKey: "dismissedbuttons.n")
|
||||
try container.encodeNil(forKey: "dismissedbuttons.i")
|
||||
}
|
||||
|
||||
if let processedSetupReplyMessageId = self.processedSetupReplyMessageId {
|
||||
encoder.encodeInt64(processedSetupReplyMessageId.peerId.toInt64(), forKey: "pb.p")
|
||||
encoder.encodeInt32(processedSetupReplyMessageId.namespace, forKey: "pb.n")
|
||||
encoder.encodeInt32(processedSetupReplyMessageId.id, forKey: "pb.i")
|
||||
try container.encode(processedSetupReplyMessageId.peerId.toInt64(), forKey: "pb.p")
|
||||
try container.encode(processedSetupReplyMessageId.namespace, forKey: "pb.n")
|
||||
try container.encode(processedSetupReplyMessageId.id, forKey: "pb.i")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "pb.p")
|
||||
encoder.encodeNil(forKey: "pb.n")
|
||||
encoder.encodeNil(forKey: "pb.i")
|
||||
try container.encodeNil(forKey: "pb.p")
|
||||
try container.encodeNil(forKey: "pb.n")
|
||||
try container.encodeNil(forKey: "pb.i")
|
||||
}
|
||||
|
||||
if let closedPinnedMessageId = self.closedPinnedMessageId {
|
||||
encoder.encodeInt64(closedPinnedMessageId.peerId.toInt64(), forKey: "cp.p")
|
||||
encoder.encodeInt32(closedPinnedMessageId.namespace, forKey: "cp.n")
|
||||
encoder.encodeInt32(closedPinnedMessageId.id, forKey: "cp.i")
|
||||
try container.encode(closedPinnedMessageId.peerId.toInt64(), forKey: "cp.p")
|
||||
try container.encode(closedPinnedMessageId.namespace, forKey: "cp.n")
|
||||
try container.encode(closedPinnedMessageId.id, forKey: "cp.i")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "cp.p")
|
||||
encoder.encodeNil(forKey: "cp.n")
|
||||
encoder.encodeNil(forKey: "cp.i")
|
||||
try container.encodeNil(forKey: "cp.p")
|
||||
try container.encodeNil(forKey: "cp.n")
|
||||
try container.encodeNil(forKey: "cp.i")
|
||||
}
|
||||
|
||||
encoder.encodeInt32(self.closedPeerSpecificPackSetup ? 1 : 0, forKey: "cpss")
|
||||
try container.encode((self.closedPeerSpecificPackSetup ? 1 : 0) as Int32, forKey: "cpss")
|
||||
|
||||
if let dismissedAddContactPhoneNumber = self.dismissedAddContactPhoneNumber {
|
||||
encoder.encodeString(dismissedAddContactPhoneNumber, forKey: "dismissedAddContactPhoneNumber")
|
||||
try container.encode(dismissedAddContactPhoneNumber, forKey: "dismissedAddContactPhoneNumber")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "dismissedAddContactPhoneNumber")
|
||||
try container.encodeNil(forKey: "dismissedAddContactPhoneNumber")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatInterfaceHistoryScrollState: PostboxCoding, Equatable {
|
||||
public struct ChatInterfaceHistoryScrollState: Codable, Equatable {
|
||||
public let messageIndex: MessageIndex
|
||||
public let relativeOffset: Double
|
||||
|
||||
@ -261,17 +225,28 @@ public struct ChatInterfaceHistoryScrollState: PostboxCoding, Equatable {
|
||||
self.relativeOffset = relativeOffset
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.messageIndex = MessageIndex(id: MessageId(peerId: PeerId(decoder.decodeInt64ForKey("m.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("m.n", orElse: 0), id: decoder.decodeInt32ForKey("m.i", orElse: 0)), timestamp: decoder.decodeInt32ForKey("m.t", orElse: 0))
|
||||
self.relativeOffset = decoder.decodeDoubleForKey("ro", orElse: 0.0)
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
self.messageIndex = MessageIndex(
|
||||
id: MessageId(
|
||||
peerId: PeerId((try? container.decode(Int64.self, forKey: "m.p")) ?? 0),
|
||||
namespace: (try? container.decode(Int32.self, forKey: "m.n")) ?? 0,
|
||||
id: (try? container.decode(Int32.self, forKey: "m.i")) ?? 0
|
||||
),
|
||||
timestamp: (try? container.decode(Int32.self, forKey: "m.t")) ?? 0
|
||||
)
|
||||
self.relativeOffset = (try? container.decode(Double.self, forKey: "ro")) ?? 0.0
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeInt32(self.messageIndex.timestamp, forKey: "m.t")
|
||||
encoder.encodeInt64(self.messageIndex.id.peerId.toInt64(), forKey: "m.p")
|
||||
encoder.encodeInt32(self.messageIndex.id.namespace, forKey: "m.n")
|
||||
encoder.encodeInt32(self.messageIndex.id.id, forKey: "m.i")
|
||||
encoder.encodeDouble(self.relativeOffset, forKey: "ro")
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encode(self.messageIndex.timestamp, forKey: "m.t")
|
||||
try container.encode(self.messageIndex.id.peerId.toInt64(), forKey: "m.p")
|
||||
try container.encode(self.messageIndex.id.namespace, forKey: "m.n")
|
||||
try container.encode(self.messageIndex.id.id, forKey: "m.i")
|
||||
try container.encode(self.relativeOffset, forKey: "ro")
|
||||
}
|
||||
|
||||
public static func ==(lhs: ChatInterfaceHistoryScrollState, rhs: ChatInterfaceHistoryScrollState) -> Bool {
|
||||
@ -285,7 +260,7 @@ public struct ChatInterfaceHistoryScrollState: PostboxCoding, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equatable {
|
||||
public final class ChatInterfaceState: Codable, Equatable {
|
||||
public let timestamp: Int32
|
||||
public let composeInputState: ChatTextInputState
|
||||
public let composeDisableUrlPreview: String?
|
||||
@ -299,35 +274,15 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
||||
public let silentPosting: Bool
|
||||
public let inputLanguage: String?
|
||||
|
||||
public var associatedMessageIds: [MessageId] {
|
||||
var ids: [MessageId] = []
|
||||
if let editMessage = self.editMessage {
|
||||
ids.append(editMessage.messageId)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
public var chatListEmbeddedState: PeerChatListEmbeddedInterfaceState? {
|
||||
if self.composeInputState.inputText.length != 0 && self.timestamp != 0 {
|
||||
return ChatEmbeddedInterfaceState(timestamp: self.timestamp, text: self.composeInputState.inputText)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public var synchronizeableInputState: SynchronizeableChatInputState? {
|
||||
if self.composeInputState.inputText.length == 0 {
|
||||
return nil
|
||||
} else {
|
||||
return SynchronizeableChatInputState(replyToMessageId: self.replyMessageId, text: self.composeInputState.inputText.string, entities: generateChatInputTextEntities(self.composeInputState.inputText), timestamp: self.timestamp)
|
||||
return SynchronizeableChatInputState(replyToMessageId: self.replyMessageId, text: self.composeInputState.inputText.string, entities: generateChatInputTextEntities(self.composeInputState.inputText), timestamp: self.timestamp, textSelection: self.composeInputState.selectionRange)
|
||||
}
|
||||
}
|
||||
|
||||
public var historyScrollMessageIndex: MessageIndex? {
|
||||
return self.historyScrollState?.messageIndex
|
||||
}
|
||||
|
||||
public func withUpdatedSynchronizeableInputState(_ state: SynchronizeableChatInputState?) -> SynchronizeableChatInterfaceState {
|
||||
|
||||
public func withUpdatedSynchronizeableInputState(_ state: SynchronizeableChatInputState?) -> ChatInterfaceState {
|
||||
var result = self.withUpdatedComposeInputState(ChatTextInputState(inputText: chatInputStateStringWithAppliedEntities(state?.text ?? "", entities: state?.entities ?? []))).withUpdatedReplyMessageId(state?.replyToMessageId)
|
||||
if let timestamp = state?.timestamp {
|
||||
result = result.withUpdatedTimestamp(timestamp)
|
||||
@ -335,6 +290,10 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
||||
return result
|
||||
}
|
||||
|
||||
public var historyScrollMessageIndex: MessageIndex? {
|
||||
return self.historyScrollState?.messageIndex
|
||||
}
|
||||
|
||||
public var effectiveInputState: ChatTextInputState {
|
||||
if let editMessage = self.editMessage {
|
||||
return editMessage.inputState
|
||||
@ -373,114 +332,110 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
||||
self.inputLanguage = inputLanguage
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.timestamp = decoder.decodeInt32ForKey("ts", orElse: 0)
|
||||
if let inputState = decoder.decode(ChatTextInputState.self, forKey: "is") {
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
self.timestamp = (try? container.decode(Int32.self, forKey: "ts")) ?? 0
|
||||
if let inputState = try? container.decode(ChatTextInputState.self, forKey: "is") {
|
||||
self.composeInputState = inputState
|
||||
} else {
|
||||
self.composeInputState = ChatTextInputState()
|
||||
}
|
||||
if let composeDisableUrlPreview = decoder.decodeOptionalStringForKey("dup") {
|
||||
if let composeDisableUrlPreview = try? container.decodeIfPresent(String.self, forKey: "dup") {
|
||||
self.composeDisableUrlPreview = composeDisableUrlPreview
|
||||
} else {
|
||||
self.composeDisableUrlPreview = nil
|
||||
}
|
||||
let replyMessageIdPeerId: Int64? = decoder.decodeOptionalInt64ForKey("r.p")
|
||||
let replyMessageIdNamespace: Int32? = decoder.decodeOptionalInt32ForKey("r.n")
|
||||
let replyMessageIdId: Int32? = decoder.decodeOptionalInt32ForKey("r.i")
|
||||
let replyMessageIdPeerId: Int64? = try? container.decodeIfPresent(Int64.self, forKey: "r.p")
|
||||
let replyMessageIdNamespace: Int32? = try? container.decodeIfPresent(Int32.self, forKey: "r.n")
|
||||
let replyMessageIdId: Int32? = try? container.decodeIfPresent(Int32.self, forKey: "r.i")
|
||||
if let replyMessageIdPeerId = replyMessageIdPeerId, let replyMessageIdNamespace = replyMessageIdNamespace, let replyMessageIdId = replyMessageIdId {
|
||||
self.replyMessageId = MessageId(peerId: PeerId(replyMessageIdPeerId), namespace: replyMessageIdNamespace, id: replyMessageIdId)
|
||||
} else {
|
||||
self.replyMessageId = nil
|
||||
}
|
||||
if let forwardMessageIdsData = decoder.decodeBytesForKeyNoCopy("fm") {
|
||||
self.forwardMessageIds = MessageId.decodeArrayFromBuffer(forwardMessageIdsData)
|
||||
if let forwardMessageIdsData = try? container.decodeIfPresent(Data.self, forKey: "fm") {
|
||||
self.forwardMessageIds = MessageId.decodeArrayFromBuffer(ReadBuffer(data: forwardMessageIdsData))
|
||||
} else {
|
||||
self.forwardMessageIds = nil
|
||||
}
|
||||
if let editMessage = decoder.decode(ChatEditMessageState.self, forKey: "em") {
|
||||
if let editMessage = try? container.decodeIfPresent(ChatEditMessageState.self, forKey: "em") {
|
||||
self.editMessage = editMessage
|
||||
} else {
|
||||
self.editMessage = nil
|
||||
}
|
||||
if let selectionState = decoder.decode(ChatInterfaceSelectionState.self, forKey: "ss") {
|
||||
if let selectionState = try? container.decodeIfPresent(ChatInterfaceSelectionState.self, forKey: "ss") {
|
||||
self.selectionState = selectionState
|
||||
} else {
|
||||
self.selectionState = nil
|
||||
}
|
||||
|
||||
if let messageActionsState = decoder.decodeObjectForKey("as", decoder: { ChatInterfaceMessageActionsState(decoder: $0) }) as? ChatInterfaceMessageActionsState {
|
||||
|
||||
if let messageActionsState = try? container.decodeIfPresent(ChatInterfaceMessageActionsState.self, forKey: "as") {
|
||||
self.messageActionsState = messageActionsState
|
||||
} else {
|
||||
self.messageActionsState = ChatInterfaceMessageActionsState()
|
||||
}
|
||||
|
||||
self.historyScrollState = try? container.decodeIfPresent(ChatInterfaceHistoryScrollState.self, forKey: "hss")
|
||||
|
||||
self.historyScrollState = decoder.decodeObjectForKey("hss", decoder: { ChatInterfaceHistoryScrollState(decoder: $0) }) as? ChatInterfaceHistoryScrollState
|
||||
self.mediaRecordingMode = ChatTextInputMediaRecordingButtonMode(rawValue: (try? container.decodeIfPresent(Int32.self, forKey: "mrm")) ?? 0) ?? .audio
|
||||
|
||||
self.mediaRecordingMode = ChatTextInputMediaRecordingButtonMode(rawValue: decoder.decodeInt32ForKey("mrm", orElse: 0))!
|
||||
|
||||
self.silentPosting = decoder.decodeInt32ForKey("sip", orElse: 0) != 0
|
||||
self.inputLanguage = decoder.decodeOptionalStringForKey("inputLanguage")
|
||||
self.silentPosting = ((try? container.decode(Int32.self, forKey: "sip")) ?? 0) != 0
|
||||
self.inputLanguage = try? container.decodeIfPresent(String.self, forKey: "inputLanguage")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeInt32(self.timestamp, forKey: "ts")
|
||||
encoder.encode(self.composeInputState, forKey: "is")
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encode(self.timestamp, forKey: "ts")
|
||||
try container.encode(self.composeInputState, forKey: "is")
|
||||
if let composeDisableUrlPreview = self.composeDisableUrlPreview {
|
||||
encoder.encodeString(composeDisableUrlPreview, forKey: "dup")
|
||||
try container.encode(composeDisableUrlPreview, forKey: "dup")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "dup")
|
||||
try container.encodeNil(forKey: "dup")
|
||||
}
|
||||
if let replyMessageId = self.replyMessageId {
|
||||
encoder.encodeInt64(replyMessageId.peerId.toInt64(), forKey: "r.p")
|
||||
encoder.encodeInt32(replyMessageId.namespace, forKey: "r.n")
|
||||
encoder.encodeInt32(replyMessageId.id, forKey: "r.i")
|
||||
try container.encode(replyMessageId.peerId.toInt64(), forKey: "r.p")
|
||||
try container.encode(replyMessageId.namespace, forKey: "r.n")
|
||||
try container.encode(replyMessageId.id, forKey: "r.i")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "r.p")
|
||||
encoder.encodeNil(forKey: "r.n")
|
||||
encoder.encodeNil(forKey: "r.i")
|
||||
try container.encodeNil(forKey: "r.p")
|
||||
try container.encodeNil(forKey: "r.n")
|
||||
try container.encodeNil(forKey: "r.i")
|
||||
}
|
||||
if let forwardMessageIds = self.forwardMessageIds {
|
||||
let buffer = WriteBuffer()
|
||||
MessageId.encodeArrayToBuffer(forwardMessageIds, buffer: buffer)
|
||||
encoder.encodeBytes(buffer, forKey: "fm")
|
||||
try container.encode(buffer.makeData(), forKey: "fm")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "fm")
|
||||
try container.encodeNil(forKey: "fm")
|
||||
}
|
||||
if let editMessage = self.editMessage {
|
||||
encoder.encode(editMessage, forKey: "em")
|
||||
try container.encode(editMessage, forKey: "em")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "em")
|
||||
try container.encodeNil(forKey: "em")
|
||||
}
|
||||
if let selectionState = self.selectionState {
|
||||
encoder.encode(selectionState, forKey: "ss")
|
||||
try container.encode(selectionState, forKey: "ss")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "ss")
|
||||
try container.encodeNil(forKey: "ss")
|
||||
}
|
||||
if self.messageActionsState.isEmpty {
|
||||
encoder.encodeNil(forKey: "as")
|
||||
try container.encodeNil(forKey: "as")
|
||||
} else {
|
||||
encoder.encodeObject(self.messageActionsState, forKey: "as")
|
||||
try container.encode(self.messageActionsState, forKey: "as")
|
||||
}
|
||||
if let historyScrollState = self.historyScrollState {
|
||||
encoder.encodeObject(historyScrollState, forKey: "hss")
|
||||
try container.encode(historyScrollState, forKey: "hss")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "hss")
|
||||
try container.encodeNil(forKey: "hss")
|
||||
}
|
||||
encoder.encodeInt32(self.mediaRecordingMode.rawValue, forKey: "mrm")
|
||||
encoder.encodeInt32(self.silentPosting ? 1 : 0, forKey: "sip")
|
||||
try container.encode(self.mediaRecordingMode.rawValue, forKey: "mrm")
|
||||
try container.encode((self.silentPosting ? 1 : 0) as Int32, forKey: "sip")
|
||||
if let inputLanguage = self.inputLanguage {
|
||||
encoder.encodeString(inputLanguage, forKey: "inputLanguage")
|
||||
try container.encode(inputLanguage, forKey: "inputLanguage")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "inputLanguage")
|
||||
}
|
||||
}
|
||||
|
||||
public func isEqual(to: PeerChatInterfaceState) -> Bool {
|
||||
if let to = to as? ChatInterfaceState, self == to {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
try container.encodeNil(forKey: "inputLanguage")
|
||||
}
|
||||
}
|
||||
|
||||
@ -600,4 +555,34 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
||||
public func withUpdatedInputLanguage(_ inputLanguage: String?) -> ChatInterfaceState {
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: inputLanguage)
|
||||
}
|
||||
|
||||
public static func parse(_ state: OpaqueChatInterfaceState) -> ChatInterfaceState {
|
||||
guard let opaqueData = state.opaqueData else {
|
||||
return ChatInterfaceState().withUpdatedSynchronizeableInputState(state.synchronizeableInputState)
|
||||
}
|
||||
guard var decodedState = try? AdaptedPostboxDecoder().decode(ChatInterfaceState.self, from: opaqueData) else {
|
||||
return ChatInterfaceState().withUpdatedSynchronizeableInputState(state.synchronizeableInputState)
|
||||
}
|
||||
decodedState = decodedState.withUpdatedSynchronizeableInputState(state.synchronizeableInputState)
|
||||
return decodedState
|
||||
}
|
||||
|
||||
public static func update(engine: TelegramEngine, peerId: PeerId, threadId: Int64?, _ f: @escaping (ChatInterfaceState) -> ChatInterfaceState) -> Signal<Never, NoError> {
|
||||
return engine.peers.getOpaqueChatInterfaceState(peerId: peerId, threadId: threadId)
|
||||
|> mapToSignal { previousOpaqueState -> Signal<Never, NoError> in
|
||||
let previousState = previousOpaqueState.flatMap(ChatInterfaceState.parse)
|
||||
let updatedState = f(previousState ?? ChatInterfaceState())
|
||||
|
||||
let updatedOpaqueData = try? AdaptedPostboxEncoder().encode(updatedState)
|
||||
|
||||
return engine.peers.setOpaqueChatInterfaceState(
|
||||
peerId: peerId,
|
||||
threadId: threadId,
|
||||
state: OpaqueChatInterfaceState(
|
||||
opaqueData: updatedOpaqueData,
|
||||
historyScrollMessageIndex: updatedState.historyScrollMessageIndex,
|
||||
synchronizeableInputState: updatedState.synchronizeableInputState
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1031,15 +1031,10 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
}
|
||||
} else {
|
||||
let _ = (strongSelf.context.account.postbox.transaction({ transaction -> Void in
|
||||
transaction.updatePeerChatInterfaceState(peerId, update: { currentState in
|
||||
if let currentState = currentState as? ChatInterfaceState {
|
||||
return currentState.withUpdatedForwardMessageIds(Array(messageIds))
|
||||
} else {
|
||||
return ChatInterfaceState().withUpdatedForwardMessageIds(Array(messageIds))
|
||||
}
|
||||
})
|
||||
}) |> deliverOnMainQueue).start(completed: {
|
||||
let _ = (ChatInterfaceState.update(engine: strongSelf.context.engine, peerId: peerId, threadId: nil, { currentState in
|
||||
return currentState.withUpdatedForwardMessageIds(Array(messageIds))
|
||||
})
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
if let strongSelf = self {
|
||||
let controller = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peerId), subject: nil, botStart: nil, mode: .standard(previewing: false))
|
||||
controller.purposefulAction = { [weak self] in
|
||||
|
||||
@ -17,9 +17,10 @@ import PeerPresenceStatusManager
|
||||
import PhotoResources
|
||||
import ChatListSearchItemNode
|
||||
import ContextUI
|
||||
import ChatInterfaceState
|
||||
|
||||
public enum ChatListItemContent {
|
||||
case peer(messages: [Message], peer: RenderedPeer, combinedReadState: CombinedPeerReadState?, isRemovedFromTotalUnreadCount: Bool, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, embeddedState: PeerChatListEmbeddedInterfaceState?, inputActivities: [(Peer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, ignoreUnreadBadge: Bool, displayAsMessage: Bool, hasFailedMessages: Bool)
|
||||
case peer(messages: [Message], peer: RenderedPeer, combinedReadState: CombinedPeerReadState?, isRemovedFromTotalUnreadCount: Bool, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, embeddedState: StoredPeerChatInterfaceState?, inputActivities: [(Peer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, ignoreUnreadBadge: Bool, displayAsMessage: Bool, hasFailedMessages: Bool)
|
||||
case groupReference(groupId: PeerGroupId, peers: [ChatListGroupReferencePeer], message: Message?, unreadState: PeerGroupUnreadCountersCombinedSummary, hiddenByDefault: Bool)
|
||||
|
||||
public var chatLocation: ChatLocation? {
|
||||
@ -813,7 +814,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
let unreadCount: (count: Int32, unread: Bool, muted: Bool, mutedCount: Int32?)
|
||||
let isRemovedFromTotalUnreadCount: Bool
|
||||
let peerPresence: PeerPresence?
|
||||
let embeddedState: PeerChatListEmbeddedInterfaceState?
|
||||
let embeddedState: StoredPeerChatInterfaceState?
|
||||
let summaryInfo: ChatListMessageTagSummaryInfo
|
||||
let inputActivities: [(Peer, PeerInputActivity)]?
|
||||
let isPeerGroup: Bool
|
||||
@ -1021,11 +1022,15 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
chatListText = (text, messageText)
|
||||
}
|
||||
|
||||
if inlineAuthorPrefix == nil, let embeddedState = embeddedState as? ChatEmbeddedInterfaceState {
|
||||
if inlineAuthorPrefix == nil, let embeddedState = embeddedState, embeddedState.overrideChatTimestamp != nil, let opaqueState = _internal_decodeStoredChatInterfaceState(state: embeddedState) {
|
||||
let interfaceState = ChatInterfaceState.parse(opaqueState)
|
||||
|
||||
hasDraft = true
|
||||
authorAttributedString = NSAttributedString(string: item.presentationData.strings.DialogList_Draft, font: textFont, textColor: theme.messageDraftTextColor)
|
||||
|
||||
let draftText: String = interfaceState.composeInputState.inputText.string
|
||||
|
||||
attributedText = NSAttributedString(string: foldLineBreaks(embeddedState.text.string.replacingOccurrences(of: "\n\n", with: " ")), font: textFont, textColor: theme.messageTextColor)
|
||||
attributedText = NSAttributedString(string: foldLineBreaks(draftText.replacingOccurrences(of: "\n\n", with: " ")), font: textFont, textColor: theme.messageTextColor)
|
||||
} else if let message = messages.last {
|
||||
var composedString: NSMutableAttributedString
|
||||
if let inlineAuthorPrefix = inlineAuthorPrefix {
|
||||
|
||||
@ -46,7 +46,7 @@ public enum ChatListNodeEntryPromoInfo: Equatable {
|
||||
|
||||
enum ChatListNodeEntry: Comparable, Identifiable {
|
||||
case HeaderEntry
|
||||
case PeerEntry(index: ChatListIndex, presentationData: ChatListPresentationData, messages: [Message], readState: CombinedPeerReadState?, isRemovedFromTotalUnreadCount: Bool, embeddedInterfaceState: PeerChatListEmbeddedInterfaceState?, peer: RenderedPeer, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, inputActivities: [(Peer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, hasFailedMessages: Bool, isContact: Bool)
|
||||
case PeerEntry(index: ChatListIndex, presentationData: ChatListPresentationData, messages: [Message], readState: CombinedPeerReadState?, isRemovedFromTotalUnreadCount: Bool, embeddedInterfaceState: StoredPeerChatInterfaceState?, peer: RenderedPeer, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, inputActivities: [(Peer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, hasFailedMessages: Bool, isContact: Bool)
|
||||
case HoleEntry(ChatListHole, theme: PresentationTheme)
|
||||
case GroupReferenceEntry(index: ChatListIndex, presentationData: ChatListPresentationData, groupId: PeerGroupId, peers: [ChatListGroupReferencePeer], message: Message?, editing: Bool, unreadState: PeerGroupUnreadCountersCombinedSummary, revealed: Bool, hiddenByDefault: Bool)
|
||||
case ArchiveIntro(presentationData: ChatListPresentationData)
|
||||
@ -144,7 +144,7 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
||||
return false
|
||||
}
|
||||
if let lhsEmbeddedState = lhsEmbeddedState, let rhsEmbeddedState = rhsEmbeddedState {
|
||||
if !lhsEmbeddedState.isEqual(to: rhsEmbeddedState) {
|
||||
if lhsEmbeddedState != rhsEmbeddedState {
|
||||
return false
|
||||
}
|
||||
} else if (lhsEmbeddedState != nil) != (rhsEmbeddedState != nil) {
|
||||
|
||||
@ -110,7 +110,7 @@ private func addOperation(_ operation: ChatListOperation, groupId: PeerGroupId,
|
||||
}
|
||||
|
||||
public enum ChatListNamespaceEntry {
|
||||
case peer(index: ChatListIndex, readState: PeerReadState?, topMessageAttributes: [MessageAttribute], tagSummary: MessageHistoryTagNamespaceSummary?, interfaceState: PeerChatInterfaceState?)
|
||||
case peer(index: ChatListIndex, readState: PeerReadState?, topMessageAttributes: [MessageAttribute], tagSummary: MessageHistoryTagNamespaceSummary?, interfaceState: StoredPeerChatInterfaceState?)
|
||||
case hole(MessageIndex)
|
||||
|
||||
public var index: ChatListIndex {
|
||||
@ -294,12 +294,12 @@ final class ChatListTable: Table {
|
||||
return result
|
||||
}
|
||||
|
||||
func replay(historyOperationsByPeerId: [PeerId: [MessageHistoryOperation]], updatedPeerChatListEmbeddedStates: [PeerId: PeerChatListEmbeddedInterfaceState?], updatedChatListInclusions: [PeerId: PeerChatListInclusion], messageHistoryTable: MessageHistoryTable, peerChatInterfaceStateTable: PeerChatInterfaceStateTable, operations: inout [PeerGroupId: [ChatListOperation]]) {
|
||||
func replay(historyOperationsByPeerId: [PeerId: [MessageHistoryOperation]], updatedPeerChatListEmbeddedStates: Set<PeerId>, updatedChatListInclusions: [PeerId: PeerChatListInclusion], messageHistoryTable: MessageHistoryTable, peerChatInterfaceStateTable: PeerChatInterfaceStateTable, operations: inout [PeerGroupId: [ChatListOperation]]) {
|
||||
var changedPeerIds = Set<PeerId>()
|
||||
for peerId in historyOperationsByPeerId.keys {
|
||||
changedPeerIds.insert(peerId)
|
||||
}
|
||||
for peerId in updatedPeerChatListEmbeddedStates.keys {
|
||||
for peerId in updatedPeerChatListEmbeddedStates {
|
||||
changedPeerIds.insert(peerId)
|
||||
}
|
||||
for peerId in updatedChatListInclusions.keys {
|
||||
@ -315,19 +315,19 @@ final class ChatListTable: Table {
|
||||
}
|
||||
|
||||
let topMessage = messageHistoryTable.topIndex(peerId: peerId)
|
||||
let embeddedChatState = peerChatInterfaceStateTable.get(peerId)?.chatListEmbeddedState
|
||||
let embeddedChatStateOverrideTimestamp = peerChatInterfaceStateTable.get(peerId)?.overrideChatTimestamp
|
||||
|
||||
let rawTopMessageIndex: MessageIndex?
|
||||
let topMessageIndex: MessageIndex?
|
||||
if let topMessage = topMessage {
|
||||
var updatedTimestamp = topMessage.timestamp
|
||||
rawTopMessageIndex = MessageIndex(id: topMessage.id, timestamp: topMessage.timestamp)
|
||||
if let embeddedChatState = embeddedChatState {
|
||||
updatedTimestamp = max(updatedTimestamp, embeddedChatState.timestamp)
|
||||
if let embeddedChatStateOverrideTimestamp = embeddedChatStateOverrideTimestamp {
|
||||
updatedTimestamp = max(updatedTimestamp, embeddedChatStateOverrideTimestamp)
|
||||
}
|
||||
topMessageIndex = MessageIndex(id: topMessage.id, timestamp: updatedTimestamp)
|
||||
} else if let embeddedChatState = embeddedChatState, embeddedChatState.timestamp != 0 {
|
||||
topMessageIndex = MessageIndex(id: MessageId(peerId: peerId, namespace: 0, id: 1), timestamp: embeddedChatState.timestamp)
|
||||
} else if let embeddedChatStateOverrideTimestamp = embeddedChatStateOverrideTimestamp, embeddedChatStateOverrideTimestamp != 0 {
|
||||
topMessageIndex = MessageIndex(id: MessageId(peerId: peerId, namespace: 0, id: 1), timestamp: embeddedChatStateOverrideTimestamp)
|
||||
rawTopMessageIndex = nil
|
||||
} else {
|
||||
topMessageIndex = nil
|
||||
|
||||
@ -88,7 +88,7 @@ public struct ChatListGroupReferenceEntry: Equatable {
|
||||
}
|
||||
|
||||
public enum ChatListEntry: Comparable {
|
||||
case MessageEntry(index: ChatListIndex, messages: [Message], readState: CombinedPeerReadState?, isRemovedFromTotalUnreadCount: Bool, embeddedInterfaceState: PeerChatListEmbeddedInterfaceState?, renderedPeer: RenderedPeer, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, hasFailed: Bool, isContact: Bool)
|
||||
case MessageEntry(index: ChatListIndex, messages: [Message], readState: CombinedPeerReadState?, isRemovedFromTotalUnreadCount: Bool, embeddedInterfaceState: StoredPeerChatInterfaceState?, renderedPeer: RenderedPeer, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, hasFailed: Bool, isContact: Bool)
|
||||
case HoleEntry(ChatListHole)
|
||||
|
||||
public var index: ChatListIndex {
|
||||
@ -123,7 +123,7 @@ public enum ChatListEntry: Comparable {
|
||||
return false
|
||||
}
|
||||
if let lhsEmbeddedState = lhsEmbeddedState, let rhsEmbeddedState = rhsEmbeddedState {
|
||||
if !lhsEmbeddedState.isEqual(to: rhsEmbeddedState) {
|
||||
if lhsEmbeddedState != rhsEmbeddedState {
|
||||
return false
|
||||
}
|
||||
} else if (lhsEmbeddedState != nil) != (rhsEmbeddedState != nil) {
|
||||
@ -185,7 +185,7 @@ public enum ChatListEntry: Comparable {
|
||||
|
||||
enum MutableChatListEntry: Equatable {
|
||||
case IntermediateMessageEntry(index: ChatListIndex, messageIndex: MessageIndex?)
|
||||
case MessageEntry(index: ChatListIndex, messages: [Message], readState: CombinedPeerReadState?, notificationSettings: PeerNotificationSettings?, isRemovedFromTotalUnreadCount: Bool, embeddedInterfaceState: PeerChatListEmbeddedInterfaceState?, renderedPeer: RenderedPeer, presence: PeerPresence?, tagSummaryInfo: ChatListMessageTagSummaryInfo, hasFailedMessages: Bool, isContact: Bool)
|
||||
case MessageEntry(index: ChatListIndex, messages: [Message], readState: CombinedPeerReadState?, notificationSettings: PeerNotificationSettings?, isRemovedFromTotalUnreadCount: Bool, embeddedInterfaceState: StoredPeerChatInterfaceState?, renderedPeer: RenderedPeer, presence: PeerPresence?, tagSummaryInfo: ChatListMessageTagSummaryInfo, hasFailedMessages: Bool, isContact: Bool)
|
||||
case HoleEntry(ChatListHole)
|
||||
|
||||
init(_ intermediateEntry: ChatListIntermediateEntry, cachedDataTable: CachedPeerDataTable, readStateTable: MessageHistoryReadStateTable, messageHistoryTable: MessageHistoryTable) {
|
||||
@ -591,7 +591,7 @@ final class MutableChatListView {
|
||||
let tagSummaryCount: Int32? = nil
|
||||
let actionsSummaryCount: Int32? = nil
|
||||
|
||||
return .MessageEntry(index: index, messages: renderedMessages, readState: postbox.readStateTable.getCombinedState(index.messageIndex.id.peerId), notificationSettings: notificationSettings, isRemovedFromTotalUnreadCount: false, embeddedInterfaceState: postbox.peerChatInterfaceStateTable.get(index.messageIndex.id.peerId)?.chatListEmbeddedState, renderedPeer: RenderedPeer(peerId: index.messageIndex.id.peerId, peers: peers), presence: presence, tagSummaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: tagSummaryCount, actionsSummaryCount: actionsSummaryCount), hasFailedMessages: postbox.messageHistoryFailedTable.contains(peerId: index.messageIndex.id.peerId), isContact: isContact)
|
||||
return .MessageEntry(index: index, messages: renderedMessages, readState: postbox.readStateTable.getCombinedState(index.messageIndex.id.peerId), notificationSettings: notificationSettings, isRemovedFromTotalUnreadCount: false, embeddedInterfaceState: postbox.peerChatInterfaceStateTable.get(index.messageIndex.id.peerId), renderedPeer: RenderedPeer(peerId: index.messageIndex.id.peerId, peers: peers), presence: presence, tagSummaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: tagSummaryCount, actionsSummaryCount: actionsSummaryCount), hasFailedMessages: postbox.messageHistoryFailedTable.contains(peerId: index.messageIndex.id.peerId), isContact: isContact)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1394,7 +1394,7 @@ struct ChatListViewState {
|
||||
}
|
||||
}
|
||||
|
||||
let updatedEntry: MutableChatListEntry = .MessageEntry(index: index, messages: renderedMessages, readState: postbox.readStateTable.getCombinedState(index.messageIndex.id.peerId), notificationSettings: notificationSettings, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, embeddedInterfaceState: postbox.peerChatInterfaceStateTable.get(index.messageIndex.id.peerId)?.chatListEmbeddedState, renderedPeer: renderedPeer, presence: presence, tagSummaryInfo: tagSummaryInfo, hasFailedMessages: false, isContact: postbox.contactsTable.isContact(peerId: index.messageIndex.id.peerId))
|
||||
let updatedEntry: MutableChatListEntry = .MessageEntry(index: index, messages: renderedMessages, readState: postbox.readStateTable.getCombinedState(index.messageIndex.id.peerId), notificationSettings: notificationSettings, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, embeddedInterfaceState: postbox.peerChatInterfaceStateTable.get(index.messageIndex.id.peerId), renderedPeer: renderedPeer, presence: presence, tagSummaryInfo: tagSummaryInfo, hasFailedMessages: false, isContact: postbox.contactsTable.isContact(peerId: index.messageIndex.id.peerId))
|
||||
if directionIndex == 0 {
|
||||
self.stateBySpace[space]!.orderedEntries.setLowerOrAtAnchorAtArrayIndex(listIndex, to: updatedEntry)
|
||||
} else {
|
||||
|
||||
@ -589,7 +589,7 @@ public final class PostboxEncoder {
|
||||
let innerEncoder = _AdaptedPostboxEncoder(typeHash: typeHash)
|
||||
try! value.encode(to: innerEncoder)
|
||||
|
||||
let (data, valueType) = innerEncoder.makeData()
|
||||
let (data, valueType) = innerEncoder.makeData(addHeader: true)
|
||||
self.encodeInnerObjectData(data, valueType: valueType, forKey: key)
|
||||
}
|
||||
|
||||
@ -1612,6 +1612,29 @@ public final class PostboxDecoder {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
static func parseDataRaw(data: Data) -> Data? {
|
||||
return data.withUnsafeBytes { bytes -> Data? in
|
||||
guard let baseAddress = bytes.baseAddress else {
|
||||
return nil
|
||||
}
|
||||
if bytes.count < 4 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var length: Int32 = 0
|
||||
memcpy(&length, baseAddress, 4)
|
||||
|
||||
if length < 0 || length != (bytes.count - 4) {
|
||||
return nil
|
||||
}
|
||||
if length == 0 {
|
||||
return Data()
|
||||
}
|
||||
|
||||
return Data(bytes: baseAddress.advanced(by: 4), count: Int(length))
|
||||
}
|
||||
}
|
||||
|
||||
public func decodeDataForKey(_ key: String) -> Data? {
|
||||
if PostboxDecoder.positionOnKey(self.buffer.memory, offset: &self.offset, maxOffset: self.buffer.length, length: self.buffer.length, key: key, valueType: .Bytes) {
|
||||
|
||||
@ -2,6 +2,6 @@ import Foundation
|
||||
|
||||
public struct InitialMessageHistoryData {
|
||||
public let peer: Peer?
|
||||
public let chatInterfaceState: PeerChatInterfaceState?
|
||||
public let storedInterfaceState: StoredPeerChatInterfaceState?
|
||||
public let associatedMessages: [MessageId: Message]
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
|
||||
public struct MessageId: Hashable, Comparable, CustomStringConvertible, PostboxCoding {
|
||||
public struct MessageId: Hashable, Comparable, CustomStringConvertible, PostboxCoding, Codable {
|
||||
public typealias Namespace = Int32
|
||||
public typealias Id = Int32
|
||||
|
||||
@ -94,7 +94,7 @@ public struct MessageId: Hashable, Comparable, CustomStringConvertible, PostboxC
|
||||
}
|
||||
}
|
||||
|
||||
public struct MessageIndex: Comparable, Hashable {
|
||||
public struct MessageIndex: Codable, Comparable, Hashable {
|
||||
public let id: MessageId
|
||||
public let timestamp: Int32
|
||||
|
||||
@ -514,7 +514,7 @@ public struct MessageForwardInfo: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public protocol MessageAttribute: class, PostboxCoding {
|
||||
public protocol MessageAttribute: AnyObject, PostboxCoding {
|
||||
var associatedPeerIds: [PeerId] { get }
|
||||
var associatedMessageIds: [MessageId] { get }
|
||||
var automaticTimestampBasedAttribute: (UInt16, Int32)? { get }
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
import Foundation
|
||||
|
||||
public struct PeerId: Hashable, CustomStringConvertible, Comparable, Codable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case internalValue = "iv"
|
||||
}
|
||||
|
||||
public struct Namespace: Comparable, Hashable, Codable, CustomStringConvertible {
|
||||
public static var max: Namespace {
|
||||
return Namespace(rawValue: 0x7)
|
||||
@ -156,6 +160,17 @@ public struct PeerId: Hashable, CustomStringConvertible, Comparable, Codable {
|
||||
self.id = Id(rawValue: Int32(bitPattern: UInt32(clamping: idLowBits)))
|
||||
}
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let value = try container.decode(Int64.self, forKey: .internalValue)
|
||||
self.init(value)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(self.toInt64(), forKey: .internalValue)
|
||||
}
|
||||
|
||||
public func toInt64() -> Int64 {
|
||||
let idLowBits = UInt32(bitPattern: self.id.rawValue)
|
||||
|
||||
@ -1,14 +1,75 @@
|
||||
import Foundation
|
||||
|
||||
public protocol PeerChatListEmbeddedInterfaceState: Codable {
|
||||
/*public protocol PeerChatListEmbeddedInterfaceState: Codable {
|
||||
var timestamp: Int32 { get }
|
||||
|
||||
func isEqual(to: PeerChatListEmbeddedInterfaceState) -> Bool
|
||||
}*/
|
||||
|
||||
public final class StoredPeerChatInterfaceState: Codable, Equatable {
|
||||
private enum CodingKeys: CodingKey {
|
||||
case overrideChatTimestamp
|
||||
case historyScrollMessageIndex
|
||||
case associatedMessageIds
|
||||
case data
|
||||
}
|
||||
|
||||
public let overrideChatTimestamp: Int32?
|
||||
public let historyScrollMessageIndex: MessageIndex?
|
||||
public let associatedMessageIds: [MessageId]
|
||||
public let data: Data?
|
||||
|
||||
public init(
|
||||
overrideChatTimestamp: Int32?,
|
||||
historyScrollMessageIndex: MessageIndex?,
|
||||
associatedMessageIds: [MessageId],
|
||||
data: Data?
|
||||
) {
|
||||
self.overrideChatTimestamp = overrideChatTimestamp
|
||||
self.historyScrollMessageIndex = historyScrollMessageIndex
|
||||
self.associatedMessageIds = associatedMessageIds
|
||||
self.data = data
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
self.overrideChatTimestamp = try? container.decodeIfPresent(Int32.self, forKey: .overrideChatTimestamp)
|
||||
self.historyScrollMessageIndex = try? container.decodeIfPresent(MessageIndex.self, forKey: .historyScrollMessageIndex)
|
||||
self.associatedMessageIds = try container.decode([MessageId].self, forKey: .associatedMessageIds)
|
||||
self.data = try? container.decodeIfPresent(Data.self, forKey: .data)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encodeIfPresent(self.overrideChatTimestamp, forKey: .overrideChatTimestamp)
|
||||
try container.encodeIfPresent(self.historyScrollMessageIndex, forKey: .historyScrollMessageIndex)
|
||||
try container.encodeIfPresent(self.associatedMessageIds, forKey: .associatedMessageIds)
|
||||
try container.encodeIfPresent(self.data, forKey: .data)
|
||||
}
|
||||
|
||||
public static func ==(lhs: StoredPeerChatInterfaceState, rhs: StoredPeerChatInterfaceState) -> Bool {
|
||||
if lhs.overrideChatTimestamp != rhs.overrideChatTimestamp {
|
||||
return false
|
||||
}
|
||||
if lhs.historyScrollMessageIndex != rhs.historyScrollMessageIndex {
|
||||
return false
|
||||
}
|
||||
if lhs.associatedMessageIds != rhs.associatedMessageIds {
|
||||
return false
|
||||
}
|
||||
if lhs.data != rhs.data {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public protocol PeerChatInterfaceState: PostboxCoding {
|
||||
/*public protocol PeerChatInterfaceState: PostboxCoding {
|
||||
var chatListEmbeddedState: PeerChatListEmbeddedInterfaceState? { get }
|
||||
var historyScrollMessageIndex: MessageIndex? { get }
|
||||
var associatedMessageIds: [MessageId] { get }
|
||||
|
||||
func isEqual(to: PeerChatInterfaceState) -> Bool
|
||||
}
|
||||
}*/
|
||||
|
||||
@ -5,7 +5,7 @@ final class PeerChatInterfaceStateTable: Table {
|
||||
return ValueBoxTable(id: id, keyType: .int64, compactValuesOnCreation: false)
|
||||
}
|
||||
|
||||
private var states: [PeerId: PeerChatInterfaceState?] = [:]
|
||||
private var states: [PeerId: StoredPeerChatInterfaceState?] = [:]
|
||||
private var peerIdsWithUpdatedStates = Set<PeerId>()
|
||||
|
||||
private let sharedKey = ValueBoxKey(length: 8)
|
||||
@ -15,10 +15,10 @@ final class PeerChatInterfaceStateTable: Table {
|
||||
return sharedKey
|
||||
}
|
||||
|
||||
func get(_ peerId: PeerId) -> PeerChatInterfaceState? {
|
||||
func get(_ peerId: PeerId) -> StoredPeerChatInterfaceState? {
|
||||
if let cachedValue = self.states[peerId] {
|
||||
return cachedValue
|
||||
} else if let value = self.valueBox.get(self.table, key: self.key(peerId, sharedKey: self.sharedKey)), let state = PostboxDecoder(buffer: value).decodeRootObject() as? PeerChatInterfaceState {
|
||||
} else if let value = self.valueBox.get(self.table, key: self.key(peerId, sharedKey: self.sharedKey)), let state = try? AdaptedPostboxDecoder().decode(StoredPeerChatInterfaceState.self, from: value.makeData()) {
|
||||
self.states[peerId] = state
|
||||
return state
|
||||
} else {
|
||||
@ -27,18 +27,14 @@ final class PeerChatInterfaceStateTable: Table {
|
||||
}
|
||||
}
|
||||
|
||||
func set(_ peerId: PeerId, state: PeerChatInterfaceState?) -> (updated: Bool, updatedEmbeddedState: Bool) {
|
||||
func set(_ peerId: PeerId, state: StoredPeerChatInterfaceState?) -> (updated: Bool, updatedEmbeddedState: Bool) {
|
||||
let currentState = self.get(peerId)
|
||||
var updated = false
|
||||
var updatedEmbeddedState = false
|
||||
if let currentState = currentState, let state = state {
|
||||
if !currentState.isEqual(to: state) {
|
||||
if currentState != state {
|
||||
updated = true
|
||||
if let currentEmbeddedState = currentState.chatListEmbeddedState, let embeddedState = state.chatListEmbeddedState {
|
||||
if !currentEmbeddedState.isEqual(to: embeddedState) {
|
||||
updatedEmbeddedState = true
|
||||
}
|
||||
} else if (currentState.chatListEmbeddedState != nil) != (state.chatListEmbeddedState != nil) {
|
||||
if currentState.overrideChatTimestamp != state.overrideChatTimestamp {
|
||||
updatedEmbeddedState = true
|
||||
}
|
||||
}
|
||||
@ -60,13 +56,10 @@ final class PeerChatInterfaceStateTable: Table {
|
||||
|
||||
override func beforeCommit() {
|
||||
if !self.peerIdsWithUpdatedStates.isEmpty {
|
||||
let sharedEncoder = PostboxEncoder()
|
||||
for peerId in self.peerIdsWithUpdatedStates {
|
||||
if let state = self.states[peerId] {
|
||||
if let state = state {
|
||||
sharedEncoder.reset()
|
||||
sharedEncoder.encodeRootObject(state)
|
||||
self.valueBox.set(self.table, key: self.key(peerId, sharedKey: self.sharedKey), value: sharedEncoder.readBufferNoCopy())
|
||||
if let state = state, let data = try? AdaptedPostboxEncoder().encode(state) {
|
||||
self.valueBox.set(self.table, key: self.key(peerId, sharedKey: self.sharedKey), value: ReadBuffer(data: data))
|
||||
} else {
|
||||
self.valueBox.remove(self.table, key: self.key(peerId, sharedKey: self.sharedKey), secure: false)
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ final class PeerChatThreadInterfaceStateTable: Table {
|
||||
return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: false)
|
||||
}
|
||||
|
||||
private var states: [PeerChatThreadId: PeerChatInterfaceState?] = [:]
|
||||
private var states: [PeerChatThreadId: StoredPeerChatInterfaceState?] = [:]
|
||||
private var peerIdsWithUpdatedStates = Set<PeerChatThreadId>()
|
||||
|
||||
private let sharedKey = ValueBoxKey(length: 8 + 8)
|
||||
@ -26,10 +26,10 @@ final class PeerChatThreadInterfaceStateTable: Table {
|
||||
return sharedKey
|
||||
}
|
||||
|
||||
func get(_ peerId: PeerChatThreadId) -> PeerChatInterfaceState? {
|
||||
func get(_ peerId: PeerChatThreadId) -> StoredPeerChatInterfaceState? {
|
||||
if let cachedValue = self.states[peerId] {
|
||||
return cachedValue
|
||||
} else if let value = self.valueBox.get(self.table, key: self.key(peerId, sharedKey: self.sharedKey)), let state = PostboxDecoder(buffer: value).decodeRootObject() as? PeerChatInterfaceState {
|
||||
} else if let value = self.valueBox.get(self.table, key: self.key(peerId, sharedKey: self.sharedKey)), let state = try? AdaptedPostboxDecoder().decode(StoredPeerChatInterfaceState.self, from: value.makeData()) {
|
||||
self.states[peerId] = state
|
||||
return state
|
||||
} else {
|
||||
@ -38,11 +38,11 @@ final class PeerChatThreadInterfaceStateTable: Table {
|
||||
}
|
||||
}
|
||||
|
||||
func set(_ peerId: PeerChatThreadId, state: PeerChatInterfaceState?) -> Bool {
|
||||
func set(_ peerId: PeerChatThreadId, state: StoredPeerChatInterfaceState?) -> Bool {
|
||||
let currentState = self.get(peerId)
|
||||
var updated = false
|
||||
if let currentState = currentState, let state = state {
|
||||
if !currentState.isEqual(to: state) {
|
||||
if currentState != state {
|
||||
updated = true
|
||||
}
|
||||
} else if (currentState != nil) != (state != nil) {
|
||||
@ -62,13 +62,10 @@ final class PeerChatThreadInterfaceStateTable: Table {
|
||||
|
||||
override func beforeCommit() {
|
||||
if !self.peerIdsWithUpdatedStates.isEmpty {
|
||||
let sharedEncoder = PostboxEncoder()
|
||||
for peerId in self.peerIdsWithUpdatedStates {
|
||||
if let state = self.states[peerId] {
|
||||
if let state = state {
|
||||
sharedEncoder.reset()
|
||||
sharedEncoder.encodeRootObject(state)
|
||||
self.valueBox.set(self.table, key: self.key(peerId, sharedKey: self.sharedKey), value: sharedEncoder.readBufferNoCopy())
|
||||
if let state = state, let data = try? AdaptedPostboxEncoder().encode(state) {
|
||||
self.valueBox.set(self.table, key: self.key(peerId, sharedKey: self.sharedKey), value: ReadBuffer(data: data))
|
||||
} else {
|
||||
self.valueBox.remove(self.table, key: self.key(peerId, sharedKey: self.sharedKey), secure: false)
|
||||
}
|
||||
|
||||
@ -259,29 +259,24 @@ public final class Transaction {
|
||||
}
|
||||
}
|
||||
|
||||
/*public func getPeerGroupState(_ id: PeerGroupId) -> PeerGroupState? {
|
||||
assert(!self.disposed)
|
||||
return self.postbox?.peerGroupStateTable.get(id)
|
||||
}
|
||||
|
||||
public func setPeerGroupState(_ id: PeerGroupId, state: PeerGroupState) {
|
||||
assert(!self.disposed)
|
||||
self.postbox?.setPeerGroupState(id, state: state)
|
||||
}*/
|
||||
|
||||
public func getPeerChatInterfaceState(_ id: PeerId) -> PeerChatInterfaceState? {
|
||||
public func getPeerChatInterfaceState(_ id: PeerId) -> StoredPeerChatInterfaceState? {
|
||||
assert(!self.disposed)
|
||||
return self.postbox?.peerChatInterfaceStateTable.get(id)
|
||||
}
|
||||
|
||||
public func updatePeerChatInterfaceState(_ id: PeerId, update: (PeerChatInterfaceState?) -> (PeerChatInterfaceState?)) {
|
||||
|
||||
public func getPeerChatThreadInterfaceState(_ id: PeerId, threadId: Int64) -> StoredPeerChatInterfaceState? {
|
||||
assert(!self.disposed)
|
||||
self.postbox?.updatePeerChatInterfaceState(id, update: update)
|
||||
return self.postbox?.peerChatThreadInterfaceStateTable.get(PeerChatThreadId(peerId: id, threadId: threadId))
|
||||
}
|
||||
|
||||
public func updatePeerChatThreadInterfaceState(_ id: PeerId, threadId: Int64, update: (PeerChatInterfaceState?) -> (PeerChatInterfaceState?)) {
|
||||
public func setPeerChatInterfaceState(_ id: PeerId, state: StoredPeerChatInterfaceState?) {
|
||||
assert(!self.disposed)
|
||||
self.postbox?.updatePeerChatThreadInterfaceState(id, threadId: threadId, update: update)
|
||||
self.postbox?.setPeerChatInterfaceState(id, state: state)
|
||||
}
|
||||
|
||||
public func setPeerChatThreadInterfaceState(_ id: PeerId, threadId: Int64, state: StoredPeerChatInterfaceState?) {
|
||||
assert(!self.disposed)
|
||||
self.postbox?.setPeerChatThreadInterfaceState(id, threadId: threadId, state: state)
|
||||
}
|
||||
|
||||
public func getPeer(_ id: PeerId) -> Peer? {
|
||||
@ -1306,7 +1301,7 @@ public final class Postbox {
|
||||
private var currentUpdatedPeerNotificationBehaviorTimestamps: [PeerId: PeerNotificationSettingsBehaviorTimestamp] = [:]
|
||||
private var currentUpdatedCachedPeerData: [PeerId: CachedPeerData] = [:]
|
||||
private var currentUpdatedPeerPresences: [PeerId: PeerPresence] = [:]
|
||||
private var currentUpdatedPeerChatListEmbeddedStates: [PeerId: PeerChatListEmbeddedInterfaceState?] = [:]
|
||||
private var currentUpdatedPeerChatListEmbeddedStates = Set<PeerId>()
|
||||
private var currentUpdatedTotalUnreadStates: [PeerGroupId: ChatListTotalUnreadState] = [:]
|
||||
private var currentUpdatedGroupTotalUnreadSummaries: [PeerGroupId: PeerGroupUnreadCountersCombinedSummary] = [:]
|
||||
private var currentPeerMergedOperationLogOperations: [PeerMergedOperationLogOperation] = []
|
||||
@ -1479,8 +1474,8 @@ public final class Postbox {
|
||||
self.itemCollectionInfoTable = ItemCollectionInfoTable(valueBox: self.valueBox, table: ItemCollectionInfoTable.tableSpec(21))
|
||||
self.itemCollectionReverseIndexTable = ReverseIndexReferenceTable<ItemCollectionItemReverseIndexReference>(valueBox: self.valueBox, table: ReverseIndexReferenceTable<ItemCollectionItemReverseIndexReference>.tableSpec(36))
|
||||
self.itemCollectionItemTable = ItemCollectionItemTable(valueBox: self.valueBox, table: ItemCollectionItemTable.tableSpec(22), reverseIndexTable: self.itemCollectionReverseIndexTable)
|
||||
self.peerChatInterfaceStateTable = PeerChatInterfaceStateTable(valueBox: self.valueBox, table: PeerChatInterfaceStateTable.tableSpec(23))
|
||||
self.peerChatThreadInterfaceStateTable = PeerChatThreadInterfaceStateTable(valueBox: self.valueBox, table: PeerChatThreadInterfaceStateTable.tableSpec(64))
|
||||
self.peerChatInterfaceStateTable = PeerChatInterfaceStateTable(valueBox: self.valueBox, table: PeerChatInterfaceStateTable.tableSpec(67))
|
||||
self.peerChatThreadInterfaceStateTable = PeerChatThreadInterfaceStateTable(valueBox: self.valueBox, table: PeerChatThreadInterfaceStateTable.tableSpec(68))
|
||||
self.itemCacheMetaTable = ItemCacheMetaTable(valueBox: self.valueBox, table: ItemCacheMetaTable.tableSpec(24))
|
||||
self.itemCacheTable = ItemCacheTable(valueBox: self.valueBox, table: ItemCacheTable.tableSpec(25))
|
||||
self.chatListIndexTable = ChatListIndexTable(valueBox: self.valueBox, table: ChatListIndexTable.tableSpec(8), peerNameIndexTable: self.peerNameIndexTable, metadataTable: self.messageHistoryMetadataTable, readStateTable: self.readStateTable, notificationSettingsTable: self.peerNotificationSettingsTable)
|
||||
@ -2204,16 +2199,16 @@ public final class Postbox {
|
||||
self.currentUpdatedPeerChatStates.insert(id)
|
||||
}
|
||||
|
||||
fileprivate func updatePeerChatInterfaceState(_ id: PeerId, update: (PeerChatInterfaceState?) -> (PeerChatInterfaceState?)) {
|
||||
let updatedState = update(self.peerChatInterfaceStateTable.get(id))
|
||||
fileprivate func setPeerChatInterfaceState(_ id: PeerId, state: StoredPeerChatInterfaceState?) {
|
||||
let updatedState = state
|
||||
let (_, updatedEmbeddedState) = self.peerChatInterfaceStateTable.set(id, state: updatedState)
|
||||
if updatedEmbeddedState {
|
||||
self.currentUpdatedPeerChatListEmbeddedStates[id] = updatedState?.chatListEmbeddedState
|
||||
self.currentUpdatedPeerChatListEmbeddedStates.insert(id)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func updatePeerChatThreadInterfaceState(_ id: PeerId, threadId: Int64, update: (PeerChatInterfaceState?) -> (PeerChatInterfaceState?)) {
|
||||
let updatedState = update(self.peerChatThreadInterfaceStateTable.get(PeerChatThreadId(peerId: id, threadId: threadId)))
|
||||
fileprivate func setPeerChatThreadInterfaceState(_ id: PeerId, threadId: Int64, state: StoredPeerChatInterfaceState?) {
|
||||
let updatedState = state
|
||||
let _ = self.peerChatThreadInterfaceStateTable.set(PeerChatThreadId(peerId: id, threadId: threadId), state: updatedState)
|
||||
}
|
||||
|
||||
@ -2797,7 +2792,7 @@ public final class Postbox {
|
||||
}
|
||||
}
|
||||
}
|
||||
return InitialMessageHistoryData(peer: self.peerTable.get(peerId), chatInterfaceState: chatInterfaceState, associatedMessages: associatedMessages)
|
||||
return InitialMessageHistoryData(peer: self.peerTable.get(peerId), storedInterfaceState: chatInterfaceState, associatedMessages: associatedMessages)
|
||||
} else {
|
||||
let chatInterfaceState = self.peerChatInterfaceStateTable.get(peerId)
|
||||
var associatedMessages: [MessageId: Message] = [:]
|
||||
@ -2808,7 +2803,7 @@ public final class Postbox {
|
||||
}
|
||||
}
|
||||
}
|
||||
return InitialMessageHistoryData(peer: self.peerTable.get(peerId), chatInterfaceState: chatInterfaceState, associatedMessages: associatedMessages)
|
||||
return InitialMessageHistoryData(peer: self.peerTable.get(peerId), storedInterfaceState: chatInterfaceState, associatedMessages: associatedMessages)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ final class PostboxTransaction {
|
||||
let currentUpdatedPeerNotificationBehaviorTimestamps: [PeerId: PeerNotificationSettingsBehaviorTimestamp]
|
||||
let currentUpdatedCachedPeerData: [PeerId: CachedPeerData]
|
||||
let currentUpdatedPeerPresences: [PeerId: PeerPresence]
|
||||
let currentUpdatedPeerChatListEmbeddedStates: [PeerId: PeerChatListEmbeddedInterfaceState?]
|
||||
let currentUpdatedPeerChatListEmbeddedStates: Set<PeerId>
|
||||
let currentUpdatedTotalUnreadStates: [PeerGroupId: ChatListTotalUnreadState]
|
||||
let currentUpdatedTotalUnreadSummaries: [PeerGroupId: PeerGroupUnreadCountersCombinedSummary]
|
||||
let alteredInitialPeerCombinedReadStates: [PeerId: CombinedPeerReadState]
|
||||
@ -174,7 +174,7 @@ final class PostboxTransaction {
|
||||
return true
|
||||
}
|
||||
|
||||
init(currentUpdatedState: PostboxCoding?, currentPeerHoleOperations: [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]] = [:], currentOperationsByPeerId: [PeerId: [MessageHistoryOperation]], chatListOperations: [PeerGroupId: [ChatListOperation]], currentUpdatedChatListInclusions: [PeerId: PeerChatListInclusion], currentUpdatedPeers: [PeerId: Peer], currentUpdatedPeerNotificationSettings: [PeerId: (PeerNotificationSettings?, PeerNotificationSettings)], currentUpdatedPeerNotificationBehaviorTimestamps: [PeerId: PeerNotificationSettingsBehaviorTimestamp], currentUpdatedCachedPeerData: [PeerId: CachedPeerData], currentUpdatedPeerPresences: [PeerId: PeerPresence], currentUpdatedPeerChatListEmbeddedStates: [PeerId: PeerChatListEmbeddedInterfaceState?], currentUpdatedTotalUnreadStates: [PeerGroupId: ChatListTotalUnreadState], currentUpdatedTotalUnreadSummaries: [PeerGroupId: PeerGroupUnreadCountersCombinedSummary], alteredInitialPeerCombinedReadStates: [PeerId: CombinedPeerReadState], currentPeerMergedOperationLogOperations: [PeerMergedOperationLogOperation], currentTimestampBasedMessageAttributesOperations: [TimestampBasedMessageAttributesOperation], unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation], updatedSynchronizePeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?], currentUpdatedGroupSummarySynchronizeOperations: [PeerGroupAndNamespace: Bool], currentPreferencesOperations: [PreferencesOperation], currentOrderedItemListOperations: [Int32: [OrderedItemListOperation]], currentItemCollectionItemsOperations: [ItemCollectionId: [ItemCollectionItemsOperation]], currentItemCollectionInfosOperations: [ItemCollectionInfosOperation], currentUpdatedPeerChatStates: Set<PeerId>, currentGlobalTagsOperations: [GlobalMessageHistoryTagsOperation], currentLocalTagsOperations: [IntermediateMessageHistoryLocalTagsOperation], updatedMedia: [MediaId: Media?], replaceRemoteContactCount: Int32?, replaceContactPeerIds: Set<PeerId>?, currentPendingMessageActionsOperations: [PendingMessageActionsOperation], currentUpdatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32], currentUpdatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], currentInvalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation], currentUpdatedPendingPeerNotificationSettings: Set<PeerId>, replacedAdditionalChatListItems: [AdditionalChatListItem]?, updatedNoticeEntryKeys: Set<NoticeEntryKey>, updatedCacheEntryKeys: Set<ItemCacheEntryId>, currentUpdatedMasterClientId: Int64?, updatedFailedMessagePeerIds: Set<PeerId>, updatedFailedMessageIds: Set<MessageId>, updatedGlobalNotificationSettings: Bool) {
|
||||
init(currentUpdatedState: PostboxCoding?, currentPeerHoleOperations: [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]] = [:], currentOperationsByPeerId: [PeerId: [MessageHistoryOperation]], chatListOperations: [PeerGroupId: [ChatListOperation]], currentUpdatedChatListInclusions: [PeerId: PeerChatListInclusion], currentUpdatedPeers: [PeerId: Peer], currentUpdatedPeerNotificationSettings: [PeerId: (PeerNotificationSettings?, PeerNotificationSettings)], currentUpdatedPeerNotificationBehaviorTimestamps: [PeerId: PeerNotificationSettingsBehaviorTimestamp], currentUpdatedCachedPeerData: [PeerId: CachedPeerData], currentUpdatedPeerPresences: [PeerId: PeerPresence], currentUpdatedPeerChatListEmbeddedStates: Set<PeerId>, currentUpdatedTotalUnreadStates: [PeerGroupId: ChatListTotalUnreadState], currentUpdatedTotalUnreadSummaries: [PeerGroupId: PeerGroupUnreadCountersCombinedSummary], alteredInitialPeerCombinedReadStates: [PeerId: CombinedPeerReadState], currentPeerMergedOperationLogOperations: [PeerMergedOperationLogOperation], currentTimestampBasedMessageAttributesOperations: [TimestampBasedMessageAttributesOperation], unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation], updatedSynchronizePeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?], currentUpdatedGroupSummarySynchronizeOperations: [PeerGroupAndNamespace: Bool], currentPreferencesOperations: [PreferencesOperation], currentOrderedItemListOperations: [Int32: [OrderedItemListOperation]], currentItemCollectionItemsOperations: [ItemCollectionId: [ItemCollectionItemsOperation]], currentItemCollectionInfosOperations: [ItemCollectionInfosOperation], currentUpdatedPeerChatStates: Set<PeerId>, currentGlobalTagsOperations: [GlobalMessageHistoryTagsOperation], currentLocalTagsOperations: [IntermediateMessageHistoryLocalTagsOperation], updatedMedia: [MediaId: Media?], replaceRemoteContactCount: Int32?, replaceContactPeerIds: Set<PeerId>?, currentPendingMessageActionsOperations: [PendingMessageActionsOperation], currentUpdatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32], currentUpdatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], currentInvalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation], currentUpdatedPendingPeerNotificationSettings: Set<PeerId>, replacedAdditionalChatListItems: [AdditionalChatListItem]?, updatedNoticeEntryKeys: Set<NoticeEntryKey>, updatedCacheEntryKeys: Set<ItemCacheEntryId>, currentUpdatedMasterClientId: Int64?, updatedFailedMessagePeerIds: Set<PeerId>, updatedFailedMessageIds: Set<MessageId>, updatedGlobalNotificationSettings: Bool) {
|
||||
self.currentUpdatedState = currentUpdatedState
|
||||
self.currentPeerHoleOperations = currentPeerHoleOperations
|
||||
self.currentOperationsByPeerId = currentOperationsByPeerId
|
||||
|
||||
@ -10,7 +10,10 @@ final public class AdaptedPostboxDecoder {
|
||||
case dataArray
|
||||
}
|
||||
|
||||
func decode<T>(_ type: T.Type, from data: Data) throws -> T where T : Decodable {
|
||||
public init() {
|
||||
}
|
||||
|
||||
public func decode<T>(_ type: T.Type, from data: Data) throws -> T where T : Decodable {
|
||||
return try self.decode(type, from: data, contentType: .object)
|
||||
}
|
||||
|
||||
|
||||
@ -38,8 +38,22 @@ extension _AdaptedPostboxDecoder.KeyedContainer: KeyedDecodingContainerProtocol
|
||||
if let mappedType = AdaptedPostboxDecoder.ContentType(valueType: valueType) {
|
||||
return try AdaptedPostboxDecoder().decode(T.self, from: data, contentType: mappedType)
|
||||
} else {
|
||||
decodingErrorBreakpoint()
|
||||
throw DecodingError.typeMismatch(T.self, DecodingError.Context(codingPath: self.codingPath + [key], debugDescription: ""))
|
||||
switch valueType {
|
||||
case .Bytes:
|
||||
guard let resultData = PostboxDecoder.parseDataRaw(data: data) else {
|
||||
decodingErrorBreakpoint()
|
||||
throw DecodingError.typeMismatch(T.self, DecodingError.Context(codingPath: self.codingPath + [key], debugDescription: ""))
|
||||
}
|
||||
if let resultData = resultData as? T {
|
||||
return resultData
|
||||
} else {
|
||||
decodingErrorBreakpoint()
|
||||
throw DecodingError.typeMismatch(T.self, DecodingError.Context(codingPath: self.codingPath + [key], debugDescription: ""))
|
||||
}
|
||||
default:
|
||||
decodingErrorBreakpoint()
|
||||
throw DecodingError.typeMismatch(T.self, DecodingError.Context(codingPath: self.codingPath + [key], debugDescription: ""))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
decodingErrorBreakpoint()
|
||||
@ -82,6 +96,15 @@ extension _AdaptedPostboxDecoder.KeyedContainer: KeyedDecodingContainerProtocol
|
||||
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.codingPath + [key], debugDescription: ""))
|
||||
}
|
||||
}
|
||||
|
||||
func decode(_ type: Double.Type, forKey key: Key) throws -> Double {
|
||||
if let value = self.decoder.decodeOptionalDoubleForKey(key.stringValue) {
|
||||
return value
|
||||
} else {
|
||||
decodingErrorBreakpoint()
|
||||
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.codingPath + [key], debugDescription: ""))
|
||||
}
|
||||
}
|
||||
|
||||
func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
|
||||
preconditionFailure()
|
||||
|
||||
@ -2,12 +2,15 @@ import Foundation
|
||||
import MurMurHash32
|
||||
|
||||
public class AdaptedPostboxEncoder {
|
||||
func encode(_ value: Encodable) throws -> Data {
|
||||
public init() {
|
||||
}
|
||||
|
||||
public func encode(_ value: Encodable) throws -> Data {
|
||||
let typeHash: Int32 = murMurHashString32("\(type(of: value))")
|
||||
|
||||
let encoder = _AdaptedPostboxEncoder(typeHash: typeHash)
|
||||
try value.encode(to: encoder)
|
||||
return encoder.makeData().0
|
||||
return encoder.makeData(addHeader: false).0
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,8 +27,8 @@ final class _AdaptedPostboxEncoder {
|
||||
self.typeHash = typeHash
|
||||
}
|
||||
|
||||
func makeData() -> (Data, ValueType) {
|
||||
return self.container!.makeData()
|
||||
func makeData(addHeader: Bool) -> (Data, ValueType) {
|
||||
return self.container!.makeData(addHeader: addHeader)
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,5 +61,5 @@ extension _AdaptedPostboxEncoder: Encoder {
|
||||
}
|
||||
|
||||
protocol AdaptedPostboxEncodingContainer: AnyObject {
|
||||
func makeData() -> (Data, ValueType)
|
||||
func makeData(addHeader: Bool) -> (Data, ValueType)
|
||||
}
|
||||
|
||||
@ -17,16 +17,21 @@ extension _AdaptedPostboxEncoder {
|
||||
self.encoder = PostboxEncoder()
|
||||
}
|
||||
|
||||
func makeData() -> (Data, ValueType) {
|
||||
func makeData(addHeader: Bool) -> (Data, ValueType) {
|
||||
let buffer = WriteBuffer()
|
||||
|
||||
var typeHash: Int32 = self.typeHash
|
||||
buffer.write(&typeHash, offset: 0, length: 4)
|
||||
if addHeader {
|
||||
var typeHash: Int32 = self.typeHash
|
||||
buffer.write(&typeHash, offset: 0, length: 4)
|
||||
}
|
||||
|
||||
let data = self.encoder.makeData()
|
||||
|
||||
var length: Int32 = Int32(data.count)
|
||||
buffer.write(&length, offset: 0, length: 4)
|
||||
if addHeader {
|
||||
var length: Int32 = Int32(data.count)
|
||||
buffer.write(&length, offset: 0, length: 4)
|
||||
}
|
||||
|
||||
buffer.write(data)
|
||||
|
||||
return (buffer.makeData(), .Object)
|
||||
@ -43,7 +48,7 @@ extension _AdaptedPostboxEncoder.KeyedContainer: KeyedEncodingContainerProtocol
|
||||
let innerEncoder = _AdaptedPostboxEncoder(typeHash: typeHash)
|
||||
try! value.encode(to: innerEncoder)
|
||||
|
||||
let (data, valueType) = innerEncoder.makeData()
|
||||
let (data, valueType) = innerEncoder.makeData(addHeader: true)
|
||||
self.encoder.encodeInnerObjectData(data, valueType: valueType, forKey: key.stringValue)
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,7 +79,7 @@ extension _AdaptedPostboxEncoder.SingleValueContainer: SingleValueEncodingContai
|
||||
}
|
||||
|
||||
extension _AdaptedPostboxEncoder.SingleValueContainer: AdaptedPostboxEncodingContainer {
|
||||
func makeData() -> (Data, ValueType) {
|
||||
func makeData(addHeader: Bool) -> (Data, ValueType) {
|
||||
preconditionFailure()
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,9 @@ extension _AdaptedPostboxEncoder {
|
||||
self.userInfo = userInfo
|
||||
}
|
||||
|
||||
func makeData() -> (Data, ValueType) {
|
||||
func makeData(addHeader: Bool) -> (Data, ValueType) {
|
||||
precondition(addHeader)
|
||||
|
||||
if self.items.isEmpty {
|
||||
let buffer = WriteBuffer()
|
||||
|
||||
@ -111,7 +113,7 @@ extension _AdaptedPostboxEncoder.UnkeyedContainer: UnkeyedEncodingContainer {
|
||||
let innerEncoder = _AdaptedPostboxEncoder(typeHash: typeHash)
|
||||
try! value.encode(to: innerEncoder)
|
||||
|
||||
let (data, _) = innerEncoder.makeData()
|
||||
let (data, _) = innerEncoder.makeData(addHeader: true)
|
||||
|
||||
let buffer = WriteBuffer()
|
||||
|
||||
|
||||
@ -698,13 +698,11 @@ public enum AccountNetworkState: Equatable {
|
||||
}
|
||||
|
||||
public final class AccountAuxiliaryMethods {
|
||||
public let updatePeerChatInputState: (PeerChatInterfaceState?, SynchronizeableChatInputState?) -> PeerChatInterfaceState?
|
||||
public let fetchResource: (Account, MediaResource, Signal<[(Range<Int>, MediaBoxFetchPriority)], NoError>, MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError>?
|
||||
public let fetchResourceMediaReferenceHash: (MediaResource) -> Signal<Data?, NoError>
|
||||
public let prepareSecretThumbnailData: (MediaResourceData) -> (PixelDimensions, Data)?
|
||||
|
||||
public init(updatePeerChatInputState: @escaping (PeerChatInterfaceState?, SynchronizeableChatInputState?) -> PeerChatInterfaceState?, fetchResource: @escaping (Account, MediaResource, Signal<[(Range<Int>, MediaBoxFetchPriority)], NoError>, MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError>?, fetchResourceMediaReferenceHash: @escaping (MediaResource) -> Signal<Data?, NoError>, prepareSecretThumbnailData: @escaping (MediaResourceData) -> (PixelDimensions, Data)?) {
|
||||
self.updatePeerChatInputState = updatePeerChatInputState
|
||||
public init(fetchResource: @escaping (Account, MediaResource, Signal<[(Range<Int>, MediaBoxFetchPriority)], NoError>, MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError>?, fetchResourceMediaReferenceHash: @escaping (MediaResource) -> Signal<Data?, NoError>, prepareSecretThumbnailData: @escaping (MediaResourceData) -> (PixelDimensions, Data)?) {
|
||||
self.fetchResource = fetchResource
|
||||
self.fetchResourceMediaReferenceHash = fetchResourceMediaReferenceHash
|
||||
self.prepareSecretThumbnailData = prepareSecretThumbnailData
|
||||
|
||||
@ -1353,7 +1353,7 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
|
||||
if let replyToMsgId = replyToMsgId {
|
||||
replyToMessageId = MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId)
|
||||
}
|
||||
inputState = SynchronizeableChatInputState(replyToMessageId: replyToMessageId, text: message, entities: messageTextEntitiesFromApiEntities(entities ?? []), timestamp: date)
|
||||
inputState = SynchronizeableChatInputState(replyToMessageId: replyToMessageId, text: message, entities: messageTextEntitiesFromApiEntities(entities ?? []), timestamp: date, textSelection: nil)
|
||||
}
|
||||
updatedState.addUpdateChatInputState(peerId: peer.peerId, state: inputState)
|
||||
case let .updatePhoneCall(phoneCall):
|
||||
@ -2995,9 +2995,7 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
|
||||
case .UpdateRecentGifs:
|
||||
syncRecentGifs = true
|
||||
case let .UpdateChatInputState(peerId, inputState):
|
||||
transaction.updatePeerChatInterfaceState(peerId, update: { current in
|
||||
return auxiliaryMethods.updatePeerChatInputState(current, inputState)
|
||||
})
|
||||
_internal_updateChatInputState(transaction: transaction, peerId: peerId, inputState: inputState)
|
||||
case let .UpdateCall(call):
|
||||
updatedCalls.append(call)
|
||||
case let .AddCallSignalingData(callId, data):
|
||||
|
||||
@ -126,7 +126,11 @@ func managedSynchronizeChatInputStateOperations(postbox: Postbox, network: Netwo
|
||||
}
|
||||
|
||||
private func synchronizeChatInputState(transaction: Transaction, postbox: Postbox, network: Network, peerId: PeerId, operation: SynchronizeChatInputStateOperation) -> Signal<Void, NoError> {
|
||||
let inputState = (transaction.getPeerChatInterfaceState(peerId) as? SynchronizeableChatInterfaceState)?.synchronizeableInputState
|
||||
var inputState: SynchronizeableChatInputState?
|
||||
if let peerChatInterfaceState = transaction.getPeerChatInterfaceState(peerId), let data = peerChatInterfaceState.data {
|
||||
inputState = (try? AdaptedPostboxDecoder().decode(InternalChatInterfaceState.self, from: data))?.synchronizeableInputState
|
||||
}
|
||||
|
||||
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
||||
var flags: Int32 = 0
|
||||
if let inputState = inputState {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
|
||||
|
||||
func addSynchronizeChatInputStateOperation(transaction: Transaction, peerId: PeerId) {
|
||||
var updateLocalIndex: Int32?
|
||||
let tag: PeerOperationLogTag = OperationLogTags.SynchronizeChatInputStates
|
||||
@ -17,8 +16,8 @@ func addSynchronizeChatInputStateOperation(transaction: Transaction, peerId: Pee
|
||||
var previousState: SynchronizeableChatInputState?
|
||||
if let previousOperation = previousOperation {
|
||||
previousState = previousOperation.previousState
|
||||
} else if let peerChatInterfaceState = transaction.getPeerChatInterfaceState(peerId) as? SynchronizeableChatInterfaceState {
|
||||
previousState = peerChatInterfaceState.synchronizeableInputState
|
||||
} else if let peerChatInterfaceState = transaction.getPeerChatInterfaceState(peerId), let data = peerChatInterfaceState.data {
|
||||
previousState = (try? AdaptedPostboxDecoder().decode(InternalChatInterfaceState.self, from: data))?.synchronizeableInputState
|
||||
}
|
||||
let operationContents = SynchronizeChatInputStateOperation(previousState: previousState)
|
||||
if let updateLocalIndex = updateLocalIndex {
|
||||
|
||||
@ -8,12 +8,12 @@ public final class SynchronizeChatInputStateOperation: PostboxCoding {
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.previousState = decoder.decodeObjectForKey("p", decoder: { SynchronizeableChatInputState(decoder: $0) }) as? SynchronizeableChatInputState
|
||||
self.previousState = decoder.decode(SynchronizeableChatInputState.self, forKey: "p")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
if let previousState = self.previousState {
|
||||
encoder.encodeObject(previousState, forKey: "p")
|
||||
encoder.encode(previousState, forKey: "p")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "p")
|
||||
}
|
||||
|
||||
@ -1,42 +1,49 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
|
||||
public struct SynchronizeableChatInputState: PostboxCoding, Equatable {
|
||||
public struct SynchronizeableChatInputState: Codable, Equatable {
|
||||
public let replyToMessageId: MessageId?
|
||||
public let text: String
|
||||
public let entities: [MessageTextEntity]
|
||||
public let timestamp: Int32
|
||||
public let textSelection: Range<Int>?
|
||||
|
||||
public init(replyToMessageId: MessageId?, text: String, entities: [MessageTextEntity], timestamp: Int32) {
|
||||
public init(replyToMessageId: MessageId?, text: String, entities: [MessageTextEntity], timestamp: Int32, textSelection: Range<Int>?) {
|
||||
self.replyToMessageId = replyToMessageId
|
||||
self.text = text
|
||||
self.entities = entities
|
||||
self.timestamp = timestamp
|
||||
self.textSelection = textSelection
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.text = decoder.decodeStringForKey("t", orElse: "")
|
||||
self.entities = decoder.decodeObjectArrayWithDecoderForKey("e")
|
||||
self.timestamp = decoder.decodeInt32ForKey("s", orElse: 0)
|
||||
if let messageIdPeerId = decoder.decodeOptionalInt64ForKey("m.p"), let messageIdNamespace = decoder.decodeOptionalInt32ForKey("m.n"), let messageIdId = decoder.decodeOptionalInt32ForKey("m.i") {
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
self.text = (try? container.decode(String.self, forKey: "t")) ?? ""
|
||||
self.entities = (try? container.decode([MessageTextEntity].self, forKey: "e")) ?? []
|
||||
self.timestamp = (try? container.decode(Int32.self, forKey: "s")) ?? 0
|
||||
|
||||
if let messageIdPeerId = try? container.decodeIfPresent(Int64.self, forKey: "m.p"), let messageIdNamespace = try? container.decodeIfPresent(Int32.self, forKey: "m.n"), let messageIdId = try? container.decodeIfPresent(Int32.self, forKey: "m.i") {
|
||||
self.replyToMessageId = MessageId(peerId: PeerId(messageIdPeerId), namespace: messageIdNamespace, id: messageIdId)
|
||||
} else {
|
||||
self.replyToMessageId = nil
|
||||
}
|
||||
self.textSelection = nil
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeString(self.text, forKey: "t")
|
||||
encoder.encodeObjectArray(self.entities, forKey: "e")
|
||||
encoder.encodeInt32(self.timestamp, forKey: "s")
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encode(self.text, forKey: "t")
|
||||
try container.encode(self.entities, forKey: "e")
|
||||
try container.encode(self.timestamp, forKey: "s")
|
||||
if let replyToMessageId = self.replyToMessageId {
|
||||
encoder.encodeInt64(replyToMessageId.peerId.toInt64(), forKey: "m.p")
|
||||
encoder.encodeInt32(replyToMessageId.namespace, forKey: "m.n")
|
||||
encoder.encodeInt32(replyToMessageId.id, forKey: "m.i")
|
||||
try container.encode(replyToMessageId.peerId.toInt64(), forKey: "m.p")
|
||||
try container.encode(replyToMessageId.namespace, forKey: "m.n")
|
||||
try container.encode(replyToMessageId.id, forKey: "m.i")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "m.p")
|
||||
encoder.encodeNil(forKey: "m.n")
|
||||
encoder.encodeNil(forKey: "m.i")
|
||||
try container.encodeNil(forKey: "m.p")
|
||||
try container.encodeNil(forKey: "m.n")
|
||||
try container.encodeNil(forKey: "m.i")
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,11 +60,46 @@ public struct SynchronizeableChatInputState: PostboxCoding, Equatable {
|
||||
if lhs.timestamp != rhs.timestamp {
|
||||
return false
|
||||
}
|
||||
if lhs.textSelection != rhs.textSelection {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public protocol SynchronizeableChatInterfaceState: PeerChatInterfaceState {
|
||||
var synchronizeableInputState: SynchronizeableChatInputState? { get }
|
||||
func withUpdatedSynchronizeableInputState(_ state: SynchronizeableChatInputState?) -> SynchronizeableChatInterfaceState
|
||||
class InternalChatInterfaceState: Codable {
|
||||
let synchronizeableInputState: SynchronizeableChatInputState?
|
||||
let historyScrollMessageIndex: MessageIndex?
|
||||
let opaqueData: Data?
|
||||
|
||||
init(
|
||||
synchronizeableInputState: SynchronizeableChatInputState?,
|
||||
historyScrollMessageIndex: MessageIndex?,
|
||||
opaqueData: Data?
|
||||
) {
|
||||
self.synchronizeableInputState = synchronizeableInputState
|
||||
self.historyScrollMessageIndex = historyScrollMessageIndex
|
||||
self.opaqueData = opaqueData
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_updateChatInputState(transaction: Transaction, peerId: PeerId, inputState: SynchronizeableChatInputState?) {
|
||||
var previousState: InternalChatInterfaceState?
|
||||
if let peerChatInterfaceState = transaction.getPeerChatInterfaceState(peerId), let data = peerChatInterfaceState.data {
|
||||
previousState = (try? AdaptedPostboxDecoder().decode(InternalChatInterfaceState.self, from: data))
|
||||
}
|
||||
|
||||
if let updatedStateData = try? AdaptedPostboxEncoder().encode(InternalChatInterfaceState(
|
||||
synchronizeableInputState: inputState,
|
||||
historyScrollMessageIndex: previousState?.historyScrollMessageIndex,
|
||||
opaqueData: previousState?.opaqueData
|
||||
)) {
|
||||
let storedState = StoredPeerChatInterfaceState(
|
||||
overrideChatTimestamp: inputState?.timestamp,
|
||||
historyScrollMessageIndex: previousState?.historyScrollMessageIndex,
|
||||
associatedMessageIds: (inputState?.replyToMessageId).flatMap({ [$0] }) ?? [],
|
||||
data: updatedStateData
|
||||
)
|
||||
transaction.setPeerChatInterfaceState(peerId, state: storedState)
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ public enum MessageTextEntityType: Equatable {
|
||||
case Custom(type: CustomEntityType)
|
||||
}
|
||||
|
||||
public struct MessageTextEntity: PostboxCoding, Equatable {
|
||||
public struct MessageTextEntity: PostboxCoding, Codable, Equatable {
|
||||
public let range: Range<Int>
|
||||
public let type: MessageTextEntityType
|
||||
|
||||
@ -74,6 +74,60 @@ public struct MessageTextEntity: PostboxCoding, Equatable {
|
||||
self.type = .Unknown
|
||||
}
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
let rangeStart: Int32 = (try? container.decode(Int32.self, forKey: "start")) ?? 0
|
||||
var rangeEnd: Int32 = (try? container.decode(Int32.self, forKey: "end")) ?? 0
|
||||
rangeEnd = max(rangeEnd, rangeStart)
|
||||
|
||||
let type: Int32 = (try? container.decode(Int32.self, forKey: "_rawValue")) ?? 0
|
||||
|
||||
self.range = Int(rangeStart) ..< Int(rangeEnd)
|
||||
|
||||
switch type {
|
||||
case 1:
|
||||
self.type = .Mention
|
||||
case 2:
|
||||
self.type = .Hashtag
|
||||
case 3:
|
||||
self.type = .BotCommand
|
||||
case 4:
|
||||
self.type = .Url
|
||||
case 5:
|
||||
self.type = .Email
|
||||
case 6:
|
||||
self.type = .Bold
|
||||
case 7:
|
||||
self.type = .Italic
|
||||
case 8:
|
||||
self.type = .Code
|
||||
case 9:
|
||||
self.type = .Pre
|
||||
case 10:
|
||||
let url = (try? container.decode(String.self, forKey: "url")) ?? ""
|
||||
self.type = .TextUrl(url: url)
|
||||
case 11:
|
||||
let peerId = (try? container.decode(Int64.self, forKey: "peerId")) ?? 0
|
||||
self.type = .TextMention(peerId: PeerId(peerId))
|
||||
case 12:
|
||||
self.type = .PhoneNumber
|
||||
case 13:
|
||||
self.type = .Strikethrough
|
||||
case 14:
|
||||
self.type = .BlockQuote
|
||||
case 15:
|
||||
self.type = .Underline
|
||||
case 16:
|
||||
self.type = .BankCard
|
||||
case Int32.max:
|
||||
let customType: Int32 = (try? container.decode(Int32.self, forKey: "type")) ?? 0
|
||||
self.type = .Custom(type: customType)
|
||||
default:
|
||||
self.type = .Unknown
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeInt32(Int32(self.range.lowerBound), forKey: "start")
|
||||
@ -120,6 +174,54 @@ public struct MessageTextEntity: PostboxCoding, Equatable {
|
||||
encoder.encodeInt32(type, forKey: "type")
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encode(Int32(self.range.lowerBound), forKey: "start")
|
||||
try container.encode(Int32(self.range.upperBound), forKey: "end")
|
||||
switch self.type {
|
||||
case .Unknown:
|
||||
try container.encode(0 as Int32, forKey: "_rawValue")
|
||||
case .Mention:
|
||||
try container.encode(1 as Int32, forKey: "_rawValue")
|
||||
case .Hashtag:
|
||||
try container.encode(2 as Int32, forKey: "_rawValue")
|
||||
case .BotCommand:
|
||||
try container.encode(3 as Int32, forKey: "_rawValue")
|
||||
case .Url:
|
||||
try container.encode(4 as Int32, forKey: "_rawValue")
|
||||
case .Email:
|
||||
try container.encode(5 as Int32, forKey: "_rawValue")
|
||||
case .Bold:
|
||||
try container.encode(6 as Int32, forKey: "_rawValue")
|
||||
case .Italic:
|
||||
try container.encode(7 as Int32, forKey: "_rawValue")
|
||||
case .Code:
|
||||
try container.encode(8 as Int32, forKey: "_rawValue")
|
||||
case .Pre:
|
||||
try container.encode(9 as Int32, forKey: "_rawValue")
|
||||
case let .TextUrl(url):
|
||||
try container.encode(10 as Int32, forKey: "_rawValue")
|
||||
try container.encode(url, forKey: "url")
|
||||
case let .TextMention(peerId):
|
||||
try container.encode(11 as Int32, forKey: "_rawValue")
|
||||
try container.encode(peerId.toInt64(), forKey: "peerId")
|
||||
case .PhoneNumber:
|
||||
try container.encode(12 as Int32, forKey: "_rawValue")
|
||||
case .Strikethrough:
|
||||
try container.encode(13 as Int32, forKey: "_rawValue")
|
||||
case .BlockQuote:
|
||||
try container.encode(14 as Int32, forKey: "_rawValue")
|
||||
case .Underline:
|
||||
try container.encode(15 as Int32, forKey: "_rawValue")
|
||||
case .BankCard:
|
||||
try container.encode(16 as Int32, forKey: "_rawValue")
|
||||
case let .Custom(type):
|
||||
try container.encode(Int32.max as Int32, forKey: "_rawValue")
|
||||
try container.encode(type as Int32, forKey: "type")
|
||||
}
|
||||
}
|
||||
|
||||
public static func ==(lhs: MessageTextEntity, rhs: MessageTextEntity) -> Bool {
|
||||
return lhs.range == rhs.range && lhs.type == rhs.type
|
||||
|
||||
@ -41,13 +41,7 @@ func _internal_clearCloudDraftsInteractively(postbox: Postbox, network: Network,
|
||||
updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences)
|
||||
var signals: [Signal<Void, NoError>] = []
|
||||
for peerId in peerIds {
|
||||
transaction.updatePeerChatInterfaceState(peerId, update: { current in
|
||||
if let current = current as? SynchronizeableChatInterfaceState {
|
||||
return current.withUpdatedSynchronizeableInputState(nil)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
})
|
||||
_internal_updateChatInputState(transaction: transaction, peerId: peerId, inputState: nil)
|
||||
|
||||
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
||||
signals.append(network.request(Api.functions.messages.saveDraft(flags: 0, replyToMsgId: nil, peer: inputPeer, message: "", entities: nil))
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
import Postbox
|
||||
|
||||
public protocol EngineOpaqueChatState: AnyObject, Codable {
|
||||
func isEqual(to other: EngineOpaqueChatState) -> Bool
|
||||
}
|
||||
@ -25,13 +25,7 @@ func _internal_terminateSecretChat(transaction: Transaction, peerId: PeerId, req
|
||||
|
||||
func _internal_removePeerChat(account: Account, transaction: Transaction, mediaBox: MediaBox, peerId: PeerId, reportChatSpam: Bool, deleteGloballyIfPossible: Bool) {
|
||||
if let _ = transaction.getPeerChatInterfaceState(peerId) {
|
||||
transaction.updatePeerChatInterfaceState(peerId, update: { current in
|
||||
if let current = current {
|
||||
return account.auxiliaryMethods.updatePeerChatInputState(current, nil)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
})
|
||||
transaction.setPeerChatInterfaceState(peerId, state: nil)
|
||||
}
|
||||
_internal_updateChatListFiltersInteractively(transaction: transaction, { filters in
|
||||
var filters = filters
|
||||
|
||||
@ -8,6 +8,22 @@ public enum AddressNameValidationStatus: Equatable {
|
||||
case availability(AddressNameAvailability)
|
||||
}
|
||||
|
||||
public final class OpaqueChatInterfaceState {
|
||||
public let opaqueData: Data?
|
||||
public let historyScrollMessageIndex: MessageIndex?
|
||||
public let synchronizeableInputState: SynchronizeableChatInputState?
|
||||
|
||||
public init(
|
||||
opaqueData: Data?,
|
||||
historyScrollMessageIndex: MessageIndex?,
|
||||
synchronizeableInputState: SynchronizeableChatInputState?
|
||||
) {
|
||||
self.opaqueData = opaqueData
|
||||
self.historyScrollMessageIndex = historyScrollMessageIndex
|
||||
self.synchronizeableInputState = synchronizeableInputState
|
||||
}
|
||||
}
|
||||
|
||||
public extension TelegramEngine {
|
||||
final class Peers {
|
||||
private let account: Account
|
||||
@ -508,5 +524,86 @@ public extension TelegramEngine {
|
||||
return results.first?.0
|
||||
}
|
||||
}
|
||||
|
||||
public func getOpaqueChatInterfaceState(peerId: PeerId, threadId: Int64?) -> Signal<OpaqueChatInterfaceState?, NoError> {
|
||||
return self.account.postbox.transaction { transaction -> OpaqueChatInterfaceState? in
|
||||
let storedState: StoredPeerChatInterfaceState?
|
||||
if let threadId = threadId {
|
||||
storedState = transaction.getPeerChatThreadInterfaceState(peerId, threadId: threadId)
|
||||
} else {
|
||||
storedState = transaction.getPeerChatInterfaceState(peerId)
|
||||
}
|
||||
|
||||
guard let state = storedState, let data = state.data else {
|
||||
return nil
|
||||
}
|
||||
guard let internalState = try? AdaptedPostboxDecoder().decode(InternalChatInterfaceState.self, from: data) else {
|
||||
return nil
|
||||
}
|
||||
return OpaqueChatInterfaceState(
|
||||
opaqueData: internalState.opaqueData,
|
||||
historyScrollMessageIndex: internalState.historyScrollMessageIndex,
|
||||
synchronizeableInputState: internalState.synchronizeableInputState
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public func setOpaqueChatInterfaceState(peerId: PeerId, threadId: Int64?, state: OpaqueChatInterfaceState) -> Signal<Never, NoError> {
|
||||
return self.account.postbox.transaction { transaction -> Void in
|
||||
guard let data = try? AdaptedPostboxEncoder().encode(InternalChatInterfaceState(
|
||||
synchronizeableInputState: state.synchronizeableInputState,
|
||||
historyScrollMessageIndex: state.historyScrollMessageIndex,
|
||||
opaqueData: state.opaqueData
|
||||
)) else {
|
||||
return
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
let _ = try! AdaptedPostboxDecoder().decode(InternalChatInterfaceState.self, from: data)
|
||||
#endif
|
||||
|
||||
let storedState = StoredPeerChatInterfaceState(
|
||||
overrideChatTimestamp: state.synchronizeableInputState?.timestamp,
|
||||
historyScrollMessageIndex: state.historyScrollMessageIndex,
|
||||
associatedMessageIds: (state.synchronizeableInputState?.replyToMessageId).flatMap({ [$0] }) ?? [],
|
||||
data: data
|
||||
)
|
||||
|
||||
if let threadId = threadId {
|
||||
transaction.setPeerChatThreadInterfaceState(peerId, threadId: threadId, state: storedState)
|
||||
} else {
|
||||
var currentInputState: SynchronizeableChatInputState?
|
||||
if let peerChatInterfaceState = transaction.getPeerChatInterfaceState(peerId), let data = peerChatInterfaceState.data {
|
||||
currentInputState = (try? AdaptedPostboxDecoder().decode(InternalChatInterfaceState.self, from: data))?.synchronizeableInputState
|
||||
}
|
||||
let updatedInputState = state.synchronizeableInputState
|
||||
|
||||
if currentInputState != updatedInputState {
|
||||
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudChannel || peerId.namespace == Namespaces.Peer.CloudGroup {
|
||||
addSynchronizeChatInputStateOperation(transaction: transaction, peerId: peerId)
|
||||
}
|
||||
}
|
||||
transaction.setPeerChatInterfaceState(
|
||||
peerId,
|
||||
state: storedState
|
||||
)
|
||||
}
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func _internal_decodeStoredChatInterfaceState(state: StoredPeerChatInterfaceState) -> OpaqueChatInterfaceState? {
|
||||
guard let data = state.data else {
|
||||
return nil
|
||||
}
|
||||
guard let internalState = try? AdaptedPostboxDecoder().decode(InternalChatInterfaceState.self, from: data) else {
|
||||
return nil
|
||||
}
|
||||
return OpaqueChatInterfaceState(
|
||||
opaqueData: internalState.opaqueData,
|
||||
historyScrollMessageIndex: internalState.historyScrollMessageIndex,
|
||||
synchronizeableInputState: internalState.synchronizeableInputState
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,26 +1 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
|
||||
|
||||
public func updatePeerChatInterfaceState(account: Account, peerId: PeerId, threadId: Int64?, state: SynchronizeableChatInterfaceState) -> Signal<Void, NoError> {
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
if let threadId = threadId {
|
||||
transaction.updatePeerChatThreadInterfaceState(peerId, threadId: threadId, update: { _ in
|
||||
return state
|
||||
})
|
||||
} else {
|
||||
let currentInputState = (transaction.getPeerChatInterfaceState(peerId) as? SynchronizeableChatInterfaceState)?.synchronizeableInputState
|
||||
let updatedInputState = state.synchronizeableInputState
|
||||
|
||||
if currentInputState != updatedInputState {
|
||||
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudChannel || peerId.namespace == Namespaces.Peer.CloudGroup {
|
||||
addSynchronizeChatInputStateOperation(transaction: transaction, peerId: peerId)
|
||||
}
|
||||
}
|
||||
transaction.updatePeerChatInterfaceState(peerId, update: { _ in
|
||||
return state
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3803,7 +3803,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
})
|
||||
|
||||
if case let .peer(peerId) = self.chatLocation {
|
||||
/*if case let .peer(peerId) = self.chatLocation {
|
||||
self.importStateDisposable = (ChatHistoryImportTasks.importState(peerId: peerId)
|
||||
|> distinctUntilChanged
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
@ -3817,7 +3817,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
$0.updatedImportState(mappedState)
|
||||
})
|
||||
})
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
@ -4282,7 +4282,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let strongSelf = self, let combinedInitialData = combinedInitialData else {
|
||||
return
|
||||
}
|
||||
if let interfaceState = combinedInitialData.initialData?.chatInterfaceState as? ChatInterfaceState {
|
||||
|
||||
if let opaqueState = (combinedInitialData.initialData?.storedInterfaceState).flatMap(_internal_decodeStoredChatInterfaceState) {
|
||||
let interfaceState = ChatInterfaceState.parse(opaqueState)
|
||||
|
||||
var pinnedMessageId: MessageId?
|
||||
var peerIsBlocked: Bool = false
|
||||
var callsAvailable: Bool = true
|
||||
@ -7515,7 +7518,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
interfaceState = interfaceState.withUpdatedHistoryScrollState(scrollState)
|
||||
}
|
||||
interfaceState = interfaceState.withUpdatedInputLanguage(self.chatDisplayNode.currentTextInputLanguage)
|
||||
let _ = updatePeerChatInterfaceState(account: self.context.account, peerId: peerId, threadId: threadId, state: interfaceState).start()
|
||||
let _ = ChatInterfaceState.update(engine: self.context.engine, peerId: peerId, threadId: threadId, { _ in
|
||||
return interfaceState
|
||||
}).start()
|
||||
}
|
||||
|
||||
override public func viewDidDisappear(_ animated: Bool) {
|
||||
@ -11173,16 +11178,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = (strongSelf.context.account.postbox.transaction({ transaction -> Void in
|
||||
transaction.updatePeerChatInterfaceState(peerId, update: { currentState in
|
||||
if let currentState = currentState as? ChatInterfaceState {
|
||||
return currentState.withUpdatedForwardMessageIds(messages.map { $0.id })
|
||||
} else {
|
||||
return ChatInterfaceState().withUpdatedForwardMessageIds(messages.map { $0.id })
|
||||
}
|
||||
})
|
||||
}) |> deliverOnMainQueue).start(completed: {
|
||||
|
||||
let _ = (ChatInterfaceState.update(engine: strongSelf.context.engine, peerId: peerId, threadId: nil, { currentState in
|
||||
return currentState.withUpdatedForwardMessageIds(messages.map { $0.id })
|
||||
})
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: false, interactive: true, { $0.updatedInterfaceState({ $0.withoutSelectionState() }) })
|
||||
|
||||
@ -11266,14 +11266,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}))
|
||||
case let .chat(textInputState, subject, peekData):
|
||||
if let textInputState = textInputState {
|
||||
let _ = (self.context.account.postbox.transaction({ transaction -> Void in
|
||||
transaction.updatePeerChatInterfaceState(peerId, update: { currentState in
|
||||
if let currentState = currentState as? ChatInterfaceState {
|
||||
return currentState.withUpdatedComposeInputState(textInputState)
|
||||
} else {
|
||||
return ChatInterfaceState().withUpdatedComposeInputState(textInputState)
|
||||
}
|
||||
})
|
||||
let _ = (ChatInterfaceState.update(engine: self.context.engine, peerId: peerId, threadId: nil, { currentState in
|
||||
return currentState.withUpdatedComposeInputState(textInputState)
|
||||
})
|
||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||
if let strongSelf = self, let navigationController = strongSelf.effectiveNavigationController {
|
||||
@ -11308,15 +11302,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
})
|
||||
strongController.dismiss()
|
||||
} else {
|
||||
let _ = (strongSelf.context.account.postbox.transaction({ transaction -> Void in
|
||||
transaction.updatePeerChatInterfaceState(peerId, update: { currentState in
|
||||
if let currentState = currentState as? ChatInterfaceState {
|
||||
return currentState.withUpdatedComposeInputState(textInputState)
|
||||
} else {
|
||||
return ChatInterfaceState().withUpdatedComposeInputState(textInputState)
|
||||
}
|
||||
})
|
||||
}) |> deliverOnMainQueue).start(completed: {
|
||||
let _ = (ChatInterfaceState.update(engine: strongSelf.context.engine, peerId: peerId, threadId: nil, { currentState in
|
||||
return currentState.withUpdatedComposeInputState(textInputState)
|
||||
})
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: false, interactive: true, { $0.updatedInterfaceState({ $0.withoutSelectionState() }) })
|
||||
|
||||
|
||||
@ -149,7 +149,7 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, context: A
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if view.isAddedToChatList, let historyScrollState = (initialData?.chatInterfaceState as? ChatInterfaceState)?.historyScrollState, tagMask == nil {
|
||||
} else if view.isAddedToChatList, tagMask == nil, let historyScrollState = (initialData?.storedInterfaceState).flatMap(_internal_decodeStoredChatInterfaceState).flatMap(ChatInterfaceState.parse)?.historyScrollState {
|
||||
scrollPosition = .positionRestoration(index: historyScrollState.messageIndex, relativeOffset: CGFloat(historyScrollState.relativeOffset))
|
||||
} else {
|
||||
if case .peer = chatLocation, !view.isAddedToChatList {
|
||||
|
||||
@ -761,16 +761,20 @@ final class ChatMediaInputNode: ChatInputNode {
|
||||
let inputNodeInteraction = self.inputNodeInteraction!
|
||||
let peerSpecificPack: Signal<(PeerSpecificPackData?, CanInstallPeerSpecificPack), NoError>
|
||||
if let peerId = peerId {
|
||||
self.dismissedPeerSpecificStickerPack.set(context.account.postbox.transaction { transaction -> Bool in
|
||||
guard let state = transaction.getPeerChatInterfaceState(peerId) as? ChatInterfaceState else {
|
||||
self.dismissedPeerSpecificStickerPack.set(
|
||||
context.engine.peers.getOpaqueChatInterfaceState(peerId: peerId, threadId: nil)
|
||||
|> map { opaqueState -> Bool in
|
||||
guard let opaqueState = opaqueState else {
|
||||
return false
|
||||
}
|
||||
let interfaceState = ChatInterfaceState.parse(opaqueState)
|
||||
|
||||
if interfaceState.messageActionsState.closedPeerSpecificPackSetup {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
if state.messageActionsState.closedPeerSpecificPackSetup {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
)
|
||||
peerSpecificPack = combineLatest(context.engine.peers.peerSpecificStickerPack(peerId: peerId), context.account.postbox.multiplePeersView([peerId]), self.dismissedPeerSpecificStickerPack.get())
|
||||
|> map { packData, peersView, dismissedPeerSpecificPack -> (PeerSpecificPackData?, CanInstallPeerSpecificPack) in
|
||||
if let peer = peersView.peers[peerId] {
|
||||
@ -2094,17 +2098,11 @@ final class ChatMediaInputNode: ChatInputNode {
|
||||
return
|
||||
}
|
||||
self.dismissedPeerSpecificStickerPack.set(.single(true))
|
||||
let _ = (self.context.account.postbox.transaction { transaction -> Void in
|
||||
transaction.updatePeerChatInterfaceState(peerId, update: { current in
|
||||
if let current = current as? ChatInterfaceState {
|
||||
return current.withUpdatedMessageActionsState({ value in
|
||||
var value = value
|
||||
value.closedPeerSpecificPackSetup = true
|
||||
return value
|
||||
})
|
||||
} else {
|
||||
return current
|
||||
}
|
||||
let _ = ChatInterfaceState.update(engine: self.context.engine, peerId: peerId, threadId: nil, { current in
|
||||
return current.withUpdatedMessageActionsState({ value in
|
||||
var value = value
|
||||
value.closedPeerSpecificPackSetup = true
|
||||
return value
|
||||
})
|
||||
}).start()
|
||||
}
|
||||
|
||||
@ -15,7 +15,6 @@ import ChatInterfaceState
|
||||
|
||||
private var telegramUIDeclaredEncodables: Void = {
|
||||
declareEncodable(InAppNotificationSettings.self, f: { InAppNotificationSettings(decoder: $0) })
|
||||
declareEncodable(ChatInterfaceState.self, f: { ChatInterfaceState(decoder: $0) })
|
||||
declareEncodable(VideoLibraryMediaResource.self, f: { VideoLibraryMediaResource(decoder: $0) })
|
||||
declareEncodable(LocalFileVideoMediaResource.self, f: { LocalFileVideoMediaResource(decoder: $0) })
|
||||
declareEncodable(LocalFileGifMediaResource.self, f: { LocalFileGifMediaResource(decoder: $0) })
|
||||
|
||||
@ -222,14 +222,8 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
||||
}
|
||||
|
||||
if let textInputState = textInputState {
|
||||
let _ = (context.account.postbox.transaction({ transaction -> Void in
|
||||
transaction.updatePeerChatInterfaceState(peerId, update: { currentState in
|
||||
if let currentState = currentState as? ChatInterfaceState {
|
||||
return currentState.withUpdatedComposeInputState(textInputState)
|
||||
} else {
|
||||
return ChatInterfaceState().withUpdatedComposeInputState(textInputState)
|
||||
}
|
||||
})
|
||||
let _ = (ChatInterfaceState.update(engine: context.engine, peerId: peerId, threadId: nil, { currentState in
|
||||
return currentState.withUpdatedComposeInputState(textInputState)
|
||||
})
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
navigationController?.pushViewController(ChatControllerImpl(context: context, chatLocation: .peer(peerId)))
|
||||
|
||||
@ -5771,15 +5771,10 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
peerSelectionController.dismiss()
|
||||
}
|
||||
} else {
|
||||
let _ = (strongSelf.context.account.postbox.transaction({ transaction -> Void in
|
||||
transaction.updatePeerChatInterfaceState(peerId, update: { currentState in
|
||||
if let currentState = currentState as? ChatInterfaceState {
|
||||
return currentState.withUpdatedForwardMessageIds(Array(messageIds))
|
||||
} else {
|
||||
return ChatInterfaceState().withUpdatedForwardMessageIds(Array(messageIds))
|
||||
}
|
||||
})
|
||||
}) |> deliverOnMainQueue).start(completed: {
|
||||
let _ = (ChatInterfaceState.update(engine: strongSelf.context.engine, peerId: peerId, threadId: nil, { currentState in
|
||||
return currentState.withUpdatedForwardMessageIds(Array(messageIds))
|
||||
})
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
if let strongSelf = self {
|
||||
strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone)
|
||||
|
||||
|
||||
@ -12,15 +12,7 @@ import WallpaperResources
|
||||
import AppBundle
|
||||
import SwiftSignalKit
|
||||
|
||||
public let telegramAccountAuxiliaryMethods = AccountAuxiliaryMethods(updatePeerChatInputState: { interfaceState, inputState -> PeerChatInterfaceState? in
|
||||
if interfaceState == nil {
|
||||
return ChatInterfaceState().withUpdatedSynchronizeableInputState(inputState)
|
||||
} else if let interfaceState = interfaceState as? ChatInterfaceState {
|
||||
return interfaceState.withUpdatedSynchronizeableInputState(inputState)
|
||||
} else {
|
||||
return interfaceState
|
||||
}
|
||||
}, fetchResource: { account, resource, ranges, _ in
|
||||
public let telegramAccountAuxiliaryMethods = AccountAuxiliaryMethods(fetchResource: { account, resource, ranges, _ in
|
||||
if let resource = resource as? VideoLibraryMediaResource {
|
||||
return fetchVideoLibraryMediaResource(account: account, resource: resource)
|
||||
} else if let resource = resource as? LocalFileVideoMediaResource {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user