mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Search filters improvements
This commit is contained in:
parent
9ef16b1185
commit
4aada91da5
22
submodules/ChatInterfaceState/BUCK
Normal file
22
submodules/ChatInterfaceState/BUCK
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
load("//Config:buck_rule_macros.bzl", "static_library")
|
||||||
|
|
||||||
|
static_library(
|
||||||
|
name = "ChatInterfaceState",
|
||||||
|
srcs = glob([
|
||||||
|
"Sources/**/*.swift",
|
||||||
|
]),
|
||||||
|
deps = [
|
||||||
|
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared",
|
||||||
|
"//submodules/AsyncDisplayKit:AsyncDisplayKit#shared",
|
||||||
|
"//submodules/Display:Display#shared",
|
||||||
|
"//submodules/Postbox:Postbox#shared",
|
||||||
|
"//submodules/TelegramCore:TelegramCore#shared",
|
||||||
|
"//submodules/SyncCore:SyncCore#shared",
|
||||||
|
"//submodules/TextFormat:TextFormat",
|
||||||
|
"//submodules/AccountContext:AccountContext",
|
||||||
|
],
|
||||||
|
frameworks = [
|
||||||
|
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||||
|
"$SDKROOT/System/Library/Frameworks/UIKit.framework",
|
||||||
|
],
|
||||||
|
)
|
22
submodules/ChatInterfaceState/BUILD
Normal file
22
submodules/ChatInterfaceState/BUILD
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||||
|
|
||||||
|
swift_library(
|
||||||
|
name = "ChatInterfaceState",
|
||||||
|
module_name = "ChatInterfaceState",
|
||||||
|
srcs = glob([
|
||||||
|
"Sources/**/*.swift",
|
||||||
|
]),
|
||||||
|
deps = [
|
||||||
|
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||||
|
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||||
|
"//submodules/Display:Display",
|
||||||
|
"//submodules/Postbox:Postbox",
|
||||||
|
"//submodules/TelegramCore:TelegramCore",
|
||||||
|
"//submodules/SyncCore:SyncCore",
|
||||||
|
"//submodules/TextFormat:TextFormat",
|
||||||
|
"//submodules/AccountContext:AccountContext",
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
],
|
||||||
|
)
|
@ -6,18 +6,23 @@ import SyncCore
|
|||||||
import TextFormat
|
import TextFormat
|
||||||
import AccountContext
|
import AccountContext
|
||||||
|
|
||||||
struct ChatInterfaceSelectionState: PostboxCoding, Equatable {
|
public enum ChatTextInputMediaRecordingButtonMode: Int32 {
|
||||||
let selectedIds: Set<MessageId>
|
case audio = 0
|
||||||
|
case video = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ChatInterfaceSelectionState: PostboxCoding, Equatable {
|
||||||
|
public let selectedIds: Set<MessageId>
|
||||||
|
|
||||||
static func ==(lhs: ChatInterfaceSelectionState, rhs: ChatInterfaceSelectionState) -> Bool {
|
public static func ==(lhs: ChatInterfaceSelectionState, rhs: ChatInterfaceSelectionState) -> Bool {
|
||||||
return lhs.selectedIds == rhs.selectedIds
|
return lhs.selectedIds == rhs.selectedIds
|
||||||
}
|
}
|
||||||
|
|
||||||
init(selectedIds: Set<MessageId>) {
|
public init(selectedIds: Set<MessageId>) {
|
||||||
self.selectedIds = selectedIds
|
self.selectedIds = selectedIds
|
||||||
}
|
}
|
||||||
|
|
||||||
init(decoder: PostboxDecoder) {
|
public init(decoder: PostboxDecoder) {
|
||||||
if let data = decoder.decodeBytesForKeyNoCopy("i") {
|
if let data = decoder.decodeBytesForKeyNoCopy("i") {
|
||||||
self.selectedIds = Set(MessageId.decodeArrayFromBuffer(data))
|
self.selectedIds = Set(MessageId.decodeArrayFromBuffer(data))
|
||||||
} else {
|
} else {
|
||||||
@ -25,27 +30,27 @@ struct ChatInterfaceSelectionState: PostboxCoding, Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func encode(_ encoder: PostboxEncoder) {
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
let buffer = WriteBuffer()
|
let buffer = WriteBuffer()
|
||||||
MessageId.encodeArrayToBuffer(Array(selectedIds), buffer: buffer)
|
MessageId.encodeArrayToBuffer(Array(selectedIds), buffer: buffer)
|
||||||
encoder.encodeBytes(buffer, forKey: "i")
|
encoder.encodeBytes(buffer, forKey: "i")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ChatEditMessageState: PostboxCoding, Equatable {
|
public struct ChatEditMessageState: PostboxCoding, Equatable {
|
||||||
let messageId: MessageId
|
public let messageId: MessageId
|
||||||
let inputState: ChatTextInputState
|
public let inputState: ChatTextInputState
|
||||||
let disableUrlPreview: String?
|
public let disableUrlPreview: String?
|
||||||
let inputTextMaxLength: Int32?
|
public let inputTextMaxLength: Int32?
|
||||||
|
|
||||||
init(messageId: MessageId, inputState: ChatTextInputState, disableUrlPreview: String?, inputTextMaxLength: Int32?) {
|
public init(messageId: MessageId, inputState: ChatTextInputState, disableUrlPreview: String?, inputTextMaxLength: Int32?) {
|
||||||
self.messageId = messageId
|
self.messageId = messageId
|
||||||
self.inputState = inputState
|
self.inputState = inputState
|
||||||
self.disableUrlPreview = disableUrlPreview
|
self.disableUrlPreview = disableUrlPreview
|
||||||
self.inputTextMaxLength = inputTextMaxLength
|
self.inputTextMaxLength = inputTextMaxLength
|
||||||
}
|
}
|
||||||
|
|
||||||
init(decoder: PostboxDecoder) {
|
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))
|
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 {
|
if let inputState = decoder.decodeObjectForKey("is", decoder: { return ChatTextInputState(decoder: $0) }) as? ChatTextInputState {
|
||||||
self.inputState = inputState
|
self.inputState = inputState
|
||||||
@ -56,7 +61,7 @@ struct ChatEditMessageState: PostboxCoding, Equatable {
|
|||||||
self.inputTextMaxLength = decoder.decodeOptionalInt32ForKey("tl")
|
self.inputTextMaxLength = decoder.decodeOptionalInt32ForKey("tl")
|
||||||
}
|
}
|
||||||
|
|
||||||
func encode(_ encoder: PostboxEncoder) {
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
encoder.encodeInt64(self.messageId.peerId.toInt64(), forKey: "mp")
|
encoder.encodeInt64(self.messageId.peerId.toInt64(), forKey: "mp")
|
||||||
encoder.encodeInt32(self.messageId.namespace, forKey: "mn")
|
encoder.encodeInt32(self.messageId.namespace, forKey: "mn")
|
||||||
encoder.encodeInt32(self.messageId.id, forKey: "mi")
|
encoder.encodeInt32(self.messageId.id, forKey: "mi")
|
||||||
@ -73,31 +78,31 @@ struct ChatEditMessageState: PostboxCoding, Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func ==(lhs: ChatEditMessageState, rhs: ChatEditMessageState) -> Bool {
|
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
|
return lhs.messageId == rhs.messageId && lhs.inputState == rhs.inputState && lhs.disableUrlPreview == rhs.disableUrlPreview && lhs.inputTextMaxLength == rhs.inputTextMaxLength
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedInputState(_ inputState: ChatTextInputState) -> ChatEditMessageState {
|
public func withUpdatedInputState(_ inputState: ChatTextInputState) -> ChatEditMessageState {
|
||||||
return ChatEditMessageState(messageId: self.messageId, inputState: inputState, disableUrlPreview: self.disableUrlPreview, inputTextMaxLength: self.inputTextMaxLength)
|
return ChatEditMessageState(messageId: self.messageId, inputState: inputState, disableUrlPreview: self.disableUrlPreview, inputTextMaxLength: self.inputTextMaxLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedDisableUrlPreview(_ disableUrlPreview: String?) -> ChatEditMessageState {
|
public func withUpdatedDisableUrlPreview(_ disableUrlPreview: String?) -> ChatEditMessageState {
|
||||||
return ChatEditMessageState(messageId: self.messageId, inputState: self.inputState, disableUrlPreview: disableUrlPreview, inputTextMaxLength: self.inputTextMaxLength)
|
return ChatEditMessageState(messageId: self.messageId, inputState: self.inputState, disableUrlPreview: disableUrlPreview, inputTextMaxLength: self.inputTextMaxLength)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
public struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
||||||
var closedButtonKeyboardMessageId: MessageId?
|
public var closedButtonKeyboardMessageId: MessageId?
|
||||||
var processedSetupReplyMessageId: MessageId?
|
public var processedSetupReplyMessageId: MessageId?
|
||||||
var closedPinnedMessageId: MessageId?
|
public var closedPinnedMessageId: MessageId?
|
||||||
var closedPeerSpecificPackSetup: Bool = false
|
public var closedPeerSpecificPackSetup: Bool = false
|
||||||
var dismissedAddContactPhoneNumber: String?
|
public var dismissedAddContactPhoneNumber: String?
|
||||||
|
|
||||||
var isEmpty: Bool {
|
public var isEmpty: Bool {
|
||||||
return self.closedButtonKeyboardMessageId == nil && self.processedSetupReplyMessageId == nil && self.closedPinnedMessageId == nil && self.closedPeerSpecificPackSetup == false && self.dismissedAddContactPhoneNumber == nil
|
return self.closedButtonKeyboardMessageId == nil && self.processedSetupReplyMessageId == nil && self.closedPinnedMessageId == nil && self.closedPeerSpecificPackSetup == false && self.dismissedAddContactPhoneNumber == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
public init() {
|
||||||
self.closedButtonKeyboardMessageId = nil
|
self.closedButtonKeyboardMessageId = nil
|
||||||
self.processedSetupReplyMessageId = nil
|
self.processedSetupReplyMessageId = nil
|
||||||
self.closedPinnedMessageId = nil
|
self.closedPinnedMessageId = nil
|
||||||
@ -105,7 +110,7 @@ struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
|||||||
self.dismissedAddContactPhoneNumber = nil
|
self.dismissedAddContactPhoneNumber = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
init(closedButtonKeyboardMessageId: MessageId?, processedSetupReplyMessageId: MessageId?, closedPinnedMessageId: MessageId?, closedPeerSpecificPackSetup: Bool, dismissedAddContactPhoneNumber: String?) {
|
public init(closedButtonKeyboardMessageId: MessageId?, processedSetupReplyMessageId: MessageId?, closedPinnedMessageId: MessageId?, closedPeerSpecificPackSetup: Bool, dismissedAddContactPhoneNumber: String?) {
|
||||||
self.closedButtonKeyboardMessageId = closedButtonKeyboardMessageId
|
self.closedButtonKeyboardMessageId = closedButtonKeyboardMessageId
|
||||||
self.processedSetupReplyMessageId = processedSetupReplyMessageId
|
self.processedSetupReplyMessageId = processedSetupReplyMessageId
|
||||||
self.closedPinnedMessageId = closedPinnedMessageId
|
self.closedPinnedMessageId = closedPinnedMessageId
|
||||||
@ -113,7 +118,7 @@ struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
|||||||
self.dismissedAddContactPhoneNumber = dismissedAddContactPhoneNumber
|
self.dismissedAddContactPhoneNumber = dismissedAddContactPhoneNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
init(decoder: PostboxDecoder) {
|
public init(decoder: PostboxDecoder) {
|
||||||
if let closedMessageIdPeerId = decoder.decodeOptionalInt64ForKey("cb.p"), let closedMessageIdNamespace = decoder.decodeOptionalInt32ForKey("cb.n"), let closedMessageIdId = decoder.decodeOptionalInt32ForKey("cb.i") {
|
if let closedMessageIdPeerId = decoder.decodeOptionalInt64ForKey("cb.p"), let closedMessageIdNamespace = decoder.decodeOptionalInt32ForKey("cb.n"), let closedMessageIdId = decoder.decodeOptionalInt32ForKey("cb.i") {
|
||||||
self.closedButtonKeyboardMessageId = MessageId(peerId: PeerId(closedMessageIdPeerId), namespace: closedMessageIdNamespace, id: closedMessageIdId)
|
self.closedButtonKeyboardMessageId = MessageId(peerId: PeerId(closedMessageIdPeerId), namespace: closedMessageIdNamespace, id: closedMessageIdId)
|
||||||
} else {
|
} else {
|
||||||
@ -135,7 +140,7 @@ struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
|||||||
self.closedPeerSpecificPackSetup = decoder.decodeInt32ForKey("cpss", orElse: 0) != 0
|
self.closedPeerSpecificPackSetup = decoder.decodeInt32ForKey("cpss", orElse: 0) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func encode(_ encoder: PostboxEncoder) {
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
if let closedButtonKeyboardMessageId = self.closedButtonKeyboardMessageId {
|
if let closedButtonKeyboardMessageId = self.closedButtonKeyboardMessageId {
|
||||||
encoder.encodeInt64(closedButtonKeyboardMessageId.peerId.toInt64(), forKey: "cb.p")
|
encoder.encodeInt64(closedButtonKeyboardMessageId.peerId.toInt64(), forKey: "cb.p")
|
||||||
encoder.encodeInt32(closedButtonKeyboardMessageId.namespace, forKey: "cb.n")
|
encoder.encodeInt32(closedButtonKeyboardMessageId.namespace, forKey: "cb.n")
|
||||||
@ -176,21 +181,21 @@ struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ChatInterfaceHistoryScrollState: PostboxCoding, Equatable {
|
public struct ChatInterfaceHistoryScrollState: PostboxCoding, Equatable {
|
||||||
let messageIndex: MessageIndex
|
public let messageIndex: MessageIndex
|
||||||
let relativeOffset: Double
|
public let relativeOffset: Double
|
||||||
|
|
||||||
init(messageIndex: MessageIndex, relativeOffset: Double) {
|
public init(messageIndex: MessageIndex, relativeOffset: Double) {
|
||||||
self.messageIndex = messageIndex
|
self.messageIndex = messageIndex
|
||||||
self.relativeOffset = relativeOffset
|
self.relativeOffset = relativeOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
init(decoder: PostboxDecoder) {
|
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.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)
|
self.relativeOffset = decoder.decodeDoubleForKey("ro", orElse: 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func encode(_ encoder: PostboxEncoder) {
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
encoder.encodeInt32(self.messageIndex.timestamp, forKey: "m.t")
|
encoder.encodeInt32(self.messageIndex.timestamp, forKey: "m.t")
|
||||||
encoder.encodeInt64(self.messageIndex.id.peerId.toInt64(), forKey: "m.p")
|
encoder.encodeInt64(self.messageIndex.id.peerId.toInt64(), forKey: "m.p")
|
||||||
encoder.encodeInt32(self.messageIndex.id.namespace, forKey: "m.n")
|
encoder.encodeInt32(self.messageIndex.id.namespace, forKey: "m.n")
|
||||||
@ -198,7 +203,7 @@ struct ChatInterfaceHistoryScrollState: PostboxCoding, Equatable {
|
|||||||
encoder.encodeDouble(self.relativeOffset, forKey: "ro")
|
encoder.encodeDouble(self.relativeOffset, forKey: "ro")
|
||||||
}
|
}
|
||||||
|
|
||||||
static func ==(lhs: ChatInterfaceHistoryScrollState, rhs: ChatInterfaceHistoryScrollState) -> Bool {
|
public static func ==(lhs: ChatInterfaceHistoryScrollState, rhs: ChatInterfaceHistoryScrollState) -> Bool {
|
||||||
if lhs.messageIndex != rhs.messageIndex {
|
if lhs.messageIndex != rhs.messageIndex {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -210,18 +215,18 @@ struct ChatInterfaceHistoryScrollState: PostboxCoding, Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equatable {
|
public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equatable {
|
||||||
let timestamp: Int32
|
public let timestamp: Int32
|
||||||
let composeInputState: ChatTextInputState
|
public let composeInputState: ChatTextInputState
|
||||||
let composeDisableUrlPreview: String?
|
public let composeDisableUrlPreview: String?
|
||||||
let replyMessageId: MessageId?
|
public let replyMessageId: MessageId?
|
||||||
let forwardMessageIds: [MessageId]?
|
public let forwardMessageIds: [MessageId]?
|
||||||
let editMessage: ChatEditMessageState?
|
public let editMessage: ChatEditMessageState?
|
||||||
let selectionState: ChatInterfaceSelectionState?
|
public let selectionState: ChatInterfaceSelectionState?
|
||||||
let messageActionsState: ChatInterfaceMessageActionsState
|
public let messageActionsState: ChatInterfaceMessageActionsState
|
||||||
let historyScrollState: ChatInterfaceHistoryScrollState?
|
public let historyScrollState: ChatInterfaceHistoryScrollState?
|
||||||
let mediaRecordingMode: ChatTextInputMediaRecordingButtonMode
|
public let mediaRecordingMode: ChatTextInputMediaRecordingButtonMode
|
||||||
let silentPosting: Bool
|
public let silentPosting: Bool
|
||||||
let inputLanguage: String?
|
public let inputLanguage: String?
|
||||||
|
|
||||||
public var associatedMessageIds: [MessageId] {
|
public var associatedMessageIds: [MessageId] {
|
||||||
var ids: [MessageId] = []
|
var ids: [MessageId] = []
|
||||||
@ -259,7 +264,7 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
var effectiveInputState: ChatTextInputState {
|
public var effectiveInputState: ChatTextInputState {
|
||||||
if let editMessage = self.editMessage {
|
if let editMessage = self.editMessage {
|
||||||
return editMessage.inputState
|
return editMessage.inputState
|
||||||
} else {
|
} else {
|
||||||
@ -282,7 +287,7 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
|||||||
self.inputLanguage = nil
|
self.inputLanguage = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
init(timestamp: Int32, composeInputState: ChatTextInputState, composeDisableUrlPreview: String?, replyMessageId: MessageId?, forwardMessageIds: [MessageId]?, editMessage: ChatEditMessageState?, selectionState: ChatInterfaceSelectionState?, messageActionsState: ChatInterfaceMessageActionsState, historyScrollState: ChatInterfaceHistoryScrollState?, mediaRecordingMode: ChatTextInputMediaRecordingButtonMode, silentPosting: Bool, inputLanguage: String?) {
|
public init(timestamp: Int32, composeInputState: ChatTextInputState, composeDisableUrlPreview: String?, replyMessageId: MessageId?, forwardMessageIds: [MessageId]?, editMessage: ChatEditMessageState?, selectionState: ChatInterfaceSelectionState?, messageActionsState: ChatInterfaceMessageActionsState, historyScrollState: ChatInterfaceHistoryScrollState?, mediaRecordingMode: ChatTextInputMediaRecordingButtonMode, silentPosting: Bool, inputLanguage: String?) {
|
||||||
self.timestamp = timestamp
|
self.timestamp = timestamp
|
||||||
self.composeInputState = composeInputState
|
self.composeInputState = composeInputState
|
||||||
self.composeDisableUrlPreview = composeDisableUrlPreview
|
self.composeDisableUrlPreview = composeDisableUrlPreview
|
||||||
@ -437,17 +442,17 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
|||||||
return lhs.composeInputState == rhs.composeInputState && lhs.replyMessageId == rhs.replyMessageId && lhs.selectionState == rhs.selectionState && lhs.editMessage == rhs.editMessage
|
return lhs.composeInputState == rhs.composeInputState && lhs.replyMessageId == rhs.replyMessageId && lhs.selectionState == rhs.selectionState && lhs.editMessage == rhs.editMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedComposeInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
|
public func withUpdatedComposeInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
|
||||||
let updatedComposeInputState = inputState
|
let updatedComposeInputState = inputState
|
||||||
|
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, 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: self.inputLanguage)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, 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: self.inputLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedComposeDisableUrlPreview(_ disableUrlPreview: String?) -> ChatInterfaceState {
|
public func withUpdatedComposeDisableUrlPreview(_ disableUrlPreview: String?) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: disableUrlPreview, 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: self.inputLanguage)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: disableUrlPreview, 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: self.inputLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedEffectiveInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
|
public func withUpdatedEffectiveInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
|
||||||
var updatedEditMessage = self.editMessage
|
var updatedEditMessage = self.editMessage
|
||||||
var updatedComposeInputState = self.composeInputState
|
var updatedComposeInputState = self.composeInputState
|
||||||
if let editMessage = self.editMessage {
|
if let editMessage = self.editMessage {
|
||||||
@ -459,15 +464,15 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
|||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: updatedEditMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: updatedEditMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedReplyMessageId(_ replyMessageId: MessageId?) -> ChatInterfaceState {
|
public func withUpdatedReplyMessageId(_ replyMessageId: MessageId?) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedForwardMessageIds(_ forwardMessageIds: [MessageId]?) -> ChatInterfaceState {
|
public func withUpdatedForwardMessageIds(_ forwardMessageIds: [MessageId]?) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedSelectedMessages(_ messageIds: [MessageId]) -> ChatInterfaceState {
|
public func withUpdatedSelectedMessages(_ messageIds: [MessageId]) -> ChatInterfaceState {
|
||||||
var selectedIds = Set<MessageId>()
|
var selectedIds = Set<MessageId>()
|
||||||
if let selectionState = self.selectionState {
|
if let selectionState = self.selectionState {
|
||||||
selectedIds.formUnion(selectionState.selectedIds)
|
selectedIds.formUnion(selectionState.selectedIds)
|
||||||
@ -478,7 +483,7 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
|||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withToggledSelectedMessages(_ messageIds: [MessageId], value: Bool) -> ChatInterfaceState {
|
public func withToggledSelectedMessages(_ messageIds: [MessageId], value: Bool) -> ChatInterfaceState {
|
||||||
var selectedIds = Set<MessageId>()
|
var selectedIds = Set<MessageId>()
|
||||||
if let selectionState = self.selectionState {
|
if let selectionState = self.selectionState {
|
||||||
selectedIds.formUnion(selectionState.selectedIds)
|
selectedIds.formUnion(selectionState.selectedIds)
|
||||||
@ -493,27 +498,27 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
|||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withoutSelectionState() -> ChatInterfaceState {
|
public func withoutSelectionState() -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: nil, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: nil, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedTimestamp(_ timestamp: Int32) -> ChatInterfaceState {
|
public func withUpdatedTimestamp(_ timestamp: Int32) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: 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: self.inputLanguage)
|
return ChatInterfaceState(timestamp: 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: self.inputLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedEditMessage(_ editMessage: ChatEditMessageState?) -> ChatInterfaceState {
|
public func withUpdatedEditMessage(_ editMessage: ChatEditMessageState?) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedMessageActionsState(_ f: (ChatInterfaceMessageActionsState) -> ChatInterfaceMessageActionsState) -> ChatInterfaceState {
|
public func withUpdatedMessageActionsState(_ f: (ChatInterfaceMessageActionsState) -> ChatInterfaceMessageActionsState) -> 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: f(self.messageActionsState), historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: f(self.messageActionsState), historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedHistoryScrollState(_ historyScrollState: ChatInterfaceHistoryScrollState?) -> ChatInterfaceState {
|
public func withUpdatedHistoryScrollState(_ historyScrollState: ChatInterfaceHistoryScrollState?) -> 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: historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
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: historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedMediaRecordingMode(_ mediaRecordingMode: ChatTextInputMediaRecordingButtonMode) -> ChatInterfaceState {
|
public func withUpdatedMediaRecordingMode(_ mediaRecordingMode: ChatTextInputMediaRecordingButtonMode) -> 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: mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
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: mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage)
|
||||||
}
|
}
|
||||||
|
|
@ -53,6 +53,7 @@ static_library(
|
|||||||
"//submodules/GalleryData:GalleryData",
|
"//submodules/GalleryData:GalleryData",
|
||||||
"//submodules/InstantPageUI:InstantPageUI",
|
"//submodules/InstantPageUI:InstantPageUI",
|
||||||
"//submodules/ListSectionHeaderNode:ListSectionHeaderNode",
|
"//submodules/ListSectionHeaderNode:ListSectionHeaderNode",
|
||||||
|
"//submodules/ChatInterfaceState:ChatInterfaceState",
|
||||||
],
|
],
|
||||||
frameworks = [
|
frameworks = [
|
||||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||||
|
@ -52,6 +52,8 @@ swift_library(
|
|||||||
"//submodules/GalleryData:GalleryData",
|
"//submodules/GalleryData:GalleryData",
|
||||||
"//submodules/InstantPageUI:InstantPageUI",
|
"//submodules/InstantPageUI:InstantPageUI",
|
||||||
"//submodules/ListSectionHeaderNode:ListSectionHeaderNode",
|
"//submodules/ListSectionHeaderNode:ListSectionHeaderNode",
|
||||||
|
"//submodules/ChatInterfaceState:ChatInterfaceState",
|
||||||
|
"//submodules/ShareController:ShareController",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -27,6 +27,8 @@ import AnimatedStickerNode
|
|||||||
import AppBundle
|
import AppBundle
|
||||||
import GalleryData
|
import GalleryData
|
||||||
import InstantPageUI
|
import InstantPageUI
|
||||||
|
import ChatInterfaceState
|
||||||
|
import ShareController
|
||||||
|
|
||||||
private final class PassthroughContainerNode: ASDisplayNode {
|
private final class PassthroughContainerNode: ASDisplayNode {
|
||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
@ -595,20 +597,26 @@ public func chatListSearchContainerPreparedTransition(from fromEntries: [ChatLis
|
|||||||
|
|
||||||
private struct ChatListSearchContainerNodeState: Equatable {
|
private struct ChatListSearchContainerNodeState: Equatable {
|
||||||
let peerIdWithRevealedOptions: PeerId?
|
let peerIdWithRevealedOptions: PeerId?
|
||||||
|
let selectedMessageIds: Set<MessageId>?
|
||||||
|
|
||||||
init(peerIdWithRevealedOptions: PeerId? = nil) {
|
init(peerIdWithRevealedOptions: PeerId? = nil, selectedMessageIds: Set<MessageId>? = nil) {
|
||||||
self.peerIdWithRevealedOptions = peerIdWithRevealedOptions
|
self.peerIdWithRevealedOptions = peerIdWithRevealedOptions
|
||||||
|
self.selectedMessageIds = selectedMessageIds
|
||||||
}
|
}
|
||||||
|
|
||||||
static func ==(lhs: ChatListSearchContainerNodeState, rhs: ChatListSearchContainerNodeState) -> Bool {
|
static func ==(lhs: ChatListSearchContainerNodeState, rhs: ChatListSearchContainerNodeState) -> Bool {
|
||||||
if lhs.peerIdWithRevealedOptions != rhs.peerIdWithRevealedOptions {
|
if lhs.peerIdWithRevealedOptions != rhs.peerIdWithRevealedOptions || lhs.selectedMessageIds != rhs.selectedMessageIds {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedPeerIdWithRevealedOptions(_ peerIdWithRevealedOptions: PeerId?) -> ChatListSearchContainerNodeState {
|
func withUpdatedPeerIdWithRevealedOptions(_ peerIdWithRevealedOptions: PeerId?) -> ChatListSearchContainerNodeState {
|
||||||
return ChatListSearchContainerNodeState(peerIdWithRevealedOptions: peerIdWithRevealedOptions)
|
return ChatListSearchContainerNodeState(peerIdWithRevealedOptions: peerIdWithRevealedOptions, selectedMessageIds: self.selectedMessageIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
func withUpdatedSelectedMessageIds(_ selectedMessageIds: Set<MessageId>?) -> ChatListSearchContainerNodeState {
|
||||||
|
return ChatListSearchContainerNodeState(peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, selectedMessageIds: selectedMessageIds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -681,12 +689,13 @@ public struct ChatListSearchOptions {
|
|||||||
|
|
||||||
public final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
|
public final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let filter: ChatListNodePeersFilter
|
private let peersFilter: ChatListNodePeersFilter
|
||||||
private var interaction: ChatListNodeInteraction?
|
private var interaction: ChatListNodeInteraction?
|
||||||
private let openMessage: (Peer, MessageId) -> Void
|
private let openMessage: (Peer, MessageId) -> Void
|
||||||
private let navigationController: NavigationController?
|
private let navigationController: NavigationController?
|
||||||
|
|
||||||
let filterContainerNode: ChatListSearchFiltersContainerNode
|
let filterContainerNode: ChatListSearchFiltersContainerNode
|
||||||
|
private var selectionPanelNode: ChatListSearchMessageSelectionPanelNode?
|
||||||
private let recentListNode: ListView
|
private let recentListNode: ListView
|
||||||
private let listNode: ListView
|
private let listNode: ListView
|
||||||
private let mediaNode: ChatListSearchMediaNode
|
private let mediaNode: ChatListSearchMediaNode
|
||||||
@ -695,8 +704,11 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
private var enqueuedTransitions: [(ChatListSearchContainerTransition, Bool)] = []
|
private var enqueuedTransitions: [(ChatListSearchContainerTransition, Bool)] = []
|
||||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||||
|
|
||||||
|
private var present: ((ViewController, Any?) -> Void)?
|
||||||
private var presentInGlobalOverlay: ((ViewController, Any?) -> Void)?
|
private var presentInGlobalOverlay: ((ViewController, Any?) -> Void)?
|
||||||
|
|
||||||
|
private let activeActionDisposable = MetaDisposable()
|
||||||
|
|
||||||
private let recentDisposable = MetaDisposable()
|
private let recentDisposable = MetaDisposable()
|
||||||
private let updatedRecentPeersDisposable = MetaDisposable()
|
private let updatedRecentPeersDisposable = MetaDisposable()
|
||||||
|
|
||||||
@ -738,11 +750,12 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
|
|
||||||
public init(context: AccountContext, filter: ChatListNodePeersFilter, groupId: PeerGroupId, openPeer originalOpenPeer: @escaping (Peer, Bool) -> Void, openDisabledPeer: @escaping (Peer) -> Void, openRecentPeerOptions: @escaping (Peer) -> Void, openMessage originalOpenMessage: @escaping (Peer, MessageId) -> Void, addContact: ((String) -> Void)?, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void, navigationController: NavigationController?, updatedSearchOptions: ((ChatListSearchOptions?) -> Void)? = nil) {
|
public init(context: AccountContext, filter: ChatListNodePeersFilter, groupId: PeerGroupId, openPeer originalOpenPeer: @escaping (Peer, Bool) -> Void, openDisabledPeer: @escaping (Peer) -> Void, openRecentPeerOptions: @escaping (Peer) -> Void, openMessage originalOpenMessage: @escaping (Peer, MessageId) -> Void, addContact: ((String) -> Void)?, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void, navigationController: NavigationController?, updatedSearchOptions: ((ChatListSearchOptions?) -> Void)? = nil) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.filter = filter
|
self.peersFilter = filter
|
||||||
self.dimNode = ASDisplayNode()
|
self.dimNode = ASDisplayNode()
|
||||||
self.navigationController = navigationController
|
self.navigationController = navigationController
|
||||||
self.updatedSearchOptions = updatedSearchOptions
|
self.updatedSearchOptions = updatedSearchOptions
|
||||||
|
|
||||||
|
self.present = present
|
||||||
self.presentInGlobalOverlay = presentInGlobalOverlay
|
self.presentInGlobalOverlay = presentInGlobalOverlay
|
||||||
|
|
||||||
self.openMessage = originalOpenMessage
|
self.openMessage = originalOpenMessage
|
||||||
@ -1475,7 +1488,11 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
strongSelf.mediaNode.updateHistory(entries: entriesAndFlags?.0 ?? [], totalCount: totalCount, updateType: .Initial)
|
var entries: [ChatListSearchEntry]? = entriesAndFlags?.0 ?? []
|
||||||
|
if isSearching && (entries?.isEmpty ?? true) {
|
||||||
|
entries = nil
|
||||||
|
}
|
||||||
|
strongSelf.mediaNode.updateHistory(entries: entries, totalCount: totalCount, updateType: .Initial)
|
||||||
}
|
}
|
||||||
|
|
||||||
let previousEntries = previousSearchItems.swap(entriesAndFlags?.0)
|
let previousEntries = previousSearchItems.swap(entriesAndFlags?.0)
|
||||||
@ -1621,6 +1638,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
|
self.activeActionDisposable.dispose()
|
||||||
self.updatedRecentPeersDisposable.dispose()
|
self.updatedRecentPeersDisposable.dispose()
|
||||||
self.recentDisposable.dispose()
|
self.recentDisposable.dispose()
|
||||||
self.searchDisposable.dispose()
|
self.searchDisposable.dispose()
|
||||||
@ -1701,8 +1719,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateTheme(theme: PresentationTheme) {
|
private func updateTheme(theme: PresentationTheme) {
|
||||||
self.backgroundColor = self.filter.contains(.excludeRecent) ? nil : theme.chatList.backgroundColor
|
self.backgroundColor = self.peersFilter.contains(.excludeRecent) ? nil : theme.chatList.backgroundColor
|
||||||
self.dimNode.backgroundColor = self.filter.contains(.excludeRecent) ? UIColor.black.withAlphaComponent(0.5) : theme.chatList.backgroundColor
|
self.dimNode.backgroundColor = self.peersFilter.contains(.excludeRecent) ? UIColor.black.withAlphaComponent(0.5) : theme.chatList.backgroundColor
|
||||||
self.recentListNode.verticalScrollIndicatorColor = theme.list.scrollIndicatorColor
|
self.recentListNode.verticalScrollIndicatorColor = theme.list.scrollIndicatorColor
|
||||||
self.listNode.verticalScrollIndicatorColor = theme.list.scrollIndicatorColor
|
self.listNode.verticalScrollIndicatorColor = theme.list.scrollIndicatorColor
|
||||||
|
|
||||||
@ -1811,9 +1829,9 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
strongSelf.emptyResultsTextNode.isHidden = !emptyResults
|
strongSelf.emptyResultsTextNode.isHidden = !emptyResults
|
||||||
strongSelf.emptyResultsAnimationNode.visibility = emptyResults
|
strongSelf.emptyResultsAnimationNode.visibility = emptyResults
|
||||||
|
|
||||||
strongSelf.recentListNode.isHidden = displayingResults || strongSelf.filter.contains(.excludeRecent)
|
strongSelf.recentListNode.isHidden = displayingResults || strongSelf.peersFilter.contains(.excludeRecent)
|
||||||
strongSelf.dimNode.isHidden = displayingResults
|
strongSelf.dimNode.isHidden = displayingResults
|
||||||
strongSelf.backgroundColor = !displayingResults && strongSelf.filter.contains(.excludeRecent) ? nil : strongSelf.presentationData.theme.chatList.backgroundColor
|
strongSelf.backgroundColor = !displayingResults && strongSelf.peersFilter.contains(.excludeRecent) ? nil : strongSelf.presentationData.theme.chatList.backgroundColor
|
||||||
|
|
||||||
if let (layout, navigationBarHeight) = strongSelf.validLayout {
|
if let (layout, navigationBarHeight) = strongSelf.validLayout {
|
||||||
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||||
@ -2036,6 +2054,66 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
transition.updateFrame(node: self.filterContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: navigationBarHeight + 6.0), size: CGSize(width: layout.size.width, height: 37.0)))
|
transition.updateFrame(node: self.filterContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: navigationBarHeight + 6.0), size: CGSize(width: layout.size.width, height: 37.0)))
|
||||||
self.filterContainerNode.update(size: CGSize(width: layout.size.width, height: 37.0), sideInset: layout.safeInsets.left, filters: ChatListSearchFilter.allCases.map { .filter($0) }, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring))
|
self.filterContainerNode.update(size: CGSize(width: layout.size.width, height: 37.0), sideInset: layout.safeInsets.left, filters: ChatListSearchFilter.allCases.map { .filter($0) }, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring))
|
||||||
|
|
||||||
|
|
||||||
|
if let selectedMessageIds = self.stateValue.selectedMessageIds {
|
||||||
|
var wasAdded = false
|
||||||
|
let selectionPanelNode: ChatListSearchMessageSelectionPanelNode
|
||||||
|
if let current = self.selectionPanelNode {
|
||||||
|
selectionPanelNode = current
|
||||||
|
} else {
|
||||||
|
wasAdded = true
|
||||||
|
selectionPanelNode = ChatListSearchMessageSelectionPanelNode(context: self.context, deleteMessages: { [weak self] in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.deleteMessages(messageIds: nil)
|
||||||
|
}, shareMessages: { [weak self] in
|
||||||
|
guard let strongSelf = self, let messageIds = strongSelf.stateValue.selectedMessageIds, !messageIds.isEmpty else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Message] in
|
||||||
|
var messages: [Message] = []
|
||||||
|
for id in messageIds {
|
||||||
|
if let message = transaction.getMessage(id) {
|
||||||
|
messages.append(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return messages
|
||||||
|
}
|
||||||
|
|> deliverOnMainQueue).start(next: { messages in
|
||||||
|
if let strongSelf = self, !messages.isEmpty {
|
||||||
|
let shareController = ShareController(context: strongSelf.context, subject: .messages(messages.sorted(by: { lhs, rhs in
|
||||||
|
return lhs.index < rhs.index
|
||||||
|
})), externalShare: true, immediateExternalShare: true)
|
||||||
|
strongSelf.view.endEditing(true)
|
||||||
|
strongSelf.present?(shareController, nil)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, forwardMessages: { [weak self] in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.forwardMessages(messageIds: nil)
|
||||||
|
})
|
||||||
|
self.selectionPanelNode = selectionPanelNode
|
||||||
|
self.addSubnode(selectionPanelNode)
|
||||||
|
}
|
||||||
|
selectionPanelNode.selectedMessages = selectedMessageIds
|
||||||
|
let panelHeight = selectionPanelNode.update(layout: layout, presentationData: self.presentationData, transition: wasAdded ? .immediate : transition)
|
||||||
|
let panelFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - panelHeight), size: CGSize(width: layout.size.width, height: panelHeight))
|
||||||
|
if wasAdded {
|
||||||
|
selectionPanelNode.frame = panelFrame
|
||||||
|
transition.animatePositionAdditive(node: selectionPanelNode, offset: CGPoint(x: 0.0, y: panelHeight))
|
||||||
|
} else {
|
||||||
|
transition.updateFrame(node: selectionPanelNode, frame: panelFrame)
|
||||||
|
}
|
||||||
|
} else if let selectionPanelNode = self.selectionPanelNode {
|
||||||
|
self.selectionPanelNode = nil
|
||||||
|
transition.updateFrame(node: selectionPanelNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height), size: selectionPanelNode.bounds.size), completion: { [weak selectionPanelNode] _ in
|
||||||
|
selectionPanelNode?.removeFromSupernode()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition)
|
let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition)
|
||||||
|
|
||||||
self.recentListNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
self.recentListNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||||
@ -2180,15 +2258,18 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
items.append(.action(ContextMenuActionItem(text: strings.Conversation_ContextMenuMore, icon: { theme in
|
items.append(.action(ContextMenuActionItem(text: strings.Conversation_ContextMenuMore, icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/More"), color: theme.actionSheet.primaryTextColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/More"), color: theme.actionSheet.primaryTextColor)
|
||||||
}, action: { _, f in
|
}, action: { _, f in
|
||||||
guard let strongSelf = self else {
|
if let strongSelf = self {
|
||||||
return
|
strongSelf.updateState { state in
|
||||||
|
return state.withUpdatedSelectedMessageIds([message.id])
|
||||||
|
}
|
||||||
|
|
||||||
|
if let (layout, navigationBarHeight) = strongSelf.validLayout {
|
||||||
|
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// strongSelf.chatInterfaceInteraction.toggleMessagesSelection([message.id], true)
|
|
||||||
// strongSelf.expandTabs()
|
|
||||||
f(.default)
|
f(.default)
|
||||||
})))
|
})))
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
switch previewData {
|
switch previewData {
|
||||||
case let .gallery(gallery):
|
case let .gallery(gallery):
|
||||||
@ -2245,12 +2326,17 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
})))
|
})))
|
||||||
|
|
||||||
items.append(.separator)
|
items.append(.separator)
|
||||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuMore, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/More"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuMore, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/More"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||||
c.dismiss(completion: {
|
c.dismiss(completion: {
|
||||||
// if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
// strongSelf.chatInterfaceInteraction.toggleMessagesSelection([message.id], true)
|
strongSelf.updateState { state in
|
||||||
// strongSelf.expandTabs()
|
return state.withUpdatedSelectedMessageIds([message.id])
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
if let (layout, navigationBarHeight) = strongSelf.validLayout {
|
||||||
|
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})))
|
})))
|
||||||
|
|
||||||
@ -2262,74 +2348,83 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
self.updateSearchOptions(nil)
|
self.updateSearchOptions(nil)
|
||||||
self.setQuery?(nil, [], self.searchQueryValue ?? "")
|
self.setQuery?(nil, [], self.searchQueryValue ?? "")
|
||||||
}
|
}
|
||||||
|
func deleteMessages(messageIds: Set<MessageId>?) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func forwardMessages(messageIds: Set<MessageId>?) {
|
func forwardMessages(messageIds: Set<MessageId>?) {
|
||||||
// if let messageIds = messageIds, !messageIds.isEmpty {
|
if let messageIds = messageIds, !messageIds.isEmpty {
|
||||||
// let peerSelectionController = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: [.onlyWriteable, .excludeDisabled]))
|
let peerSelectionController = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: [.onlyWriteable, .excludeDisabled]))
|
||||||
// peerSelectionController.peerSelected = { [weak self, weak peerSelectionController] peerId in
|
peerSelectionController.peerSelected = { [weak self, weak peerSelectionController] peerId in
|
||||||
// if let strongSelf = self, let _ = peerSelectionController {
|
if let strongSelf = self, let _ = peerSelectionController {
|
||||||
// if peerId == strongSelf.context.account.peerId {
|
if peerId == strongSelf.context.account.peerId {
|
||||||
//// strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone)
|
// strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone)
|
||||||
//
|
|
||||||
// let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: messageIds.map { id -> EnqueueMessage in
|
let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: messageIds.map { id -> EnqueueMessage in
|
||||||
// return .forward(source: id, grouping: .auto, attributes: [])
|
return .forward(source: id, grouping: .auto, attributes: [])
|
||||||
// })
|
})
|
||||||
// |> deliverOnMainQueue).start(next: { [weak self] messageIds in
|
|> deliverOnMainQueue).start(next: { [weak self] messageIds in
|
||||||
// if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
// let signals: [Signal<Bool, NoError>] = messageIds.compactMap({ id -> Signal<Bool, NoError>? in
|
let signals: [Signal<Bool, NoError>] = messageIds.compactMap({ id -> Signal<Bool, NoError>? in
|
||||||
// guard let id = id else {
|
guard let id = id else {
|
||||||
// return nil
|
return nil
|
||||||
// }
|
}
|
||||||
// return strongSelf.context.account.pendingMessageManager.pendingMessageStatus(id)
|
return strongSelf.context.account.pendingMessageManager.pendingMessageStatus(id)
|
||||||
// |> mapToSignal { status, _ -> Signal<Bool, NoError> in
|
|> mapToSignal { status, _ -> Signal<Bool, NoError> in
|
||||||
// if status != nil {
|
if status != nil {
|
||||||
// return .never()
|
return .never()
|
||||||
// } else {
|
} else {
|
||||||
// return .single(true)
|
return .single(true)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// |> take(1)
|
|> take(1)
|
||||||
// })
|
})
|
||||||
// strongSelf.activeActionDisposable.set((combineLatest(signals)
|
strongSelf.activeActionDisposable.set((combineLatest(signals)
|
||||||
// |> deliverOnMainQueue).start(completed: {
|
|> deliverOnMainQueue).start(completed: {
|
||||||
// guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
// strongSelf.controller?.present(OverlayStatusController(theme: strongSelf.presentationData.theme, type: .success), in: .window(.root))
|
strongSelf.present?(OverlayStatusController(theme: strongSelf.presentationData.theme, type: .success), nil)
|
||||||
// }))
|
}))
|
||||||
// }
|
}
|
||||||
// })
|
})
|
||||||
// if let peerSelectionController = peerSelectionController {
|
if let peerSelectionController = peerSelectionController {
|
||||||
// peerSelectionController.dismiss()
|
peerSelectionController.dismiss()
|
||||||
// }
|
}
|
||||||
// } else {
|
} else {
|
||||||
// let _ = (strongSelf.context.account.postbox.transaction({ transaction -> Void in
|
let _ = (strongSelf.context.account.postbox.transaction({ transaction -> Void in
|
||||||
// transaction.updatePeerChatInterfaceState(peerId, update: { currentState in
|
transaction.updatePeerChatInterfaceState(peerId, update: { currentState in
|
||||||
// if let currentState = currentState as? ChatInterfaceState {
|
if let currentState = currentState as? ChatInterfaceState {
|
||||||
// return currentState.withUpdatedForwardMessageIds(Array(messageIds))
|
return currentState.withUpdatedForwardMessageIds(Array(messageIds))
|
||||||
// } else {
|
} else {
|
||||||
// return ChatInterfaceState().withUpdatedForwardMessageIds(Array(messageIds))
|
return ChatInterfaceState().withUpdatedForwardMessageIds(Array(messageIds))
|
||||||
// }
|
}
|
||||||
// })
|
})
|
||||||
// }) |> deliverOnMainQueue).start(completed: {
|
}) |> deliverOnMainQueue).start(completed: {
|
||||||
// if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
// strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone)
|
// strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone)
|
||||||
//
|
|
||||||
// let ready = Promise<Bool>()
|
let ready = Promise<Bool>()
|
||||||
// strongSelf.activeActionDisposable.set((ready.get() |> filter { $0 } |> take(1) |> deliverOnMainQueue).start(next: { _ in
|
let signal = ready.get()
|
||||||
// if let peerSelectionController = peerSelectionController {
|
|> filter({ $0 })
|
||||||
// peerSelectionController.dismiss()
|
|> take(1)
|
||||||
// }
|
|> deliverOnMainQueue
|
||||||
// }))
|
|
||||||
//
|
strongSelf.activeActionDisposable.set(signal.start(next: { _ in
|
||||||
// (strongSelf.controller?.navigationController as? NavigationController)?.replaceTopController(ChatControllerImpl(context: strongSelf.context, chatLocation: .peer(peerId)), animated: false, ready: ready)
|
if let peerSelectionController = peerSelectionController {
|
||||||
// }
|
peerSelectionController.dismiss()
|
||||||
// })
|
}
|
||||||
// }
|
}))
|
||||||
// }
|
|
||||||
// }
|
let controller = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peerId), subject: nil, botStart: nil, mode: .standard(previewing: false))
|
||||||
// self.controller?.push(peerSelectionController)
|
strongSelf.navigationController?.replaceTopController(controller, animated: false, ready: ready)
|
||||||
// }
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.navigationController?.pushViewController(peerSelectionController)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import UniversalMediaPlayer
|
|||||||
import ListMessageItem
|
import ListMessageItem
|
||||||
import ListSectionHeaderNode
|
import ListSectionHeaderNode
|
||||||
import ChatMessageInteractiveMediaBadge
|
import ChatMessageInteractiveMediaBadge
|
||||||
|
import ShimmerEffect
|
||||||
|
|
||||||
private let mediaBadgeBackgroundColor = UIColor(white: 0.0, alpha: 0.6)
|
private let mediaBadgeBackgroundColor = UIColor(white: 0.0, alpha: 0.6)
|
||||||
private let mediaBadgeTextColor = UIColor.white
|
private let mediaBadgeTextColor = UIColor.white
|
||||||
@ -41,8 +42,6 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
|||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let interaction: VisualMediaItemInteraction
|
private let interaction: VisualMediaItemInteraction
|
||||||
|
|
||||||
// private var videoLayerFrameManager: SoftwareVideoLayerFrameManager?
|
|
||||||
// private var sampleBufferLayer: SampleBufferLayer?
|
|
||||||
private var displayLink: ConstantDisplayLinkAnimator?
|
private var displayLink: ConstantDisplayLinkAnimator?
|
||||||
private var displayLinkTimestamp: Double = 0.0
|
private var displayLinkTimestamp: Double = 0.0
|
||||||
|
|
||||||
@ -50,6 +49,7 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
|||||||
private let imageNode: TransformImageNode
|
private let imageNode: TransformImageNode
|
||||||
private var statusNode: RadialStatusNode
|
private var statusNode: RadialStatusNode
|
||||||
private let mediaBadgeNode: ChatMessageInteractiveMediaBadge
|
private let mediaBadgeNode: ChatMessageInteractiveMediaBadge
|
||||||
|
private var placeholderNode: ShimmerEffectNode?
|
||||||
|
|
||||||
private let fetchStatusDisposable = MetaDisposable()
|
private let fetchStatusDisposable = MetaDisposable()
|
||||||
private let fetchDisposable = MetaDisposable()
|
private let fetchDisposable = MetaDisposable()
|
||||||
@ -84,7 +84,9 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
|||||||
guard let strongSelf = self, let item = strongSelf.item else {
|
guard let strongSelf = self, let item = strongSelf.item else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.interaction.openMessageContextActions(item.0.message, strongSelf.containerNode, strongSelf.containerNode.bounds, gesture)
|
if let message = item.0.message {
|
||||||
|
strongSelf.interaction.openMessageContextActions(message, strongSelf.containerNode, strongSelf.containerNode.bounds, gesture)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,12 +110,15 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc func tapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
@objc func tapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
||||||
|
guard let message = self.item?.0.message else {
|
||||||
|
return
|
||||||
|
}
|
||||||
if case .ended = recognizer.state {
|
if case .ended = recognizer.state {
|
||||||
if let (gesture, _) = recognizer.lastRecognizedGestureAndLocation {
|
if let (gesture, _) = recognizer.lastRecognizedGestureAndLocation {
|
||||||
if case .tap = gesture {
|
if case .tap = gesture {
|
||||||
if let (item, _, _, _) = self.item {
|
if let (item, _, _, _) = self.item {
|
||||||
var media: Media?
|
var media: Media?
|
||||||
for value in item.message.media {
|
for value in message.media {
|
||||||
if let image = value as? TelegramMediaImage {
|
if let image = value as? TelegramMediaImage {
|
||||||
media = image
|
media = image
|
||||||
break
|
break
|
||||||
@ -125,13 +130,13 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
|||||||
|
|
||||||
if let media = media {
|
if let media = media {
|
||||||
if let file = media as? TelegramMediaFile {
|
if let file = media as? TelegramMediaFile {
|
||||||
if isMediaStreamable(message: item.message, media: file) {
|
if isMediaStreamable(message: message, media: file) {
|
||||||
self.interaction.openMessage(item.message)
|
self.interaction.openMessage(message)
|
||||||
} else {
|
} else {
|
||||||
self.progressPressed()
|
self.progressPressed()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.interaction.openMessage(item.message)
|
self.interaction.openMessage(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,50 +177,34 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
|||||||
self.containerNode.cancelGesture()
|
self.containerNode.cancelGesture()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateAbsoluteRect(_ absoluteRect: CGRect, within containerSize: CGSize) {
|
||||||
|
self.placeholderNode?.updateAbsoluteRect(absoluteRect, within: containerSize)
|
||||||
|
}
|
||||||
|
|
||||||
func update(size: CGSize, item: VisualMediaItem, theme: PresentationTheme, synchronousLoad: Bool) {
|
func update(size: CGSize, item: VisualMediaItem, theme: PresentationTheme, synchronousLoad: Bool) {
|
||||||
if item === self.item?.0 && size == self.item?.2 {
|
if item === self.item?.0 && size == self.item?.2 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
var media: Media?
|
var media: Media?
|
||||||
for value in item.message.media {
|
if let message = item.message {
|
||||||
if let image = value as? TelegramMediaImage {
|
for value in message.media {
|
||||||
media = image
|
if let image = value as? TelegramMediaImage {
|
||||||
break
|
media = image
|
||||||
} else if let file = value as? TelegramMediaFile {
|
break
|
||||||
media = file
|
} else if let file = value as? TelegramMediaFile {
|
||||||
break
|
media = file
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if let file = media as? TelegramMediaFile, file.isAnimated {
|
if let media = media, (self.item?.1 == nil || !media.isEqual(to: self.item!.1!)), let message = item.message {
|
||||||
// if self.videoLayerFrameManager == nil {
|
|
||||||
// let sampleBufferLayer: SampleBufferLayer
|
|
||||||
// if let current = self.sampleBufferLayer {
|
|
||||||
// sampleBufferLayer = current
|
|
||||||
// } else {
|
|
||||||
// sampleBufferLayer = takeSampleBufferLayer()
|
|
||||||
// self.sampleBufferLayer = sampleBufferLayer
|
|
||||||
// self.imageNode.layer.addSublayer(sampleBufferLayer.layer)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// self.videoLayerFrameManager = SoftwareVideoLayerFrameManager(account: self.context.account, fileReference: FileMediaReference.message(message: MessageReference(item.message), media: file), layerHolder: sampleBufferLayer)
|
|
||||||
// self.videoLayerFrameManager?.start()
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// if let sampleBufferLayer = self.sampleBufferLayer {
|
|
||||||
// sampleBufferLayer.layer.removeFromSuperlayer()
|
|
||||||
// self.sampleBufferLayer = nil
|
|
||||||
// }
|
|
||||||
// self.videoLayerFrameManager = nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
if let media = media, (self.item?.1 == nil || !media.isEqual(to: self.item!.1!)) {
|
|
||||||
var mediaDimensions: CGSize?
|
var mediaDimensions: CGSize?
|
||||||
if let image = media as? TelegramMediaImage, let largestSize = largestImageRepresentation(image.representations)?.dimensions {
|
if let image = media as? TelegramMediaImage, let largestSize = largestImageRepresentation(image.representations)?.dimensions {
|
||||||
mediaDimensions = largestSize.cgSize
|
mediaDimensions = largestSize.cgSize
|
||||||
|
|
||||||
self.imageNode.setSignal(mediaGridMessagePhoto(account: context.account, photoReference: .message(message: MessageReference(item.message), media: image), fullRepresentationSize: CGSize(width: 300.0, height: 300.0), synchronousLoad: synchronousLoad), attemptSynchronously: synchronousLoad, dispatchOnDisplayLink: true)
|
self.imageNode.setSignal(mediaGridMessagePhoto(account: context.account, photoReference: .message(message: MessageReference(message), media: image), fullRepresentationSize: CGSize(width: 300.0, height: 300.0), synchronousLoad: synchronousLoad), attemptSynchronously: synchronousLoad, dispatchOnDisplayLink: true)
|
||||||
|
|
||||||
self.fetchStatusDisposable.set(nil)
|
self.fetchStatusDisposable.set(nil)
|
||||||
self.statusNode.transitionToState(.none, completion: { [weak self] in
|
self.statusNode.transitionToState(.none, completion: { [weak self] in
|
||||||
@ -225,7 +214,7 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
|||||||
self.resourceStatus = nil
|
self.resourceStatus = nil
|
||||||
} else if let file = media as? TelegramMediaFile, file.isVideo {
|
} else if let file = media as? TelegramMediaFile, file.isVideo {
|
||||||
mediaDimensions = file.dimensions?.cgSize
|
mediaDimensions = file.dimensions?.cgSize
|
||||||
self.imageNode.setSignal(mediaGridMessageVideo(postbox: context.account.postbox, videoReference: .message(message: MessageReference(item.message), media: file), synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: true), attemptSynchronously: synchronousLoad)
|
self.imageNode.setSignal(mediaGridMessageVideo(postbox: context.account.postbox, videoReference: .message(message: MessageReference(message), media: file), synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: true), attemptSynchronously: synchronousLoad)
|
||||||
|
|
||||||
self.mediaBadgeNode.isHidden = file.isAnimated
|
self.mediaBadgeNode.isHidden = file.isAnimated
|
||||||
|
|
||||||
@ -233,12 +222,12 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.item = (item, media, size, mediaDimensions)
|
self.item = (item, media, size, mediaDimensions)
|
||||||
|
|
||||||
self.fetchStatusDisposable.set((messageMediaFileStatus(context: context, messageId: item.message.id, file: file)
|
self.fetchStatusDisposable.set((messageMediaFileStatus(context: context, messageId: message.id, file: file)
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||||
if let strongSelf = self, let (item, _, _, _) = strongSelf.item {
|
if let strongSelf = self, let (item, _, _, _) = strongSelf.item {
|
||||||
strongSelf.resourceStatus = status
|
strongSelf.resourceStatus = status
|
||||||
|
|
||||||
let isStreamable = isMediaStreamable(message: item.message, media: file)
|
let isStreamable = isMediaStreamable(message: message, media: file)
|
||||||
|
|
||||||
var statusState: RadialStatusNodeState = .none
|
var statusState: RadialStatusNodeState = .none
|
||||||
if isStreamable || file.isAnimated {
|
if isStreamable || file.isAnimated {
|
||||||
@ -310,18 +299,26 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
|||||||
self.mediaBadgeNode.frame = CGRect(origin: CGPoint(x: size.width - 3.0, y: size.height - 18.0 - 3.0), size: CGSize(width: 50.0, height: 50.0))
|
self.mediaBadgeNode.frame = CGRect(origin: CGPoint(x: size.width - 3.0, y: size.height - 18.0 - 3.0), size: CGSize(width: 50.0, height: 50.0))
|
||||||
|
|
||||||
self.updateHiddenMedia()
|
self.updateHiddenMedia()
|
||||||
|
|
||||||
|
if let placeholderNode = self.placeholderNode {
|
||||||
|
self.placeholderNode = nil
|
||||||
|
placeholderNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
} else if item.isEmpty, self.placeholderNode == nil {
|
||||||
|
let placeholderNode = ShimmerEffectNode()
|
||||||
|
placeholderNode.update(backgroundColor: theme.list.itemBlocksBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor, shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: [.rect(rect: CGRect(origin: CGPoint(), size: size))], size: size)
|
||||||
|
self.addSubnode(placeholderNode)
|
||||||
|
self.placeholderNode = placeholderNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let imageFrame = CGRect(origin: CGPoint(), size: size)
|
||||||
|
self.placeholderNode?.frame = imageFrame
|
||||||
|
|
||||||
if let (item, media, _, mediaDimensions) = self.item {
|
if let (item, media, _, mediaDimensions) = self.item {
|
||||||
self.item = (item, media, size, mediaDimensions)
|
self.item = (item, media, size, mediaDimensions)
|
||||||
|
|
||||||
let imageFrame = CGRect(origin: CGPoint(), size: size)
|
|
||||||
|
|
||||||
self.containerNode.frame = imageFrame
|
self.containerNode.frame = imageFrame
|
||||||
self.imageNode.frame = imageFrame
|
self.imageNode.frame = imageFrame
|
||||||
// if let sampleBufferLayer = self.sampleBufferLayer {
|
|
||||||
// sampleBufferLayer.layer.frame = imageFrame
|
|
||||||
// }
|
|
||||||
|
|
||||||
if let mediaDimensions = mediaDimensions {
|
if let mediaDimensions = mediaDimensions {
|
||||||
let imageSize = mediaDimensions.aspectFilled(imageFrame.size)
|
let imageSize = mediaDimensions.aspectFilled(imageFrame.size)
|
||||||
@ -379,8 +376,8 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateHiddenMedia() {
|
func updateHiddenMedia() {
|
||||||
if let (item, _, _, _) = self.item {
|
if let (item, _, _, _) = self.item, let message = item.message {
|
||||||
if let _ = self.interaction.hiddenMedia[item.message.id] {
|
if let _ = self.interaction.hiddenMedia[message.id] {
|
||||||
self.isHidden = true
|
self.isHidden = true
|
||||||
} else {
|
} else {
|
||||||
self.isHidden = false
|
self.isHidden = false
|
||||||
@ -393,11 +390,22 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final class VisualMediaItem {
|
private final class VisualMediaItem {
|
||||||
let message: Message
|
let index: UInt32?
|
||||||
|
let message: Message?
|
||||||
let dimensions: CGSize
|
let dimensions: CGSize
|
||||||
let aspectRatio: CGFloat
|
let aspectRatio: CGFloat
|
||||||
|
let isEmpty: Bool
|
||||||
|
|
||||||
|
init(index: UInt32) {
|
||||||
|
self.index = index
|
||||||
|
self.message = nil
|
||||||
|
self.dimensions = CGSize(width: 100.0, height: 100.0)
|
||||||
|
self.aspectRatio = 1.0
|
||||||
|
self.isEmpty = true
|
||||||
|
}
|
||||||
|
|
||||||
init(message: Message) {
|
init(message: Message) {
|
||||||
|
self.index = nil
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
var aspectRatio: CGFloat = 1.0
|
var aspectRatio: CGFloat = 1.0
|
||||||
@ -412,6 +420,17 @@ private final class VisualMediaItem {
|
|||||||
}
|
}
|
||||||
self.aspectRatio = aspectRatio
|
self.aspectRatio = aspectRatio
|
||||||
self.dimensions = dimensions
|
self.dimensions = dimensions
|
||||||
|
self.isEmpty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
var stableId: UInt32 {
|
||||||
|
if let message = self.message {
|
||||||
|
return message.stableId
|
||||||
|
} else if let index = self.index {
|
||||||
|
return index
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -680,15 +699,24 @@ final class ChatListSearchMediaNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func updateHistory(entries: [ChatListSearchEntry], totalCount: Int32, updateType: ViewUpdateType) {
|
func updateHistory(entries: [ChatListSearchEntry]?, totalCount: Int32, updateType: ViewUpdateType) {
|
||||||
switch updateType {
|
switch updateType {
|
||||||
case .FillHole:
|
case .FillHole:
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
self.mediaItems.removeAll()
|
self.mediaItems.removeAll()
|
||||||
for entry in entries {
|
let loading: Bool
|
||||||
if case let .message(message, _, _, _, _) = entry {
|
if let entries = entries {
|
||||||
self.mediaItems.append(VisualMediaItem(message: message))
|
loading = false
|
||||||
|
for entry in entries {
|
||||||
|
if case let .message(message, _, _, _, _) = entry {
|
||||||
|
self.mediaItems.append(VisualMediaItem(message: message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
loading = true
|
||||||
|
for i in 0 ..< 21 {
|
||||||
|
self.mediaItems.append(VisualMediaItem(index: UInt32(i)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.itemsLayout = nil
|
self.itemsLayout = nil
|
||||||
@ -697,12 +725,14 @@ final class ChatListSearchMediaNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.initialized = true
|
self.initialized = true
|
||||||
|
|
||||||
if let (size, sideInset, bottomInset, visibleHeight, isScrollingLockedAtTop, expandProgress, presentationData) = self.currentParams {
|
if let (size, sideInset, bottomInset, visibleHeight, isScrollingLockedAtTop, expandProgress, presentationData) = self.currentParams {
|
||||||
if totalCount > 0 {
|
if loading {
|
||||||
|
self.headerNode.title = ""
|
||||||
|
} else if totalCount > 0 {
|
||||||
self.headerNode.title = presentationData.strings.ChatList_Search_Photos(totalCount).uppercased()
|
self.headerNode.title = presentationData.strings.ChatList_Search_Photos(totalCount).uppercased()
|
||||||
}
|
}
|
||||||
|
|
||||||
self.update(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, isScrollingLockedAtTop: isScrollingLockedAtTop, expandProgress: expandProgress, presentationData: presentationData, synchronous: true, transition: .immediate)
|
self.update(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, isScrollingLockedAtTop: isScrollingLockedAtTop, expandProgress: expandProgress, presentationData: presentationData, synchronous: true, transition: .immediate)
|
||||||
self.headerNode.alpha = self.mediaItems.isEmpty ? 0.0 : 1.0
|
self.headerNode.alpha = self.mediaItems.isEmpty && !loading ? 0.0 : 1.0
|
||||||
if !self.didSetReady {
|
if !self.didSetReady {
|
||||||
self.didSetReady = true
|
self.didSetReady = true
|
||||||
self.ready.set(.single(true))
|
self.ready.set(.single(true))
|
||||||
@ -722,7 +752,7 @@ final class ChatListSearchMediaNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
func findLoadedMessage(id: MessageId) -> Message? {
|
func findLoadedMessage(id: MessageId) -> Message? {
|
||||||
for item in self.mediaItems {
|
for item in self.mediaItems {
|
||||||
if item.message.id == id {
|
if item.message?.id == id {
|
||||||
return item.message
|
return item.message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -743,8 +773,8 @@ final class ChatListSearchMediaNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
|
func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
|
||||||
for item in self.mediaItems {
|
for item in self.mediaItems {
|
||||||
if item.message.id == messageId {
|
if let message = item.message, message.id == messageId {
|
||||||
if let itemNode = self.visibleMediaItems[item.message.stableId] {
|
if let itemNode = self.visibleMediaItems[message.stableId] {
|
||||||
return itemNode.transitionNode()
|
return itemNode.transitionNode()
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@ -855,7 +885,7 @@ final class ChatListSearchMediaNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
var validIds = Set<UInt32>()
|
var validIds = Set<UInt32>()
|
||||||
if minVisibleIndex <= maxVisibleIndex {
|
if minVisibleIndex <= maxVisibleIndex {
|
||||||
for i in minVisibleIndex ... maxVisibleIndex {
|
for i in minVisibleIndex ... maxVisibleIndex {
|
||||||
let stableId = self.mediaItems[i].message.stableId
|
let stableId = self.mediaItems[i].stableId
|
||||||
validIds.insert(stableId)
|
validIds.insert(stableId)
|
||||||
|
|
||||||
let itemFrame = itemsLayout.frame(forItemAt: i, sideInset: sideInset)
|
let itemFrame = itemsLayout.frame(forItemAt: i, sideInset: sideInset)
|
||||||
@ -869,6 +899,7 @@ final class ChatListSearchMediaNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.scrollNode.addSubnode(itemNode)
|
self.scrollNode.addSubnode(itemNode)
|
||||||
}
|
}
|
||||||
itemNode.frame = itemFrame
|
itemNode.frame = itemFrame
|
||||||
|
itemNode.updateAbsoluteRect(itemFrame, within: self.scrollNode.view.bounds.size)
|
||||||
if headerItem == nil && itemFrame.maxY > headerItemMinY {
|
if headerItem == nil && itemFrame.maxY > headerItemMinY {
|
||||||
headerItem = self.mediaItems[i].message
|
headerItem = self.mediaItems[i].message
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,181 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import Display
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import Display
|
||||||
|
import Postbox
|
||||||
|
import TelegramCore
|
||||||
|
import SyncCore
|
||||||
|
import SwiftSignalKit
|
||||||
|
import TelegramPresentationData
|
||||||
|
import AccountContext
|
||||||
|
import AppBundle
|
||||||
|
|
||||||
|
final class ChatListSearchMessageSelectionPanelNode: ASDisplayNode {
|
||||||
|
private let context: AccountContext
|
||||||
|
private var theme: PresentationTheme
|
||||||
|
|
||||||
|
private let deleteMessages: () -> Void
|
||||||
|
private let shareMessages: () -> Void
|
||||||
|
private let forwardMessages: () -> Void
|
||||||
|
|
||||||
|
private let separatorNode: ASDisplayNode
|
||||||
|
private let backgroundNode: ASDisplayNode
|
||||||
|
private let deleteButton: HighlightableButtonNode
|
||||||
|
private let forwardButton: HighlightableButtonNode
|
||||||
|
private let shareButton: HighlightableButtonNode
|
||||||
|
|
||||||
|
private var actions: ChatAvailableMessageActions?
|
||||||
|
|
||||||
|
private let canDeleteMessagesDisposable = MetaDisposable()
|
||||||
|
|
||||||
|
private var validLayout: ContainerViewLayout?
|
||||||
|
|
||||||
|
var selectedMessages = Set<MessageId>() {
|
||||||
|
didSet {
|
||||||
|
if oldValue != self.selectedMessages {
|
||||||
|
self.forwardButton.isEnabled = self.selectedMessages.count != 0
|
||||||
|
|
||||||
|
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
if self.selectedMessages.isEmpty {
|
||||||
|
self.actions = nil
|
||||||
|
if let layout = self.validLayout {
|
||||||
|
let _ = self.update(layout: layout, presentationData: presentationData, transition: .immediate)
|
||||||
|
}
|
||||||
|
self.canDeleteMessagesDisposable.set(nil)
|
||||||
|
} else {
|
||||||
|
self.canDeleteMessagesDisposable.set((self.context.sharedContext.chatAvailableMessageActions(postbox: context.account.postbox, accountPeerId: context.account.peerId, messageIds: self.selectedMessages)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] actions in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.actions = actions
|
||||||
|
if let layout = strongSelf.validLayout {
|
||||||
|
let _ = strongSelf.update(layout: layout, presentationData: presentationData, transition: .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(context: AccountContext, deleteMessages: @escaping () -> Void, shareMessages: @escaping () -> Void, forwardMessages: @escaping () -> Void) {
|
||||||
|
self.context = context
|
||||||
|
self.deleteMessages = deleteMessages
|
||||||
|
self.shareMessages = shareMessages
|
||||||
|
self.forwardMessages = forwardMessages
|
||||||
|
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
self.theme = presentationData.theme
|
||||||
|
|
||||||
|
self.separatorNode = ASDisplayNode()
|
||||||
|
self.separatorNode.backgroundColor = presentationData.theme.chat.inputPanel.panelSeparatorColor
|
||||||
|
|
||||||
|
self.backgroundNode = ASDisplayNode()
|
||||||
|
self.backgroundNode.backgroundColor = presentationData.theme.chat.inputPanel.panelBackgroundColor
|
||||||
|
|
||||||
|
self.deleteButton = HighlightableButtonNode(pointerStyle: .default)
|
||||||
|
self.deleteButton.isEnabled = false
|
||||||
|
self.deleteButton.isAccessibilityElement = true
|
||||||
|
self.deleteButton.accessibilityLabel = presentationData.strings.VoiceOver_MessageContextDelete
|
||||||
|
|
||||||
|
self.forwardButton = HighlightableButtonNode(pointerStyle: .default)
|
||||||
|
self.forwardButton.isAccessibilityElement = true
|
||||||
|
self.forwardButton.accessibilityLabel = presentationData.strings.VoiceOver_MessageContextForward
|
||||||
|
|
||||||
|
self.shareButton = HighlightableButtonNode(pointerStyle: .default)
|
||||||
|
self.shareButton.isEnabled = false
|
||||||
|
self.shareButton.isAccessibilityElement = true
|
||||||
|
self.shareButton.accessibilityLabel = presentationData.strings.VoiceOver_MessageContextShare
|
||||||
|
|
||||||
|
self.deleteButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: presentationData.theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
|
||||||
|
self.deleteButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: presentationData.theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
|
||||||
|
self.forwardButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: presentationData.theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
|
||||||
|
self.forwardButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: presentationData.theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
|
||||||
|
self.shareButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: presentationData.theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
|
||||||
|
self.shareButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: presentationData.theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.addSubnode(self.deleteButton)
|
||||||
|
self.addSubnode(self.forwardButton)
|
||||||
|
self.addSubnode(self.shareButton)
|
||||||
|
self.addSubnode(self.separatorNode)
|
||||||
|
|
||||||
|
self.forwardButton.isEnabled = false
|
||||||
|
|
||||||
|
self.deleteButton.addTarget(self, action: #selector(self.deleteButtonPressed), forControlEvents: .touchUpInside)
|
||||||
|
self.forwardButton.addTarget(self, action: #selector(self.forwardButtonPressed), forControlEvents: .touchUpInside)
|
||||||
|
self.shareButton.addTarget(self, action: #selector(self.shareButtonPressed), forControlEvents: .touchUpInside)
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.canDeleteMessagesDisposable.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(layout: ContainerViewLayout, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||||
|
if presentationData.theme !== self.theme {
|
||||||
|
self.theme = presentationData.theme
|
||||||
|
|
||||||
|
self.backgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.backgroundColor
|
||||||
|
self.separatorNode.backgroundColor = presentationData.theme.rootController.navigationBar.separatorColor
|
||||||
|
|
||||||
|
self.deleteButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: presentationData.theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
|
||||||
|
self.deleteButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: presentationData.theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
|
||||||
|
self.forwardButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: presentationData.theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
|
||||||
|
self.forwardButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: presentationData.theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
|
||||||
|
self.shareButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: presentationData.theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
|
||||||
|
self.shareButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: presentationData.theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
|
||||||
|
}
|
||||||
|
|
||||||
|
let width = layout.size.width
|
||||||
|
let insets = layout.insets(options: [])
|
||||||
|
let leftInset = insets.left
|
||||||
|
let rightInset = insets.left
|
||||||
|
|
||||||
|
let panelHeight: CGFloat
|
||||||
|
if case .regular = layout.metrics.widthClass, case .regular = layout.metrics.heightClass {
|
||||||
|
panelHeight = 49.0
|
||||||
|
} else {
|
||||||
|
panelHeight = 45.0
|
||||||
|
}
|
||||||
|
|
||||||
|
if let actions = self.actions {
|
||||||
|
self.deleteButton.isEnabled = false
|
||||||
|
self.forwardButton.isEnabled = actions.options.contains(.forward)
|
||||||
|
self.shareButton.isEnabled = false
|
||||||
|
|
||||||
|
self.deleteButton.isEnabled = !actions.options.intersection([.deleteLocally, .deleteGlobally]).isEmpty
|
||||||
|
self.shareButton.isEnabled = !actions.options.intersection([.forward]).isEmpty
|
||||||
|
|
||||||
|
self.deleteButton.isHidden = !self.deleteButton.isEnabled
|
||||||
|
} else {
|
||||||
|
self.deleteButton.isEnabled = false
|
||||||
|
self.deleteButton.isHidden = true
|
||||||
|
self.forwardButton.isEnabled = false
|
||||||
|
self.shareButton.isEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
self.deleteButton.frame = CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: 57.0, height: panelHeight))
|
||||||
|
self.forwardButton.frame = CGRect(origin: CGPoint(x: width - rightInset - 57.0, y: 0.0), size: CGSize(width: 57.0, height: panelHeight))
|
||||||
|
self.shareButton.frame = CGRect(origin: CGPoint(x: floor((width - rightInset - 57.0) / 2.0), y: 0.0), size: CGSize(width: 57.0, height: panelHeight))
|
||||||
|
|
||||||
|
let panelHeightWithInset = panelHeight + layout.intrinsicInsets.bottom
|
||||||
|
|
||||||
|
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: panelHeightWithInset)))
|
||||||
|
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: UIScreenPixel), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
||||||
|
|
||||||
|
return panelHeightWithInset
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func deleteButtonPressed() {
|
||||||
|
self.deleteMessages()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func forwardButtonPressed() {
|
||||||
|
self.shareMessages()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func shareButtonPressed() {
|
||||||
|
self.forwardMessages()
|
||||||
|
}
|
||||||
|
}
|
@ -37,13 +37,14 @@ public final class ListMessageItem: ListViewItem {
|
|||||||
let interaction: ListMessageItemInteraction
|
let interaction: ListMessageItemInteraction
|
||||||
let message: Message
|
let message: Message
|
||||||
let selection: ChatHistoryMessageSelection
|
let selection: ChatHistoryMessageSelection
|
||||||
|
let hintIsLink: Bool
|
||||||
let isGlobalSearchResult: Bool
|
let isGlobalSearchResult: Bool
|
||||||
|
|
||||||
let header: ListViewItemHeader?
|
let header: ListViewItemHeader?
|
||||||
|
|
||||||
public let selectable: Bool = true
|
public let selectable: Bool = true
|
||||||
|
|
||||||
public init(presentationData: ChatPresentationData, context: AccountContext, chatLocation: ChatLocation, interaction: ListMessageItemInteraction, message: Message, selection: ChatHistoryMessageSelection, displayHeader: Bool, customHeader: ListViewItemHeader? = nil, isGlobalSearchResult: Bool = false) {
|
public init(presentationData: ChatPresentationData, context: AccountContext, chatLocation: ChatLocation, interaction: ListMessageItemInteraction, message: Message, selection: ChatHistoryMessageSelection, displayHeader: Bool, customHeader: ListViewItemHeader? = nil, hintIsLink: Bool = false, isGlobalSearchResult: Bool = false) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.context = context
|
self.context = context
|
||||||
self.chatLocation = chatLocation
|
self.chatLocation = chatLocation
|
||||||
@ -57,16 +58,19 @@ public final class ListMessageItem: ListViewItem {
|
|||||||
self.header = nil
|
self.header = nil
|
||||||
}
|
}
|
||||||
self.selection = selection
|
self.selection = selection
|
||||||
|
self.hintIsLink = hintIsLink
|
||||||
self.isGlobalSearchResult = isGlobalSearchResult
|
self.isGlobalSearchResult = isGlobalSearchResult
|
||||||
}
|
}
|
||||||
|
|
||||||
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
var viewClassName: AnyClass = ListMessageSnippetItemNode.self
|
var viewClassName: AnyClass = ListMessageSnippetItemNode.self
|
||||||
|
|
||||||
for media in self.message.media {
|
if !self.hintIsLink {
|
||||||
if let _ = media as? TelegramMediaFile {
|
for media in self.message.media {
|
||||||
viewClassName = ListMessageFileItemNode.self
|
if let _ = media as? TelegramMediaFile {
|
||||||
break
|
viewClassName = ListMessageFileItemNode.self
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,6 +128,12 @@ private class SearchBarTextField: UITextField {
|
|||||||
self.setNeedsLayout()
|
self.setNeedsLayout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var selectedTokenIndex: Int? {
|
||||||
|
didSet {
|
||||||
|
self.layoutTokens(transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||||
|
self.setNeedsLayout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var theme: SearchBarNodeTheme
|
var theme: SearchBarNodeTheme
|
||||||
|
|
||||||
|
@ -354,7 +354,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
|
|||||||
controlColor: UIColor(rgb: 0x7e8791),
|
controlColor: UIColor(rgb: 0x7e8791),
|
||||||
accentTextColor: UIColor(rgb: 0x007ee5),
|
accentTextColor: UIColor(rgb: 0x007ee5),
|
||||||
backgroundColor: UIColor(rgb: 0xf7f7f7),
|
backgroundColor: UIColor(rgb: 0xf7f7f7),
|
||||||
separatorColor: UIColor(rgb: 0xb1b1b1),
|
separatorColor: UIColor(rgb: 0xc8c7cc),
|
||||||
badgeBackgroundColor: UIColor(rgb: 0xff3b30),
|
badgeBackgroundColor: UIColor(rgb: 0xff3b30),
|
||||||
badgeStrokeColor: UIColor(rgb: 0xff3b30),
|
badgeStrokeColor: UIColor(rgb: 0xff3b30),
|
||||||
badgeTextColor: UIColor(rgb: 0xffffff),
|
badgeTextColor: UIColor(rgb: 0xffffff),
|
||||||
@ -374,7 +374,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
|
|||||||
inputPlaceholderTextColor: UIColor(rgb: 0x8e8e93),
|
inputPlaceholderTextColor: UIColor(rgb: 0x8e8e93),
|
||||||
inputIconColor: UIColor(rgb: 0x8e8e93),
|
inputIconColor: UIColor(rgb: 0x8e8e93),
|
||||||
inputClearButtonColor: UIColor(rgb: 0x7b7b81),
|
inputClearButtonColor: UIColor(rgb: 0x7b7b81),
|
||||||
separatorColor: UIColor(rgb: 0xb1b1b1)
|
separatorColor: UIColor(rgb: 0xc8c7cc)
|
||||||
)
|
)
|
||||||
|
|
||||||
let rootController = PresentationThemeRootController(
|
let rootController = PresentationThemeRootController(
|
||||||
@ -685,7 +685,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
|
|||||||
|
|
||||||
let historyNavigation = PresentationThemeChatHistoryNavigation(
|
let historyNavigation = PresentationThemeChatHistoryNavigation(
|
||||||
fillColor: UIColor(rgb: 0xf7f7f7),
|
fillColor: UIColor(rgb: 0xf7f7f7),
|
||||||
strokeColor: UIColor(rgb: 0xb1b1b1),
|
strokeColor: UIColor(rgb: 0xc8c7cc),
|
||||||
foregroundColor: UIColor(rgb: 0x88888d),
|
foregroundColor: UIColor(rgb: 0x88888d),
|
||||||
badgeBackgroundColor: UIColor(rgb: 0x007ee5),
|
badgeBackgroundColor: UIColor(rgb: 0x007ee5),
|
||||||
badgeStrokeColor: UIColor(rgb: 0x007ee5),
|
badgeStrokeColor: UIColor(rgb: 0x007ee5),
|
||||||
@ -751,7 +751,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
|
|||||||
backgroundColor: UIColor(rgb: 0xffffff),
|
backgroundColor: UIColor(rgb: 0xffffff),
|
||||||
primaryTextColor: UIColor(rgb: 0x000000),
|
primaryTextColor: UIColor(rgb: 0x000000),
|
||||||
controlColor: UIColor(rgb: 0x7e8791),
|
controlColor: UIColor(rgb: 0x7e8791),
|
||||||
separatorColor: UIColor(rgb: 0xb1b1b1)
|
separatorColor: UIColor(rgb: 0xc8c7cc)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -210,6 +210,7 @@ framework(
|
|||||||
"//submodules/FileMediaResourceStatus:FileMediaResourceStatus",
|
"//submodules/FileMediaResourceStatus:FileMediaResourceStatus",
|
||||||
"//submodules/ChatMessageInteractiveMediaBadge:ChatMessageInteractiveMediaBadge",
|
"//submodules/ChatMessageInteractiveMediaBadge:ChatMessageInteractiveMediaBadge",
|
||||||
"//submodules/GalleryData:GalleryData",
|
"//submodules/GalleryData:GalleryData",
|
||||||
|
"//submodules/ChatInterfaceState:ChatInterfaceState",
|
||||||
],
|
],
|
||||||
frameworks = [
|
frameworks = [
|
||||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||||
|
@ -205,6 +205,7 @@ swift_library(
|
|||||||
"//submodules/FileMediaResourceStatus:FileMediaResourceStatus",
|
"//submodules/FileMediaResourceStatus:FileMediaResourceStatus",
|
||||||
"//submodules/ChatMessageInteractiveMediaBadge:ChatMessageInteractiveMediaBadge",
|
"//submodules/ChatMessageInteractiveMediaBadge:ChatMessageInteractiveMediaBadge",
|
||||||
"//submodules/GalleryData:GalleryData",
|
"//submodules/GalleryData:GalleryData",
|
||||||
|
"//submodules/ChatInterfaceState:ChatInterfaceState",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -4,7 +4,6 @@ import Display
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
|
|
||||||
private final class AudioWaveformNodeParameters: NSObject {
|
private final class AudioWaveformNodeParameters: NSObject {
|
||||||
|
|
||||||
let waveform: AudioWaveform?
|
let waveform: AudioWaveform?
|
||||||
let color: UIColor?
|
let color: UIColor?
|
||||||
let gravity: AudioWaveformNode.Gravity?
|
let gravity: AudioWaveformNode.Gravity?
|
||||||
@ -21,9 +20,7 @@ private final class AudioWaveformNodeParameters: NSObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class AudioWaveformNode: ASDisplayNode {
|
final class AudioWaveformNode: ASDisplayNode {
|
||||||
|
|
||||||
enum Gravity {
|
enum Gravity {
|
||||||
|
|
||||||
case bottom
|
case bottom
|
||||||
case center
|
case center
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,7 @@ import TooltipUI
|
|||||||
import StatisticsUI
|
import StatisticsUI
|
||||||
import MediaResources
|
import MediaResources
|
||||||
import GalleryData
|
import GalleryData
|
||||||
|
import ChatInterfaceState
|
||||||
|
|
||||||
extension ChatLocation {
|
extension ChatLocation {
|
||||||
var peerId: PeerId {
|
var peerId: PeerId {
|
||||||
|
@ -10,6 +10,7 @@ import AccountContext
|
|||||||
import TextSelectionNode
|
import TextSelectionNode
|
||||||
import ReactionSelectionNode
|
import ReactionSelectionNode
|
||||||
import ContextUI
|
import ContextUI
|
||||||
|
import ChatInterfaceState
|
||||||
|
|
||||||
struct ChatInterfaceHighlightedState: Equatable {
|
struct ChatInterfaceHighlightedState: Equatable {
|
||||||
let messageStableId: UInt32
|
let messageStableId: UInt32
|
||||||
|
@ -13,6 +13,7 @@ import AccountContext
|
|||||||
import TelegramNotices
|
import TelegramNotices
|
||||||
import ReactionSelectionNode
|
import ReactionSelectionNode
|
||||||
import TelegramUniversalVideoContent
|
import TelegramUniversalVideoContent
|
||||||
|
import ChatInterfaceState
|
||||||
|
|
||||||
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
|
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
|
||||||
let itemNode: OverlayMediaItemNode
|
let itemNode: OverlayMediaItemNode
|
||||||
|
@ -16,6 +16,7 @@ import Emoji
|
|||||||
import AppBundle
|
import AppBundle
|
||||||
import ListMessageItem
|
import ListMessageItem
|
||||||
import AccountContext
|
import AccountContext
|
||||||
|
import ChatInterfaceState
|
||||||
|
|
||||||
private class ChatHistoryListSelectionRecognizer: UIPanGestureRecognizer {
|
private class ChatHistoryListSelectionRecognizer: UIPanGestureRecognizer {
|
||||||
private let selectionGestureActivationThreshold: CGFloat = 5.0
|
private let selectionGestureActivationThreshold: CGFloat = 5.0
|
||||||
@ -76,7 +77,7 @@ public enum ChatHistoryListDisplayHeaders {
|
|||||||
|
|
||||||
public enum ChatHistoryListMode: Equatable {
|
public enum ChatHistoryListMode: Equatable {
|
||||||
case bubbles
|
case bubbles
|
||||||
case list(search: Bool, reversed: Bool, displayHeaders: ChatHistoryListDisplayHeaders, isGlobalSearch: Bool)
|
case list(search: Bool, reversed: Bool, displayHeaders: ChatHistoryListDisplayHeaders, hintLinks: Bool, isGlobalSearch: Bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ChatHistoryViewScrollPosition {
|
enum ChatHistoryViewScrollPosition {
|
||||||
@ -249,7 +250,7 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca
|
|||||||
switch mode {
|
switch mode {
|
||||||
case .bubbles:
|
case .bubbles:
|
||||||
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes))
|
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes))
|
||||||
case let .list(_, _, displayHeaders, isGlobalSearch):
|
case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch):
|
||||||
let displayHeader: Bool
|
let displayHeader: Bool
|
||||||
switch displayHeaders {
|
switch displayHeaders {
|
||||||
case .none:
|
case .none:
|
||||||
@ -259,8 +260,7 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca
|
|||||||
case .allButLast:
|
case .allButLast:
|
||||||
displayHeader = listMessageDateHeaderId(timestamp: message.timestamp) != lastHeaderId
|
displayHeader = listMessageDateHeaderId(timestamp: message.timestamp) != lastHeaderId
|
||||||
}
|
}
|
||||||
|
item = ListMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: controllerInteraction), message: message, selection: selection, displayHeader: displayHeader, hintIsLink: hintLinks, isGlobalSearchResult: isGlobalSearch)
|
||||||
item = ListMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: controllerInteraction), message: message, selection: selection, displayHeader: displayHeader, isGlobalSearchResult: isGlobalSearch)
|
|
||||||
}
|
}
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
|
||||||
case let .MessageGroupEntry(_, messages, presentationData):
|
case let .MessageGroupEntry(_, messages, presentationData):
|
||||||
@ -268,7 +268,7 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca
|
|||||||
switch mode {
|
switch mode {
|
||||||
case .bubbles:
|
case .bubbles:
|
||||||
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .group(messages: messages))
|
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .group(messages: messages))
|
||||||
case let .list(_, _, _, _):
|
case let .list(_, _, _, _, _):
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
item = ListMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: controllerInteraction), message: messages[0].0, selection: .none, displayHeader: false)
|
item = ListMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: controllerInteraction), message: messages[0].0, selection: .none, displayHeader: false)
|
||||||
}
|
}
|
||||||
@ -293,7 +293,7 @@ private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLoca
|
|||||||
switch mode {
|
switch mode {
|
||||||
case .bubbles:
|
case .bubbles:
|
||||||
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes))
|
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes))
|
||||||
case let .list(_, _, displayHeaders, isGlobalSearch):
|
case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch):
|
||||||
let displayHeader: Bool
|
let displayHeader: Bool
|
||||||
switch displayHeaders {
|
switch displayHeaders {
|
||||||
case .none:
|
case .none:
|
||||||
@ -303,7 +303,7 @@ private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLoca
|
|||||||
case .allButLast:
|
case .allButLast:
|
||||||
displayHeader = listMessageDateHeaderId(timestamp: message.timestamp) != lastHeaderId
|
displayHeader = listMessageDateHeaderId(timestamp: message.timestamp) != lastHeaderId
|
||||||
}
|
}
|
||||||
item = ListMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: controllerInteraction), message: message, selection: selection, displayHeader: displayHeader, isGlobalSearchResult: isGlobalSearch)
|
item = ListMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: controllerInteraction), message: message, selection: selection, displayHeader: displayHeader, hintIsLink: hintLinks, isGlobalSearchResult: isGlobalSearch)
|
||||||
}
|
}
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
|
||||||
case let .MessageGroupEntry(_, messages, presentationData):
|
case let .MessageGroupEntry(_, messages, presentationData):
|
||||||
@ -311,7 +311,7 @@ private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLoca
|
|||||||
switch mode {
|
switch mode {
|
||||||
case .bubbles:
|
case .bubbles:
|
||||||
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .group(messages: messages))
|
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .group(messages: messages))
|
||||||
case let .list(_, _, _, _):
|
case let .list(_, _, _, _, _):
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
item = ListMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: controllerInteraction), message: messages[0].0, selection: .none, displayHeader: false)
|
item = ListMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: controllerInteraction), message: messages[0].0, selection: .none, displayHeader: false)
|
||||||
}
|
}
|
||||||
@ -762,7 +762,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
|||||||
|
|
||||||
var reverse = false
|
var reverse = false
|
||||||
var includeSearchEntry = false
|
var includeSearchEntry = false
|
||||||
if case let .list(search, reverseValue, _, _) = mode {
|
if case let .list(search, reverseValue, _, _, _) = mode {
|
||||||
includeSearchEntry = search
|
includeSearchEntry = search
|
||||||
reverse = reverseValue
|
reverse = reverseValue
|
||||||
}
|
}
|
||||||
@ -1738,7 +1738,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
|||||||
switch self.mode {
|
switch self.mode {
|
||||||
case .bubbles:
|
case .bubbles:
|
||||||
item = ChatMessageItem(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes))
|
item = ChatMessageItem(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes))
|
||||||
case let .list(_, _, displayHeaders, isGlobalSearch):
|
case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch):
|
||||||
let displayHeader: Bool
|
let displayHeader: Bool
|
||||||
switch displayHeaders {
|
switch displayHeaders {
|
||||||
case .none:
|
case .none:
|
||||||
@ -1748,7 +1748,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
|||||||
case .allButLast:
|
case .allButLast:
|
||||||
displayHeader = listMessageDateHeaderId(timestamp: message.timestamp) != historyView.lastHeaderId
|
displayHeader = listMessageDateHeaderId(timestamp: message.timestamp) != historyView.lastHeaderId
|
||||||
}
|
}
|
||||||
item = ListMessageItem(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: self.controllerInteraction), message: message, selection: selection, displayHeader: displayHeader, isGlobalSearchResult: isGlobalSearch)
|
item = ListMessageItem(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: self.controllerInteraction), message: message, selection: selection, displayHeader: displayHeader, hintIsLink: hintLinks, isGlobalSearchResult: isGlobalSearch)
|
||||||
}
|
}
|
||||||
let updateItem = ListViewUpdateItem(index: index, previousIndex: index, item: item, directionHint: nil)
|
let updateItem = ListViewUpdateItem(index: index, previousIndex: index, item: item, directionHint: nil)
|
||||||
self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [updateItem], options: [.AnimateInsertion], scrollToItem: nil, additionalScrollDistance: 0.0, updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [updateItem], options: [.AnimateInsertion], scrollToItem: nil, additionalScrollDistance: 0.0, updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||||
|
@ -6,6 +6,7 @@ import SyncCore
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import Display
|
import Display
|
||||||
import AccountContext
|
import AccountContext
|
||||||
|
import ChatInterfaceState
|
||||||
|
|
||||||
func preloadedChatHistoryViewForLocation(_ location: ChatHistoryLocationInput, context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, fixedCombinedReadStates: MessageHistoryViewReadState?, tagMask: MessageTags?, additionalData: [AdditionalMessageHistoryViewData], orderStatistics: MessageHistoryViewOrderStatistics = []) -> Signal<ChatHistoryViewUpdate, NoError> {
|
func preloadedChatHistoryViewForLocation(_ location: ChatHistoryLocationInput, context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, fixedCombinedReadStates: MessageHistoryViewReadState?, tagMask: MessageTags?, additionalData: [AdditionalMessageHistoryViewData], orderStatistics: MessageHistoryViewOrderStatistics = []) -> Signal<ChatHistoryViewUpdate, NoError> {
|
||||||
return chatHistoryViewForLocation(location, context: context, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, scheduled: false, fixedCombinedReadStates: fixedCombinedReadStates, tagMask: tagMask, additionalData: additionalData, orderStatistics: orderStatistics)
|
return chatHistoryViewForLocation(location, context: context, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, scheduled: false, fixedCombinedReadStates: fixedCombinedReadStates, tagMask: tagMask, additionalData: additionalData, orderStatistics: orderStatistics)
|
||||||
|
@ -6,6 +6,7 @@ import Postbox
|
|||||||
import Display
|
import Display
|
||||||
import AccountContext
|
import AccountContext
|
||||||
import Emoji
|
import Emoji
|
||||||
|
import ChatInterfaceState
|
||||||
|
|
||||||
struct PossibleContextQueryTypes: OptionSet {
|
struct PossibleContextQueryTypes: OptionSet {
|
||||||
var rawValue: Int32
|
var rawValue: Int32
|
||||||
|
@ -17,6 +17,7 @@ import ContextUI
|
|||||||
import GalleryUI
|
import GalleryUI
|
||||||
import OverlayStatusController
|
import OverlayStatusController
|
||||||
import PresentationDataUtils
|
import PresentationDataUtils
|
||||||
|
import ChatInterfaceState
|
||||||
|
|
||||||
struct PeerSpecificPackData {
|
struct PeerSpecificPackData {
|
||||||
let peer: Peer
|
let peer: Peer
|
||||||
|
@ -6,6 +6,7 @@ import SyncCore
|
|||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import TelegramUIPreferences
|
import TelegramUIPreferences
|
||||||
import AccountContext
|
import AccountContext
|
||||||
|
import ChatInterfaceState
|
||||||
|
|
||||||
enum ChatPresentationInputQueryKind: Int32 {
|
enum ChatPresentationInputQueryKind: Int32 {
|
||||||
case emoji
|
case emoji
|
||||||
|
@ -8,15 +8,11 @@ import SwiftSignalKit
|
|||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import LegacyComponents
|
import LegacyComponents
|
||||||
import AccountContext
|
import AccountContext
|
||||||
|
import ChatInterfaceState
|
||||||
|
|
||||||
private let offsetThreshold: CGFloat = 10.0
|
private let offsetThreshold: CGFloat = 10.0
|
||||||
private let dismissOffsetThreshold: CGFloat = 70.0
|
private let dismissOffsetThreshold: CGFloat = 70.0
|
||||||
|
|
||||||
enum ChatTextInputMediaRecordingButtonMode: Int32 {
|
|
||||||
case audio = 0
|
|
||||||
case video = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
private func findTargetView(_ view: UIView, point: CGPoint) -> UIView? {
|
private func findTargetView(_ view: UIView, point: CGPoint) -> UIView? {
|
||||||
if view.bounds.contains(point) && view.tag == 0x01f2bca {
|
if view.bounds.contains(point) && view.tag == 0x01f2bca {
|
||||||
return view
|
return view
|
||||||
|
@ -11,6 +11,7 @@ import SettingsUI
|
|||||||
import WallpaperResources
|
import WallpaperResources
|
||||||
import MediaResources
|
import MediaResources
|
||||||
import LocationUI
|
import LocationUI
|
||||||
|
import ChatInterfaceState
|
||||||
|
|
||||||
private var telegramUIDeclaredEncodables: Void = {
|
private var telegramUIDeclaredEncodables: Void = {
|
||||||
declareEncodable(InAppNotificationSettings.self, f: { InAppNotificationSettings(decoder: $0) })
|
declareEncodable(InAppNotificationSettings.self, f: { InAppNotificationSettings(decoder: $0) })
|
||||||
|
@ -20,6 +20,7 @@ import LanguageLinkPreviewUI
|
|||||||
import SettingsUI
|
import SettingsUI
|
||||||
import UrlHandling
|
import UrlHandling
|
||||||
import ShareController
|
import ShareController
|
||||||
|
import ChatInterfaceState
|
||||||
|
|
||||||
private func defaultNavigationForPeerId(_ peerId: PeerId?, navigation: ChatControllerInteractionNavigateToPeer) -> ChatControllerInteractionNavigateToPeer {
|
private func defaultNavigationForPeerId(_ peerId: PeerId?, navigation: ChatControllerInteractionNavigateToPeer) -> ChatControllerInteractionNavigateToPeer {
|
||||||
if case .default = navigation {
|
if case .default = navigation {
|
||||||
|
@ -164,7 +164,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
|||||||
|
|
||||||
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||||
|
|
||||||
self.historyNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(initialMessageId), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: currentIsReversed, displayHeaders: .none, isGlobalSearch: isGlobalSearch))
|
self.historyNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(initialMessageId), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: isGlobalSearch))
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -495,7 +495,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
|||||||
}
|
}
|
||||||
|
|
||||||
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||||
let historyNode = ChatHistoryListNode(context: self.context, chatLocation: .peer(self.peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(messageId), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, displayHeaders: .none, isGlobalSearch: self.isGlobalSearch))
|
let historyNode = ChatHistoryListNode(context: self.context, chatLocation: .peer(self.peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(messageId), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch))
|
||||||
historyNode.preloadPages = true
|
historyNode.preloadPages = true
|
||||||
historyNode.stackFromBottom = true
|
historyNode.stackFromBottom = true
|
||||||
historyNode.updateFloatingHeaderOffset = { [weak self] offset, _ in
|
historyNode.updateFloatingHeaderOffset = { [weak self] offset, _ in
|
||||||
|
@ -72,7 +72,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
|||||||
self.selectedMessagesPromise.set(.single(self.selectedMessages))
|
self.selectedMessagesPromise.set(.single(self.selectedMessages))
|
||||||
|
|
||||||
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||||
self.listNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: nil, controllerInteraction: chatControllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(search: false, reversed: false, displayHeaders: .allButLast, isGlobalSearch: false))
|
self.listNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: nil, controllerInteraction: chatControllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(search: false, reversed: false, displayHeaders: .allButLast, hintLinks: tagMask == .webPage, isGlobalSearch: false))
|
||||||
self.listNode.defaultToSynchronousTransactionWhileScrolling = true
|
self.listNode.defaultToSynchronousTransactionWhileScrolling = true
|
||||||
|
|
||||||
if tagMask == .music {
|
if tagMask == .music {
|
||||||
|
@ -51,6 +51,7 @@ import SaveToCameraRoll
|
|||||||
import PeerInfoUI
|
import PeerInfoUI
|
||||||
import ListMessageItem
|
import ListMessageItem
|
||||||
import GalleryData
|
import GalleryData
|
||||||
|
import ChatInterfaceState
|
||||||
|
|
||||||
protocol PeerInfoScreenItem: class {
|
protocol PeerInfoScreenItem: class {
|
||||||
var id: AnyHashable { get }
|
var id: AnyHashable { get }
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import Postbox
|
import Postbox
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
import ChatInterfaceState
|
||||||
|
|
||||||
enum PeerMediaCollectionMode: Int32 {
|
enum PeerMediaCollectionMode: Int32 {
|
||||||
case photoOrVideo
|
case photoOrVideo
|
||||||
|
@ -8,6 +8,7 @@ import OpenInExternalAppUI
|
|||||||
import MusicAlbumArtResources
|
import MusicAlbumArtResources
|
||||||
import LocalMediaResources
|
import LocalMediaResources
|
||||||
import LocationResources
|
import LocationResources
|
||||||
|
import ChatInterfaceState
|
||||||
|
|
||||||
public let telegramAccountAuxiliaryMethods = AccountAuxiliaryMethods(updatePeerChatInputState: { interfaceState, inputState -> PeerChatInterfaceState? in
|
public let telegramAccountAuxiliaryMethods = AccountAuxiliaryMethods(updatePeerChatInputState: { interfaceState, inputState -> PeerChatInterfaceState? in
|
||||||
if interfaceState == nil {
|
if interfaceState == nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user