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 AccountContext
|
||||
|
||||
struct ChatInterfaceSelectionState: PostboxCoding, Equatable {
|
||||
let selectedIds: Set<MessageId>
|
||||
public enum ChatTextInputMediaRecordingButtonMode: Int32 {
|
||||
case audio = 0
|
||||
case video = 1
|
||||
}
|
||||
|
||||
static func ==(lhs: ChatInterfaceSelectionState, rhs: ChatInterfaceSelectionState) -> Bool {
|
||||
public struct ChatInterfaceSelectionState: PostboxCoding, Equatable {
|
||||
public let selectedIds: Set<MessageId>
|
||||
|
||||
public static func ==(lhs: ChatInterfaceSelectionState, rhs: ChatInterfaceSelectionState) -> Bool {
|
||||
return lhs.selectedIds == rhs.selectedIds
|
||||
}
|
||||
|
||||
init(selectedIds: Set<MessageId>) {
|
||||
public init(selectedIds: Set<MessageId>) {
|
||||
self.selectedIds = selectedIds
|
||||
}
|
||||
|
||||
init(decoder: PostboxDecoder) {
|
||||
public init(decoder: PostboxDecoder) {
|
||||
if let data = decoder.decodeBytesForKeyNoCopy("i") {
|
||||
self.selectedIds = Set(MessageId.decodeArrayFromBuffer(data))
|
||||
} else {
|
||||
@ -25,27 +30,27 @@ struct ChatInterfaceSelectionState: PostboxCoding, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
func encode(_ encoder: PostboxEncoder) {
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
let buffer = WriteBuffer()
|
||||
MessageId.encodeArrayToBuffer(Array(selectedIds), buffer: buffer)
|
||||
encoder.encodeBytes(buffer, forKey: "i")
|
||||
}
|
||||
}
|
||||
|
||||
struct ChatEditMessageState: PostboxCoding, Equatable {
|
||||
let messageId: MessageId
|
||||
let inputState: ChatTextInputState
|
||||
let disableUrlPreview: String?
|
||||
let inputTextMaxLength: Int32?
|
||||
public struct ChatEditMessageState: PostboxCoding, Equatable {
|
||||
public let messageId: MessageId
|
||||
public let inputState: ChatTextInputState
|
||||
public let disableUrlPreview: String?
|
||||
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.inputState = inputState
|
||||
self.disableUrlPreview = disableUrlPreview
|
||||
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))
|
||||
if let inputState = decoder.decodeObjectForKey("is", decoder: { return ChatTextInputState(decoder: $0) }) as? ChatTextInputState {
|
||||
self.inputState = inputState
|
||||
@ -56,7 +61,7 @@ struct ChatEditMessageState: PostboxCoding, Equatable {
|
||||
self.inputTextMaxLength = decoder.decodeOptionalInt32ForKey("tl")
|
||||
}
|
||||
|
||||
func encode(_ encoder: PostboxEncoder) {
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeInt64(self.messageId.peerId.toInt64(), forKey: "mp")
|
||||
encoder.encodeInt32(self.messageId.namespace, forKey: "mn")
|
||||
encoder.encodeInt32(self.messageId.id, forKey: "mi")
|
||||
@ -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
|
||||
}
|
||||
|
||||
func withUpdatedInputState(_ inputState: ChatTextInputState) -> ChatEditMessageState {
|
||||
public func withUpdatedInputState(_ inputState: ChatTextInputState) -> ChatEditMessageState {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
||||
var closedButtonKeyboardMessageId: MessageId?
|
||||
var processedSetupReplyMessageId: MessageId?
|
||||
var closedPinnedMessageId: MessageId?
|
||||
var closedPeerSpecificPackSetup: Bool = false
|
||||
var dismissedAddContactPhoneNumber: String?
|
||||
public struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
||||
public var closedButtonKeyboardMessageId: MessageId?
|
||||
public var processedSetupReplyMessageId: MessageId?
|
||||
public var closedPinnedMessageId: MessageId?
|
||||
public var closedPeerSpecificPackSetup: Bool = false
|
||||
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
|
||||
}
|
||||
|
||||
init() {
|
||||
public init() {
|
||||
self.closedButtonKeyboardMessageId = nil
|
||||
self.processedSetupReplyMessageId = nil
|
||||
self.closedPinnedMessageId = nil
|
||||
@ -105,7 +110,7 @@ struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
||||
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.processedSetupReplyMessageId = processedSetupReplyMessageId
|
||||
self.closedPinnedMessageId = closedPinnedMessageId
|
||||
@ -113,7 +118,7 @@ struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
||||
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") {
|
||||
self.closedButtonKeyboardMessageId = MessageId(peerId: PeerId(closedMessageIdPeerId), namespace: closedMessageIdNamespace, id: closedMessageIdId)
|
||||
} else {
|
||||
@ -135,7 +140,7 @@ struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
||||
self.closedPeerSpecificPackSetup = decoder.decodeInt32ForKey("cpss", orElse: 0) != 0
|
||||
}
|
||||
|
||||
func encode(_ encoder: PostboxEncoder) {
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
if let closedButtonKeyboardMessageId = self.closedButtonKeyboardMessageId {
|
||||
encoder.encodeInt64(closedButtonKeyboardMessageId.peerId.toInt64(), forKey: "cb.p")
|
||||
encoder.encodeInt32(closedButtonKeyboardMessageId.namespace, forKey: "cb.n")
|
||||
@ -176,21 +181,21 @@ struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
struct ChatInterfaceHistoryScrollState: PostboxCoding, Equatable {
|
||||
let messageIndex: MessageIndex
|
||||
let relativeOffset: Double
|
||||
public struct ChatInterfaceHistoryScrollState: PostboxCoding, Equatable {
|
||||
public let messageIndex: MessageIndex
|
||||
public let relativeOffset: Double
|
||||
|
||||
init(messageIndex: MessageIndex, relativeOffset: Double) {
|
||||
public init(messageIndex: MessageIndex, relativeOffset: Double) {
|
||||
self.messageIndex = messageIndex
|
||||
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.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.encodeInt64(self.messageIndex.id.peerId.toInt64(), forKey: "m.p")
|
||||
encoder.encodeInt32(self.messageIndex.id.namespace, forKey: "m.n")
|
||||
@ -198,7 +203,7 @@ struct ChatInterfaceHistoryScrollState: PostboxCoding, Equatable {
|
||||
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 {
|
||||
return false
|
||||
}
|
||||
@ -210,18 +215,18 @@ struct ChatInterfaceHistoryScrollState: PostboxCoding, Equatable {
|
||||
}
|
||||
|
||||
public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equatable {
|
||||
let timestamp: Int32
|
||||
let composeInputState: ChatTextInputState
|
||||
let composeDisableUrlPreview: String?
|
||||
let replyMessageId: MessageId?
|
||||
let forwardMessageIds: [MessageId]?
|
||||
let editMessage: ChatEditMessageState?
|
||||
let selectionState: ChatInterfaceSelectionState?
|
||||
let messageActionsState: ChatInterfaceMessageActionsState
|
||||
let historyScrollState: ChatInterfaceHistoryScrollState?
|
||||
let mediaRecordingMode: ChatTextInputMediaRecordingButtonMode
|
||||
let silentPosting: Bool
|
||||
let inputLanguage: String?
|
||||
public let timestamp: Int32
|
||||
public let composeInputState: ChatTextInputState
|
||||
public let composeDisableUrlPreview: String?
|
||||
public let replyMessageId: MessageId?
|
||||
public let forwardMessageIds: [MessageId]?
|
||||
public let editMessage: ChatEditMessageState?
|
||||
public let selectionState: ChatInterfaceSelectionState?
|
||||
public let messageActionsState: ChatInterfaceMessageActionsState
|
||||
public let historyScrollState: ChatInterfaceHistoryScrollState?
|
||||
public let mediaRecordingMode: ChatTextInputMediaRecordingButtonMode
|
||||
public let silentPosting: Bool
|
||||
public let inputLanguage: String?
|
||||
|
||||
public var associatedMessageIds: [MessageId] {
|
||||
var ids: [MessageId] = []
|
||||
@ -259,7 +264,7 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
||||
return result
|
||||
}
|
||||
|
||||
var effectiveInputState: ChatTextInputState {
|
||||
public var effectiveInputState: ChatTextInputState {
|
||||
if let editMessage = self.editMessage {
|
||||
return editMessage.inputState
|
||||
} else {
|
||||
@ -282,7 +287,7 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
||||
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.composeInputState = composeInputState
|
||||
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
|
||||
}
|
||||
|
||||
func withUpdatedComposeInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
|
||||
public func withUpdatedComposeInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func withUpdatedEffectiveInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
|
||||
public func withUpdatedEffectiveInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
|
||||
var updatedEditMessage = self.editMessage
|
||||
var updatedComposeInputState = self.composeInputState
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func withUpdatedSelectedMessages(_ messageIds: [MessageId]) -> ChatInterfaceState {
|
||||
public func withUpdatedSelectedMessages(_ messageIds: [MessageId]) -> ChatInterfaceState {
|
||||
var selectedIds = Set<MessageId>()
|
||||
if let selectionState = self.selectionState {
|
||||
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)
|
||||
}
|
||||
|
||||
func withToggledSelectedMessages(_ messageIds: [MessageId], value: Bool) -> ChatInterfaceState {
|
||||
public func withToggledSelectedMessages(_ messageIds: [MessageId], value: Bool) -> ChatInterfaceState {
|
||||
var selectedIds = Set<MessageId>()
|
||||
if let selectionState = self.selectionState {
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ static_library(
|
||||
"//submodules/GalleryData:GalleryData",
|
||||
"//submodules/InstantPageUI:InstantPageUI",
|
||||
"//submodules/ListSectionHeaderNode:ListSectionHeaderNode",
|
||||
"//submodules/ChatInterfaceState:ChatInterfaceState",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -52,6 +52,8 @@ swift_library(
|
||||
"//submodules/GalleryData:GalleryData",
|
||||
"//submodules/InstantPageUI:InstantPageUI",
|
||||
"//submodules/ListSectionHeaderNode:ListSectionHeaderNode",
|
||||
"//submodules/ChatInterfaceState:ChatInterfaceState",
|
||||
"//submodules/ShareController:ShareController",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -27,6 +27,8 @@ import AnimatedStickerNode
|
||||
import AppBundle
|
||||
import GalleryData
|
||||
import InstantPageUI
|
||||
import ChatInterfaceState
|
||||
import ShareController
|
||||
|
||||
private final class PassthroughContainerNode: ASDisplayNode {
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
@ -595,20 +597,26 @@ public func chatListSearchContainerPreparedTransition(from fromEntries: [ChatLis
|
||||
|
||||
private struct ChatListSearchContainerNodeState: Equatable {
|
||||
let peerIdWithRevealedOptions: PeerId?
|
||||
let selectedMessageIds: Set<MessageId>?
|
||||
|
||||
init(peerIdWithRevealedOptions: PeerId? = nil) {
|
||||
init(peerIdWithRevealedOptions: PeerId? = nil, selectedMessageIds: Set<MessageId>? = nil) {
|
||||
self.peerIdWithRevealedOptions = peerIdWithRevealedOptions
|
||||
self.selectedMessageIds = selectedMessageIds
|
||||
}
|
||||
|
||||
static func ==(lhs: ChatListSearchContainerNodeState, rhs: ChatListSearchContainerNodeState) -> Bool {
|
||||
if lhs.peerIdWithRevealedOptions != rhs.peerIdWithRevealedOptions {
|
||||
if lhs.peerIdWithRevealedOptions != rhs.peerIdWithRevealedOptions || lhs.selectedMessageIds != rhs.selectedMessageIds {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
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 {
|
||||
private let context: AccountContext
|
||||
private let filter: ChatListNodePeersFilter
|
||||
private let peersFilter: ChatListNodePeersFilter
|
||||
private var interaction: ChatListNodeInteraction?
|
||||
private let openMessage: (Peer, MessageId) -> Void
|
||||
private let navigationController: NavigationController?
|
||||
|
||||
let filterContainerNode: ChatListSearchFiltersContainerNode
|
||||
private var selectionPanelNode: ChatListSearchMessageSelectionPanelNode?
|
||||
private let recentListNode: ListView
|
||||
private let listNode: ListView
|
||||
private let mediaNode: ChatListSearchMediaNode
|
||||
@ -695,8 +704,11 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
private var enqueuedTransitions: [(ChatListSearchContainerTransition, Bool)] = []
|
||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||
|
||||
private var present: ((ViewController, Any?) -> Void)?
|
||||
private var presentInGlobalOverlay: ((ViewController, Any?) -> Void)?
|
||||
|
||||
private let activeActionDisposable = MetaDisposable()
|
||||
|
||||
private let recentDisposable = 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) {
|
||||
self.context = context
|
||||
self.filter = filter
|
||||
self.peersFilter = filter
|
||||
self.dimNode = ASDisplayNode()
|
||||
self.navigationController = navigationController
|
||||
self.updatedSearchOptions = updatedSearchOptions
|
||||
|
||||
self.present = present
|
||||
self.presentInGlobalOverlay = presentInGlobalOverlay
|
||||
|
||||
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)
|
||||
@ -1621,6 +1638,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.activeActionDisposable.dispose()
|
||||
self.updatedRecentPeersDisposable.dispose()
|
||||
self.recentDisposable.dispose()
|
||||
self.searchDisposable.dispose()
|
||||
@ -1701,8 +1719,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
}
|
||||
|
||||
private func updateTheme(theme: PresentationTheme) {
|
||||
self.backgroundColor = self.filter.contains(.excludeRecent) ? nil : theme.chatList.backgroundColor
|
||||
self.dimNode.backgroundColor = self.filter.contains(.excludeRecent) ? UIColor.black.withAlphaComponent(0.5) : theme.chatList.backgroundColor
|
||||
self.backgroundColor = self.peersFilter.contains(.excludeRecent) ? nil : 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.listNode.verticalScrollIndicatorColor = theme.list.scrollIndicatorColor
|
||||
|
||||
@ -1811,9 +1829,9 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
strongSelf.emptyResultsTextNode.isHidden = !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.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 {
|
||||
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)))
|
||||
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)
|
||||
|
||||
self.recentListNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
@ -2180,16 +2258,19 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Conversation_ContextMenuMore, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/More"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { _, f in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateState { state in
|
||||
return state.withUpdatedSelectedMessageIds([message.id])
|
||||
}
|
||||
// strongSelf.chatInterfaceInteraction.toggleMessagesSelection([message.id], true)
|
||||
// strongSelf.expandTabs()
|
||||
|
||||
if let (layout, navigationBarHeight) = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
f(.default)
|
||||
})))
|
||||
|
||||
// }
|
||||
|
||||
switch previewData {
|
||||
case let .gallery(gallery):
|
||||
gallery.setHintWillBePresentedInPreviewingContext(true)
|
||||
@ -2245,12 +2326,17 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
})))
|
||||
|
||||
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: {
|
||||
// if let strongSelf = self {
|
||||
// strongSelf.chatInterfaceInteraction.toggleMessagesSelection([message.id], true)
|
||||
// strongSelf.expandTabs()
|
||||
// }
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateState { state in
|
||||
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.setQuery?(nil, [], self.searchQueryValue ?? "")
|
||||
}
|
||||
func deleteMessages(messageIds: Set<MessageId>?) {
|
||||
|
||||
}
|
||||
|
||||
func forwardMessages(messageIds: Set<MessageId>?) {
|
||||
// if let messageIds = messageIds, !messageIds.isEmpty {
|
||||
// let peerSelectionController = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: [.onlyWriteable, .excludeDisabled]))
|
||||
// peerSelectionController.peerSelected = { [weak self, weak peerSelectionController] peerId in
|
||||
// if let strongSelf = self, let _ = peerSelectionController {
|
||||
// if peerId == strongSelf.context.account.peerId {
|
||||
//// strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone)
|
||||
//
|
||||
// let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: messageIds.map { id -> EnqueueMessage in
|
||||
// return .forward(source: id, grouping: .auto, attributes: [])
|
||||
// })
|
||||
// |> deliverOnMainQueue).start(next: { [weak self] messageIds in
|
||||
// if let strongSelf = self {
|
||||
// let signals: [Signal<Bool, NoError>] = messageIds.compactMap({ id -> Signal<Bool, NoError>? in
|
||||
// guard let id = id else {
|
||||
// return nil
|
||||
// }
|
||||
// return strongSelf.context.account.pendingMessageManager.pendingMessageStatus(id)
|
||||
// |> mapToSignal { status, _ -> Signal<Bool, NoError> in
|
||||
// if status != nil {
|
||||
// return .never()
|
||||
// } else {
|
||||
// return .single(true)
|
||||
// }
|
||||
// }
|
||||
// |> take(1)
|
||||
// })
|
||||
// strongSelf.activeActionDisposable.set((combineLatest(signals)
|
||||
// |> deliverOnMainQueue).start(completed: {
|
||||
// guard let strongSelf = self else {
|
||||
// return
|
||||
// }
|
||||
// strongSelf.controller?.present(OverlayStatusController(theme: strongSelf.presentationData.theme, type: .success), in: .window(.root))
|
||||
// }))
|
||||
// }
|
||||
// })
|
||||
// if let peerSelectionController = peerSelectionController {
|
||||
// peerSelectionController.dismiss()
|
||||
// }
|
||||
// } else {
|
||||
// let _ = (strongSelf.context.account.postbox.transaction({ transaction -> Void in
|
||||
// transaction.updatePeerChatInterfaceState(peerId, update: { currentState in
|
||||
// if let currentState = currentState as? ChatInterfaceState {
|
||||
// return currentState.withUpdatedForwardMessageIds(Array(messageIds))
|
||||
// } else {
|
||||
// return ChatInterfaceState().withUpdatedForwardMessageIds(Array(messageIds))
|
||||
// }
|
||||
// })
|
||||
// }) |> deliverOnMainQueue).start(completed: {
|
||||
// if let strongSelf = self {
|
||||
if let messageIds = messageIds, !messageIds.isEmpty {
|
||||
let peerSelectionController = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: [.onlyWriteable, .excludeDisabled]))
|
||||
peerSelectionController.peerSelected = { [weak self, weak peerSelectionController] peerId in
|
||||
if let strongSelf = self, let _ = peerSelectionController {
|
||||
if peerId == strongSelf.context.account.peerId {
|
||||
// strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone)
|
||||
//
|
||||
// let ready = Promise<Bool>()
|
||||
// strongSelf.activeActionDisposable.set((ready.get() |> filter { $0 } |> take(1) |> deliverOnMainQueue).start(next: { _ in
|
||||
// if let peerSelectionController = peerSelectionController {
|
||||
// peerSelectionController.dismiss()
|
||||
// }
|
||||
// }))
|
||||
//
|
||||
// (strongSelf.controller?.navigationController as? NavigationController)?.replaceTopController(ChatControllerImpl(context: strongSelf.context, chatLocation: .peer(peerId)), animated: false, ready: ready)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// self.controller?.push(peerSelectionController)
|
||||
// }
|
||||
|
||||
let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: messageIds.map { id -> EnqueueMessage in
|
||||
return .forward(source: id, grouping: .auto, attributes: [])
|
||||
})
|
||||
|> deliverOnMainQueue).start(next: { [weak self] messageIds in
|
||||
if let strongSelf = self {
|
||||
let signals: [Signal<Bool, NoError>] = messageIds.compactMap({ id -> Signal<Bool, NoError>? in
|
||||
guard let id = id else {
|
||||
return nil
|
||||
}
|
||||
return strongSelf.context.account.pendingMessageManager.pendingMessageStatus(id)
|
||||
|> mapToSignal { status, _ -> Signal<Bool, NoError> in
|
||||
if status != nil {
|
||||
return .never()
|
||||
} else {
|
||||
return .single(true)
|
||||
}
|
||||
}
|
||||
|> take(1)
|
||||
})
|
||||
strongSelf.activeActionDisposable.set((combineLatest(signals)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.present?(OverlayStatusController(theme: strongSelf.presentationData.theme, type: .success), nil)
|
||||
}))
|
||||
}
|
||||
})
|
||||
if let peerSelectionController = peerSelectionController {
|
||||
peerSelectionController.dismiss()
|
||||
}
|
||||
} else {
|
||||
let _ = (strongSelf.context.account.postbox.transaction({ transaction -> Void in
|
||||
transaction.updatePeerChatInterfaceState(peerId, update: { currentState in
|
||||
if let currentState = currentState as? ChatInterfaceState {
|
||||
return currentState.withUpdatedForwardMessageIds(Array(messageIds))
|
||||
} else {
|
||||
return ChatInterfaceState().withUpdatedForwardMessageIds(Array(messageIds))
|
||||
}
|
||||
})
|
||||
}) |> deliverOnMainQueue).start(completed: {
|
||||
if let strongSelf = self {
|
||||
// strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone)
|
||||
|
||||
let ready = Promise<Bool>()
|
||||
let signal = ready.get()
|
||||
|> filter({ $0 })
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue
|
||||
|
||||
strongSelf.activeActionDisposable.set(signal.start(next: { _ in
|
||||
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))
|
||||
strongSelf.navigationController?.replaceTopController(controller, animated: false, ready: ready)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
self.navigationController?.pushViewController(peerSelectionController)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ import UniversalMediaPlayer
|
||||
import ListMessageItem
|
||||
import ListSectionHeaderNode
|
||||
import ChatMessageInteractiveMediaBadge
|
||||
import ShimmerEffect
|
||||
|
||||
private let mediaBadgeBackgroundColor = UIColor(white: 0.0, alpha: 0.6)
|
||||
private let mediaBadgeTextColor = UIColor.white
|
||||
@ -41,8 +42,6 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
||||
private let context: AccountContext
|
||||
private let interaction: VisualMediaItemInteraction
|
||||
|
||||
// private var videoLayerFrameManager: SoftwareVideoLayerFrameManager?
|
||||
// private var sampleBufferLayer: SampleBufferLayer?
|
||||
private var displayLink: ConstantDisplayLinkAnimator?
|
||||
private var displayLinkTimestamp: Double = 0.0
|
||||
|
||||
@ -50,6 +49,7 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
||||
private let imageNode: TransformImageNode
|
||||
private var statusNode: RadialStatusNode
|
||||
private let mediaBadgeNode: ChatMessageInteractiveMediaBadge
|
||||
private var placeholderNode: ShimmerEffectNode?
|
||||
|
||||
private let fetchStatusDisposable = MetaDisposable()
|
||||
private let fetchDisposable = MetaDisposable()
|
||||
@ -84,7 +84,9 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
||||
guard let strongSelf = self, let item = strongSelf.item else {
|
||||
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) {
|
||||
guard let message = self.item?.0.message else {
|
||||
return
|
||||
}
|
||||
if case .ended = recognizer.state {
|
||||
if let (gesture, _) = recognizer.lastRecognizedGestureAndLocation {
|
||||
if case .tap = gesture {
|
||||
if let (item, _, _, _) = self.item {
|
||||
var media: Media?
|
||||
for value in item.message.media {
|
||||
for value in message.media {
|
||||
if let image = value as? TelegramMediaImage {
|
||||
media = image
|
||||
break
|
||||
@ -125,13 +130,13 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
||||
|
||||
if let media = media {
|
||||
if let file = media as? TelegramMediaFile {
|
||||
if isMediaStreamable(message: item.message, media: file) {
|
||||
self.interaction.openMessage(item.message)
|
||||
if isMediaStreamable(message: message, media: file) {
|
||||
self.interaction.openMessage(message)
|
||||
} else {
|
||||
self.progressPressed()
|
||||
}
|
||||
} else {
|
||||
self.interaction.openMessage(item.message)
|
||||
self.interaction.openMessage(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -172,13 +177,18 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
||||
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) {
|
||||
if item === self.item?.0 && size == self.item?.2 {
|
||||
return
|
||||
}
|
||||
self.theme = theme
|
||||
var media: Media?
|
||||
for value in item.message.media {
|
||||
if let message = item.message {
|
||||
for value in message.media {
|
||||
if let image = value as? TelegramMediaImage {
|
||||
media = image
|
||||
break
|
||||
@ -187,35 +197,14 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if let file = media as? TelegramMediaFile, file.isAnimated {
|
||||
// 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!)) {
|
||||
if let media = media, (self.item?.1 == nil || !media.isEqual(to: self.item!.1!)), let message = item.message {
|
||||
var mediaDimensions: CGSize?
|
||||
if let image = media as? TelegramMediaImage, let largestSize = largestImageRepresentation(image.representations)?.dimensions {
|
||||
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.statusNode.transitionToState(.none, completion: { [weak self] in
|
||||
@ -225,7 +214,7 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
||||
self.resourceStatus = nil
|
||||
} else if let file = media as? TelegramMediaFile, file.isVideo {
|
||||
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
|
||||
|
||||
@ -233,12 +222,12 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
||||
|
||||
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
|
||||
if let strongSelf = self, let (item, _, _, _) = strongSelf.item {
|
||||
strongSelf.resourceStatus = status
|
||||
|
||||
let isStreamable = isMediaStreamable(message: item.message, media: file)
|
||||
let isStreamable = isMediaStreamable(message: message, media: file)
|
||||
|
||||
var statusState: RadialStatusNodeState = .none
|
||||
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.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 {
|
||||
self.item = (item, media, size, mediaDimensions)
|
||||
|
||||
let imageFrame = CGRect(origin: CGPoint(), size: size)
|
||||
|
||||
self.containerNode.frame = imageFrame
|
||||
self.imageNode.frame = imageFrame
|
||||
// if let sampleBufferLayer = self.sampleBufferLayer {
|
||||
// sampleBufferLayer.layer.frame = imageFrame
|
||||
// }
|
||||
|
||||
if let mediaDimensions = mediaDimensions {
|
||||
let imageSize = mediaDimensions.aspectFilled(imageFrame.size)
|
||||
@ -379,8 +376,8 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
func updateHiddenMedia() {
|
||||
if let (item, _, _, _) = self.item {
|
||||
if let _ = self.interaction.hiddenMedia[item.message.id] {
|
||||
if let (item, _, _, _) = self.item, let message = item.message {
|
||||
if let _ = self.interaction.hiddenMedia[message.id] {
|
||||
self.isHidden = true
|
||||
} else {
|
||||
self.isHidden = false
|
||||
@ -393,11 +390,22 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
private final class VisualMediaItem {
|
||||
let message: Message
|
||||
let index: UInt32?
|
||||
let message: Message?
|
||||
let dimensions: CGSize
|
||||
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) {
|
||||
self.index = nil
|
||||
self.message = message
|
||||
|
||||
var aspectRatio: CGFloat = 1.0
|
||||
@ -412,6 +420,17 @@ private final class VisualMediaItem {
|
||||
}
|
||||
self.aspectRatio = aspectRatio
|
||||
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,29 +699,40 @@ final class ChatListSearchMediaNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
|
||||
|
||||
func updateHistory(entries: [ChatListSearchEntry], totalCount: Int32, updateType: ViewUpdateType) {
|
||||
func updateHistory(entries: [ChatListSearchEntry]?, totalCount: Int32, updateType: ViewUpdateType) {
|
||||
switch updateType {
|
||||
case .FillHole:
|
||||
break
|
||||
default:
|
||||
self.mediaItems.removeAll()
|
||||
let loading: Bool
|
||||
if let entries = entries {
|
||||
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
|
||||
|
||||
let wasInitialized = self.initialized
|
||||
self.initialized = true
|
||||
|
||||
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.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 {
|
||||
self.didSetReady = true
|
||||
self.ready.set(.single(true))
|
||||
@ -722,7 +752,7 @@ final class ChatListSearchMediaNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
|
||||
func findLoadedMessage(id: MessageId) -> Message? {
|
||||
for item in self.mediaItems {
|
||||
if item.message.id == id {
|
||||
if item.message?.id == id {
|
||||
return item.message
|
||||
}
|
||||
}
|
||||
@ -743,8 +773,8 @@ final class ChatListSearchMediaNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
|
||||
func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
|
||||
for item in self.mediaItems {
|
||||
if item.message.id == messageId {
|
||||
if let itemNode = self.visibleMediaItems[item.message.stableId] {
|
||||
if let message = item.message, message.id == messageId {
|
||||
if let itemNode = self.visibleMediaItems[message.stableId] {
|
||||
return itemNode.transitionNode()
|
||||
}
|
||||
break
|
||||
@ -855,7 +885,7 @@ final class ChatListSearchMediaNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
var validIds = Set<UInt32>()
|
||||
if minVisibleIndex <= maxVisibleIndex {
|
||||
for i in minVisibleIndex ... maxVisibleIndex {
|
||||
let stableId = self.mediaItems[i].message.stableId
|
||||
let stableId = self.mediaItems[i].stableId
|
||||
validIds.insert(stableId)
|
||||
|
||||
let itemFrame = itemsLayout.frame(forItemAt: i, sideInset: sideInset)
|
||||
@ -869,6 +899,7 @@ final class ChatListSearchMediaNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
self.scrollNode.addSubnode(itemNode)
|
||||
}
|
||||
itemNode.frame = itemFrame
|
||||
itemNode.updateAbsoluteRect(itemFrame, within: self.scrollNode.view.bounds.size)
|
||||
if headerItem == nil && itemFrame.maxY > headerItemMinY {
|
||||
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 message: Message
|
||||
let selection: ChatHistoryMessageSelection
|
||||
let hintIsLink: Bool
|
||||
let isGlobalSearchResult: Bool
|
||||
|
||||
let header: ListViewItemHeader?
|
||||
|
||||
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.context = context
|
||||
self.chatLocation = chatLocation
|
||||
@ -57,18 +58,21 @@ public final class ListMessageItem: ListViewItem {
|
||||
self.header = nil
|
||||
}
|
||||
self.selection = selection
|
||||
self.hintIsLink = hintIsLink
|
||||
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) {
|
||||
var viewClassName: AnyClass = ListMessageSnippetItemNode.self
|
||||
|
||||
if !self.hintIsLink {
|
||||
for media in self.message.media {
|
||||
if let _ = media as? TelegramMediaFile {
|
||||
viewClassName = ListMessageFileItemNode.self
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let configure = { () -> Void in
|
||||
let node = (viewClassName as! ListMessageNode.Type).init()
|
||||
|
@ -128,6 +128,12 @@ private class SearchBarTextField: UITextField {
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
}
|
||||
var selectedTokenIndex: Int? {
|
||||
didSet {
|
||||
self.layoutTokens(transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
}
|
||||
|
||||
var theme: SearchBarNodeTheme
|
||||
|
||||
|
@ -354,7 +354,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
|
||||
controlColor: UIColor(rgb: 0x7e8791),
|
||||
accentTextColor: UIColor(rgb: 0x007ee5),
|
||||
backgroundColor: UIColor(rgb: 0xf7f7f7),
|
||||
separatorColor: UIColor(rgb: 0xb1b1b1),
|
||||
separatorColor: UIColor(rgb: 0xc8c7cc),
|
||||
badgeBackgroundColor: UIColor(rgb: 0xff3b30),
|
||||
badgeStrokeColor: UIColor(rgb: 0xff3b30),
|
||||
badgeTextColor: UIColor(rgb: 0xffffff),
|
||||
@ -374,7 +374,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
|
||||
inputPlaceholderTextColor: UIColor(rgb: 0x8e8e93),
|
||||
inputIconColor: UIColor(rgb: 0x8e8e93),
|
||||
inputClearButtonColor: UIColor(rgb: 0x7b7b81),
|
||||
separatorColor: UIColor(rgb: 0xb1b1b1)
|
||||
separatorColor: UIColor(rgb: 0xc8c7cc)
|
||||
)
|
||||
|
||||
let rootController = PresentationThemeRootController(
|
||||
@ -685,7 +685,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
|
||||
|
||||
let historyNavigation = PresentationThemeChatHistoryNavigation(
|
||||
fillColor: UIColor(rgb: 0xf7f7f7),
|
||||
strokeColor: UIColor(rgb: 0xb1b1b1),
|
||||
strokeColor: UIColor(rgb: 0xc8c7cc),
|
||||
foregroundColor: UIColor(rgb: 0x88888d),
|
||||
badgeBackgroundColor: UIColor(rgb: 0x007ee5),
|
||||
badgeStrokeColor: UIColor(rgb: 0x007ee5),
|
||||
@ -751,7 +751,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
|
||||
backgroundColor: UIColor(rgb: 0xffffff),
|
||||
primaryTextColor: UIColor(rgb: 0x000000),
|
||||
controlColor: UIColor(rgb: 0x7e8791),
|
||||
separatorColor: UIColor(rgb: 0xb1b1b1)
|
||||
separatorColor: UIColor(rgb: 0xc8c7cc)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -210,6 +210,7 @@ framework(
|
||||
"//submodules/FileMediaResourceStatus:FileMediaResourceStatus",
|
||||
"//submodules/ChatMessageInteractiveMediaBadge:ChatMessageInteractiveMediaBadge",
|
||||
"//submodules/GalleryData:GalleryData",
|
||||
"//submodules/ChatInterfaceState:ChatInterfaceState",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -205,6 +205,7 @@ swift_library(
|
||||
"//submodules/FileMediaResourceStatus:FileMediaResourceStatus",
|
||||
"//submodules/ChatMessageInteractiveMediaBadge:ChatMessageInteractiveMediaBadge",
|
||||
"//submodules/GalleryData:GalleryData",
|
||||
"//submodules/ChatInterfaceState:ChatInterfaceState",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -4,7 +4,6 @@ import Display
|
||||
import AsyncDisplayKit
|
||||
|
||||
private final class AudioWaveformNodeParameters: NSObject {
|
||||
|
||||
let waveform: AudioWaveform?
|
||||
let color: UIColor?
|
||||
let gravity: AudioWaveformNode.Gravity?
|
||||
@ -21,9 +20,7 @@ private final class AudioWaveformNodeParameters: NSObject {
|
||||
}
|
||||
|
||||
final class AudioWaveformNode: ASDisplayNode {
|
||||
|
||||
enum Gravity {
|
||||
|
||||
case bottom
|
||||
case center
|
||||
}
|
||||
|
@ -62,6 +62,7 @@ import TooltipUI
|
||||
import StatisticsUI
|
||||
import MediaResources
|
||||
import GalleryData
|
||||
import ChatInterfaceState
|
||||
|
||||
extension ChatLocation {
|
||||
var peerId: PeerId {
|
||||
|
@ -10,6 +10,7 @@ import AccountContext
|
||||
import TextSelectionNode
|
||||
import ReactionSelectionNode
|
||||
import ContextUI
|
||||
import ChatInterfaceState
|
||||
|
||||
struct ChatInterfaceHighlightedState: Equatable {
|
||||
let messageStableId: UInt32
|
||||
|
@ -13,6 +13,7 @@ import AccountContext
|
||||
import TelegramNotices
|
||||
import ReactionSelectionNode
|
||||
import TelegramUniversalVideoContent
|
||||
import ChatInterfaceState
|
||||
|
||||
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
|
||||
let itemNode: OverlayMediaItemNode
|
||||
|
@ -16,6 +16,7 @@ import Emoji
|
||||
import AppBundle
|
||||
import ListMessageItem
|
||||
import AccountContext
|
||||
import ChatInterfaceState
|
||||
|
||||
private class ChatHistoryListSelectionRecognizer: UIPanGestureRecognizer {
|
||||
private let selectionGestureActivationThreshold: CGFloat = 5.0
|
||||
@ -76,7 +77,7 @@ public enum ChatHistoryListDisplayHeaders {
|
||||
|
||||
public enum ChatHistoryListMode: Equatable {
|
||||
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 {
|
||||
@ -249,7 +250,7 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca
|
||||
switch mode {
|
||||
case .bubbles:
|
||||
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
|
||||
switch displayHeaders {
|
||||
case .none:
|
||||
@ -259,8 +260,7 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca
|
||||
case .allButLast:
|
||||
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 ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
|
||||
case let .MessageGroupEntry(_, messages, presentationData):
|
||||
@ -268,7 +268,7 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca
|
||||
switch mode {
|
||||
case .bubbles:
|
||||
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .group(messages: messages))
|
||||
case let .list(_, _, _, _):
|
||||
case let .list(_, _, _, _, _):
|
||||
assertionFailure()
|
||||
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 {
|
||||
case .bubbles:
|
||||
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
|
||||
switch displayHeaders {
|
||||
case .none:
|
||||
@ -303,7 +303,7 @@ private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLoca
|
||||
case .allButLast:
|
||||
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)
|
||||
case let .MessageGroupEntry(_, messages, presentationData):
|
||||
@ -311,7 +311,7 @@ private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLoca
|
||||
switch mode {
|
||||
case .bubbles:
|
||||
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .group(messages: messages))
|
||||
case let .list(_, _, _, _):
|
||||
case let .list(_, _, _, _, _):
|
||||
assertionFailure()
|
||||
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 includeSearchEntry = false
|
||||
if case let .list(search, reverseValue, _, _) = mode {
|
||||
if case let .list(search, reverseValue, _, _, _) = mode {
|
||||
includeSearchEntry = search
|
||||
reverse = reverseValue
|
||||
}
|
||||
@ -1738,7 +1738,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
switch self.mode {
|
||||
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))
|
||||
case let .list(_, _, displayHeaders, isGlobalSearch):
|
||||
case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch):
|
||||
let displayHeader: Bool
|
||||
switch displayHeaders {
|
||||
case .none:
|
||||
@ -1748,7 +1748,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
case .allButLast:
|
||||
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)
|
||||
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 Display
|
||||
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> {
|
||||
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 AccountContext
|
||||
import Emoji
|
||||
import ChatInterfaceState
|
||||
|
||||
struct PossibleContextQueryTypes: OptionSet {
|
||||
var rawValue: Int32
|
||||
|
@ -17,6 +17,7 @@ import ContextUI
|
||||
import GalleryUI
|
||||
import OverlayStatusController
|
||||
import PresentationDataUtils
|
||||
import ChatInterfaceState
|
||||
|
||||
struct PeerSpecificPackData {
|
||||
let peer: Peer
|
||||
|
@ -6,6 +6,7 @@ import SyncCore
|
||||
import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import AccountContext
|
||||
import ChatInterfaceState
|
||||
|
||||
enum ChatPresentationInputQueryKind: Int32 {
|
||||
case emoji
|
||||
|
@ -8,15 +8,11 @@ import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import LegacyComponents
|
||||
import AccountContext
|
||||
import ChatInterfaceState
|
||||
|
||||
private let offsetThreshold: CGFloat = 10.0
|
||||
private let dismissOffsetThreshold: CGFloat = 70.0
|
||||
|
||||
enum ChatTextInputMediaRecordingButtonMode: Int32 {
|
||||
case audio = 0
|
||||
case video = 1
|
||||
}
|
||||
|
||||
private func findTargetView(_ view: UIView, point: CGPoint) -> UIView? {
|
||||
if view.bounds.contains(point) && view.tag == 0x01f2bca {
|
||||
return view
|
||||
|
@ -11,6 +11,7 @@ import SettingsUI
|
||||
import WallpaperResources
|
||||
import MediaResources
|
||||
import LocationUI
|
||||
import ChatInterfaceState
|
||||
|
||||
private var telegramUIDeclaredEncodables: Void = {
|
||||
declareEncodable(InAppNotificationSettings.self, f: { InAppNotificationSettings(decoder: $0) })
|
||||
|
@ -20,6 +20,7 @@ import LanguageLinkPreviewUI
|
||||
import SettingsUI
|
||||
import UrlHandling
|
||||
import ShareController
|
||||
import ChatInterfaceState
|
||||
|
||||
private func defaultNavigationForPeerId(_ peerId: PeerId?, navigation: ChatControllerInteractionNavigateToPeer) -> ChatControllerInteractionNavigateToPeer {
|
||||
if case .default = navigation {
|
||||
|
@ -164,7 +164,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
||||
|
||||
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()
|
||||
|
||||
@ -495,7 +495,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
||||
}
|
||||
|
||||
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.stackFromBottom = true
|
||||
historyNode.updateFloatingHeaderOffset = { [weak self] offset, _ in
|
||||
|
@ -72,7 +72,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
||||
self.selectedMessagesPromise.set(.single(self.selectedMessages))
|
||||
|
||||
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
|
||||
|
||||
if tagMask == .music {
|
||||
|
@ -51,6 +51,7 @@ import SaveToCameraRoll
|
||||
import PeerInfoUI
|
||||
import ListMessageItem
|
||||
import GalleryData
|
||||
import ChatInterfaceState
|
||||
|
||||
protocol PeerInfoScreenItem: class {
|
||||
var id: AnyHashable { get }
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
import TelegramPresentationData
|
||||
import ChatInterfaceState
|
||||
|
||||
enum PeerMediaCollectionMode: Int32 {
|
||||
case photoOrVideo
|
||||
|
@ -8,6 +8,7 @@ import OpenInExternalAppUI
|
||||
import MusicAlbumArtResources
|
||||
import LocalMediaResources
|
||||
import LocationResources
|
||||
import ChatInterfaceState
|
||||
|
||||
public let telegramAccountAuxiliaryMethods = AccountAuxiliaryMethods(updatePeerChatInputState: { interfaceState, inputState -> PeerChatInterfaceState? in
|
||||
if interfaceState == nil {
|
||||
|
Loading…
x
Reference in New Issue
Block a user