mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Merge branch 'master' into experimental-2
This commit is contained in:
commit
d6446a284b
778 changed files with 11584 additions and 4657 deletions
|
|
@ -1 +1 @@
|
|||
4f0d2d13a70664d3029d9b97935089df0426fe53745965d175408752838b80dd
|
||||
61c0e29ede9b63175583b4609216b9c6083192c87d0e6ee0a42a5ff263b627dc
|
||||
|
|
|
|||
|
|
@ -22,9 +22,7 @@ private func setupSharedLogger(rootPath: String, path: String) {
|
|||
}
|
||||
}
|
||||
|
||||
private let accountAuxiliaryMethods = AccountAuxiliaryMethods(updatePeerChatInputState: { interfaceState, inputState -> PeerChatInterfaceState? in
|
||||
return interfaceState
|
||||
}, fetchResource: { account, resource, ranges, _ in
|
||||
private let accountAuxiliaryMethods = AccountAuxiliaryMethods(fetchResource: { account, resource, ranges, _ in
|
||||
return nil
|
||||
}, fetchResourceMediaReferenceHash: { resource in
|
||||
return .single(nil)
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@
|
|||
"PUSH_MESSAGE_ROUND" = "%1$@|sent you a video message";
|
||||
"PUSH_MESSAGE" = "%1$@|sent you a message";
|
||||
"PUSH_MESSAGES_TEXT_1" = "sent you a message";
|
||||
"PUSH_MESSAGES_TEXT_any" = "sent you %2$d messages";
|
||||
"PUSH_MESSAGES_TEXT_any" = "sent you %d messages";
|
||||
"PUSH_ALBUM" = "%1$@|sent you an album";
|
||||
"PUSH_MESSAGE_FILES_TEXT_1" = "sent you a file";
|
||||
"PUSH_MESSAGE_FILES_TEXT_any" = "sent you %d files";
|
||||
|
|
@ -168,7 +168,7 @@
|
|||
"PUSH_CHAT_MESSAGE_PHOTOS_TEXT_any" = "{author} sent %d photos";
|
||||
"PUSH_CHAT_MESSAGE_VIDEO" = "%2$@|%1$@ sent a video";
|
||||
"PUSH_CHAT_MESSAGE_VIDEOS_TEXT_1" = "{author} sent a video";
|
||||
"PUSH_CHAT_MESSAGE_VIDEOS_TEXT_any" = "{text} sent %d videos";
|
||||
"PUSH_CHAT_MESSAGE_VIDEOS_TEXT_any" = "{author} sent %d videos";
|
||||
"PUSH_CHAT_MESSAGE_ROUND" = "%2$@|%1$@ sent a video message";
|
||||
"PUSH_CHAT_MESSAGE" = "%2$@|%1$@ sent a message";
|
||||
"PUSH_CHAT_MESSAGES_TEXT_1" = "{author} sent a message";
|
||||
|
|
@ -849,7 +849,8 @@
|
|||
"MessageTimer.ShortWeeks_3_10" = "%@w";
|
||||
"MessageTimer.ShortWeeks_any" = "%@w";
|
||||
"MessageTimer.ShortWeeks_many" = "%@w";
|
||||
"MessageTimer.ShortWeeks_0" = "%@w";
|
||||
"MessageTimer.ShortMonths_1" = "%@mo";
|
||||
"MessageTimer.ShortMonths_any" = "%@mo";
|
||||
|
||||
"Activity.UploadingPhoto" = "sending photo";
|
||||
"Activity.UploadingVideo" = "sending video";
|
||||
|
|
@ -6563,3 +6564,12 @@ Sorry for the inconvenience.";
|
|||
"VoiceChat.VideoPreviewBackCamera" = "Back Camera";
|
||||
"VoiceChat.VideoPreviewContinue" = "Continue";
|
||||
"VoiceChat.VideoPreviewShareScreenInfo" = "Everything on your screen\nwill be shared";
|
||||
|
||||
"Gallery.SaveToGallery" = "Save to Gallery";
|
||||
"Gallery.VideoSaved" = "Video Saved";
|
||||
"Gallery.WaitForVideoDownoad" = "Please wait for the video to be fully downloaded.";
|
||||
|
||||
"VoiceChat.VideoParticipantsLimitExceededExtended" = "The voice chat is over %@ members.\nNew participants only have access to audio stream. ";
|
||||
|
||||
"PlaybackSpeed.Title" = "Playback Speed";
|
||||
"PlaybackSpeed.Normal" = "Normal";
|
||||
|
|
|
|||
|
|
@ -50,9 +50,7 @@ private func setupSharedLogger(rootPath: String, path: String) {
|
|||
}
|
||||
}
|
||||
|
||||
private let accountAuxiliaryMethods = AccountAuxiliaryMethods(updatePeerChatInputState: { interfaceState, inputState -> PeerChatInterfaceState? in
|
||||
return interfaceState
|
||||
}, fetchResource: { account, resource, ranges, _ in
|
||||
private let accountAuxiliaryMethods = AccountAuxiliaryMethods(fetchResource: { account, resource, ranges, _ in
|
||||
return nil
|
||||
}, fetchResourceMediaReferenceHash: { resource in
|
||||
return .single(nil)
|
||||
|
|
|
|||
|
|
@ -402,9 +402,15 @@ static _FormattedString * _Nonnull formatWithArgumentRanges(
|
|||
[result appendString:[string substringWithRange:
|
||||
NSMakeRange(currentLocation, range.range.location - currentLocation)]];
|
||||
}
|
||||
NSString *argument = nil;
|
||||
if (range.index >= 0 && range.index < arguments.count) {
|
||||
argument = arguments[range.index];
|
||||
} else {
|
||||
argument = @"?";
|
||||
}
|
||||
[resultingRanges addObject:[[_FormattedStringRange alloc] initWithIndex:range.index
|
||||
range:NSMakeRange(result.length, arguments[range.index].length)]];
|
||||
[result appendString:arguments[range.index]];
|
||||
range:NSMakeRange(result.length, argument.length)]];
|
||||
[result appendString:argument];
|
||||
currentLocation = range.range.location + range.range.length;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -249,6 +249,9 @@ class BazelCommandLine:
|
|||
'--disk_cache={path}'.format(path=self.cache_dir)
|
||||
]
|
||||
|
||||
if self.continue_on_error:
|
||||
combined_arguments += ['--keep_going']
|
||||
|
||||
return combined_arguments
|
||||
|
||||
def get_additional_build_arguments(self):
|
||||
|
|
@ -365,6 +368,8 @@ def generate_project(arguments):
|
|||
elif arguments.cacheHost is not None:
|
||||
bazel_command_line.add_remote_cache(arguments.cacheHost)
|
||||
|
||||
bazel_command_line.set_continue_on_error(arguments.continueOnError)
|
||||
|
||||
resolve_configuration(bazel_command_line, arguments)
|
||||
|
||||
bazel_command_line.set_build_number(arguments.buildNumber)
|
||||
|
|
@ -388,7 +393,7 @@ def generate_project(arguments):
|
|||
disable_provisioning_profiles=disable_provisioning_profiles,
|
||||
generate_dsym=generate_dsym,
|
||||
configuration_path=bazel_command_line.configuration_path,
|
||||
bazel_app_arguments=bazel_command_line.get_project_generation_arguments()
|
||||
bazel_app_arguments=bazel_command_line.get_project_generation_arguments(),
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -528,6 +533,13 @@ if __name__ == '__main__':
|
|||
'''
|
||||
)
|
||||
|
||||
generateProjectParser.add_argument(
|
||||
'--continueOnError',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Continue build process after an error.',
|
||||
)
|
||||
|
||||
generateProjectParser.add_argument(
|
||||
'--disableProvisioningProfiles',
|
||||
action='store_true',
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ set -e
|
|||
|
||||
BUILD_TELEGRAM_VERSION="1"
|
||||
|
||||
MACOS_VERSION="10.15"
|
||||
XCODE_VERSION="12.4"
|
||||
MACOS_VERSION="11"
|
||||
XCODE_VERSION="12.5.1"
|
||||
GUEST_SHELL="bash"
|
||||
|
||||
VM_BASE_NAME="macos$(echo $MACOS_VERSION | sed -e 's/\.'/_/g)_Xcode$(echo $XCODE_VERSION | sed -e 's/\.'/_/g)"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/TelegramAudio:TelegramAudio",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
|
|
|
|||
|
|
@ -145,10 +145,12 @@ public struct ChatAvailableMessageActionOptions: OptionSet {
|
|||
public struct ChatAvailableMessageActions {
|
||||
public var options: ChatAvailableMessageActionOptions
|
||||
public var banAuthor: Peer?
|
||||
public var disableDelete: Bool
|
||||
|
||||
public init(options: ChatAvailableMessageActionOptions, banAuthor: Peer?) {
|
||||
public init(options: ChatAvailableMessageActionOptions, banAuthor: Peer?, disableDelete: Bool) {
|
||||
self.options = options
|
||||
self.banAuthor = banAuthor
|
||||
self.disableDelete = disableDelete
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -287,9 +289,10 @@ public final class NavigateToChatControllerParams {
|
|||
public let animated: Bool
|
||||
public let options: NavigationAnimationOptions
|
||||
public let parentGroupId: PeerGroupId?
|
||||
public let chatListFilter: ChatListFilterData?
|
||||
public let completion: (ChatController) -> Void
|
||||
|
||||
public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: Bool = false, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: (ChatSearchDomain, String)? = nil, peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, reportReason: ReportReason? = nil, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, completion: @escaping (ChatController) -> Void = { _ in }) {
|
||||
public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: Bool = false, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: (ChatSearchDomain, String)? = nil, peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, reportReason: ReportReason? = nil, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, chatListFilter: ChatListFilterData? = nil, completion: @escaping (ChatController) -> Void = { _ in }) {
|
||||
self.navigationController = navigationController
|
||||
self.chatController = chatController
|
||||
self.chatLocationContextHolder = chatLocationContextHolder
|
||||
|
|
@ -310,6 +313,7 @@ public final class NavigateToChatControllerParams {
|
|||
self.animated = animated
|
||||
self.options = options
|
||||
self.parentGroupId = parentGroupId
|
||||
self.chatListFilter = chatListFilter
|
||||
self.completion = completion
|
||||
}
|
||||
}
|
||||
|
|
@ -532,7 +536,7 @@ public enum CreateGroupMode {
|
|||
case locatedGroup(latitude: Double, longitude: Double, address: String?)
|
||||
}
|
||||
|
||||
public protocol AppLockContext: class {
|
||||
public protocol AppLockContext: AnyObject {
|
||||
var invalidAttempts: Signal<AccessChallengeAttempts?, NoError> { get }
|
||||
var autolockDeadline: Signal<Int32?, NoError> { get }
|
||||
|
||||
|
|
@ -541,10 +545,10 @@ public protocol AppLockContext: class {
|
|||
func failedUnlockAttempt()
|
||||
}
|
||||
|
||||
public protocol RecentSessionsController: class {
|
||||
public protocol RecentSessionsController: AnyObject {
|
||||
}
|
||||
|
||||
public protocol SharedAccountContext: class {
|
||||
public protocol SharedAccountContext: AnyObject {
|
||||
var sharedContainerPath: String { get }
|
||||
var basePath: String { get }
|
||||
var mainWindow: Window1? { get }
|
||||
|
|
@ -699,16 +703,16 @@ public final class TonContext {
|
|||
public protocol ComposeController: ViewController {
|
||||
}
|
||||
|
||||
public protocol ChatLocationContextHolder: class {
|
||||
public protocol ChatLocationContextHolder: AnyObject {
|
||||
}
|
||||
|
||||
public protocol AccountGroupCallContext: class {
|
||||
public protocol AccountGroupCallContext: AnyObject {
|
||||
}
|
||||
|
||||
public protocol AccountGroupCallContextCache: class {
|
||||
public protocol AccountGroupCallContextCache: AnyObject {
|
||||
}
|
||||
|
||||
public protocol AccountContext: class {
|
||||
public protocol AccountContext: AnyObject {
|
||||
var sharedContext: SharedAccountContext { get }
|
||||
var account: Account { get }
|
||||
var engine: TelegramEngine { get }
|
||||
|
|
@ -736,6 +740,6 @@ public protocol AccountContext: class {
|
|||
func applyMaxReadIndex(for location: ChatLocation, contextHolder: Atomic<ChatLocationContextHolder?>, messageIndex: MessageIndex)
|
||||
|
||||
func scheduleGroupCall(peerId: PeerId)
|
||||
func joinGroupCall(peerId: PeerId, invite: String?, requestJoinAsPeerId: ((@escaping (PeerId?) -> Void) -> Void)?, activeCall: CachedChannelData.ActiveCall)
|
||||
func joinGroupCall(peerId: PeerId, invite: String?, requestJoinAsPeerId: ((@escaping (PeerId?) -> Void) -> Void)?, activeCall: EngineGroupCallDescription)
|
||||
func requestCall(peerId: PeerId, isVideo: Bool, completion: @escaping () -> Void)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ public enum ChatControllerInteractionNavigateToPeer {
|
|||
case withBotStartPayload(ChatControllerInitialBotStart)
|
||||
}
|
||||
|
||||
public struct ChatTextInputState: PostboxCoding, Equatable {
|
||||
public struct ChatTextInputState: Codable, Equatable {
|
||||
public let inputText: NSAttributedString
|
||||
public let selectionRange: Range<Int>
|
||||
|
||||
|
|
@ -153,29 +153,40 @@ public struct ChatTextInputState: PostboxCoding, Equatable {
|
|||
let length = inputText.length
|
||||
self.selectionRange = length ..< length
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.inputText = ((decoder.decodeObjectForKey("at", decoder: { ChatTextInputStateText(decoder: $0) }) as? ChatTextInputStateText) ?? ChatTextInputStateText()).attributedText()
|
||||
self.selectionRange = Int(decoder.decodeInt32ForKey("as0", orElse: 0)) ..< Int(decoder.decodeInt32ForKey("as1", orElse: 0))
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
self.inputText = ((try? container.decode(ChatTextInputStateText.self, forKey: "at")) ?? ChatTextInputStateText()).attributedText()
|
||||
let rangeFrom = (try? container.decode(Int32.self, forKey: "as0")) ?? 0
|
||||
let rangeTo = (try? container.decode(Int32.self, forKey: "as1")) ?? 0
|
||||
if rangeFrom <= rangeTo {
|
||||
self.selectionRange = Int(rangeFrom) ..< Int(rangeTo)
|
||||
} else {
|
||||
let length = self.inputText.length
|
||||
self.selectionRange = length ..< length
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeObject(ChatTextInputStateText(attributedText: self.inputText), forKey: "at")
|
||||
|
||||
encoder.encodeInt32(Int32(self.selectionRange.lowerBound), forKey: "as0")
|
||||
encoder.encodeInt32(Int32(self.selectionRange.upperBound), forKey: "as1")
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encode(ChatTextInputStateText(attributedText: self.inputText), forKey: "at")
|
||||
try container.encode(Int32(self.selectionRange.lowerBound), forKey: "as0")
|
||||
try container.encode(Int32(self.selectionRange.upperBound), forKey: "as1")
|
||||
}
|
||||
}
|
||||
|
||||
public enum ChatTextInputStateTextAttributeType: PostboxCoding, Equatable {
|
||||
public enum ChatTextInputStateTextAttributeType: Codable, Equatable {
|
||||
case bold
|
||||
case italic
|
||||
case monospace
|
||||
case textMention(EnginePeer.Id)
|
||||
case textUrl(String)
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
switch decoder.decodeInt32ForKey("t", orElse: 0) {
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
switch (try? container.decode(Int32.self, forKey: "t")) ?? 0 {
|
||||
case 0:
|
||||
self = .bold
|
||||
case 1:
|
||||
|
|
@ -183,69 +194,37 @@ public enum ChatTextInputStateTextAttributeType: PostboxCoding, Equatable {
|
|||
case 2:
|
||||
self = .monospace
|
||||
case 3:
|
||||
self = .textMention(EnginePeer.Id(decoder.decodeInt64ForKey("peerId", orElse: 0)))
|
||||
let peerId = (try? container.decode(Int64.self, forKey: "peerId")) ?? 0
|
||||
self = .textMention(EnginePeer.Id(peerId))
|
||||
case 4:
|
||||
self = .textUrl(decoder.decodeStringForKey("url", orElse: ""))
|
||||
let url = (try? container.decode(String.self, forKey: "url")) ?? ""
|
||||
self = .textUrl(url)
|
||||
default:
|
||||
assertionFailure()
|
||||
self = .bold
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
switch self {
|
||||
case .bold:
|
||||
encoder.encodeInt32(0, forKey: "t")
|
||||
try container.encode(0 as Int32, forKey: "t")
|
||||
case .italic:
|
||||
encoder.encodeInt32(1, forKey: "t")
|
||||
try container.encode(1 as Int32, forKey: "t")
|
||||
case .monospace:
|
||||
encoder.encodeInt32(2, forKey: "t")
|
||||
try container.encode(2 as Int32, forKey: "t")
|
||||
case let .textMention(id):
|
||||
encoder.encodeInt32(3, forKey: "t")
|
||||
encoder.encodeInt64(id.toInt64(), forKey: "peerId")
|
||||
try container.encode(3 as Int32, forKey: "t")
|
||||
try container.encode(id.toInt64(), forKey: "peerId")
|
||||
case let .textUrl(url):
|
||||
encoder.encodeInt32(4, forKey: "t")
|
||||
encoder.encodeString(url, forKey: "url")
|
||||
}
|
||||
}
|
||||
|
||||
public static func ==(lhs: ChatTextInputStateTextAttributeType, rhs: ChatTextInputStateTextAttributeType) -> Bool {
|
||||
switch lhs {
|
||||
case .bold:
|
||||
if case .bold = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case .italic:
|
||||
if case .italic = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case .monospace:
|
||||
if case .monospace = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .textMention(id):
|
||||
if case .textMention(id) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .textUrl(url):
|
||||
if case .textUrl(url) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
try container.encode(4 as Int32, forKey: "t")
|
||||
try container.encode(url, forKey: "url")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatTextInputStateTextAttribute: PostboxCoding, Equatable {
|
||||
public struct ChatTextInputStateTextAttribute: Codable, Equatable {
|
||||
public let type: ChatTextInputStateTextAttributeType
|
||||
public let range: Range<Int>
|
||||
|
||||
|
|
@ -253,16 +232,23 @@ public struct ChatTextInputStateTextAttribute: PostboxCoding, Equatable {
|
|||
self.type = type
|
||||
self.range = range
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.type = decoder.decodeObjectForKey("type", decoder: { ChatTextInputStateTextAttributeType(decoder: $0) }) as! ChatTextInputStateTextAttributeType
|
||||
self.range = Int(decoder.decodeInt32ForKey("range0", orElse: 0)) ..< Int(decoder.decodeInt32ForKey("range1", orElse: 0))
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
self.type = try container.decode(ChatTextInputStateTextAttributeType.self, forKey: "type")
|
||||
let rangeFrom = (try? container.decode(Int32.self, forKey: "range0")) ?? 0
|
||||
let rangeTo = (try? container.decode(Int32.self, forKey: "range1")) ?? 0
|
||||
|
||||
self.range = Int(rangeFrom) ..< Int(rangeTo)
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeObject(self.type, forKey: "type")
|
||||
encoder.encodeInt32(Int32(self.range.lowerBound), forKey: "range0")
|
||||
encoder.encodeInt32(Int32(self.range.upperBound), forKey: "range1")
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encode(self.type, forKey: "type")
|
||||
|
||||
try container.encode(Int32(self.range.lowerBound), forKey: "range0")
|
||||
try container.encode(Int32(self.range.upperBound), forKey: "range1")
|
||||
}
|
||||
|
||||
public static func ==(lhs: ChatTextInputStateTextAttribute, rhs: ChatTextInputStateTextAttribute) -> Bool {
|
||||
|
|
@ -270,7 +256,7 @@ public struct ChatTextInputStateTextAttribute: PostboxCoding, Equatable {
|
|||
}
|
||||
}
|
||||
|
||||
public struct ChatTextInputStateText: PostboxCoding, Equatable {
|
||||
public struct ChatTextInputStateText: Codable, Equatable {
|
||||
public let text: String
|
||||
public let attributes: [ChatTextInputStateTextAttribute]
|
||||
|
||||
|
|
@ -304,15 +290,17 @@ public struct ChatTextInputStateText: PostboxCoding, Equatable {
|
|||
})
|
||||
self.attributes = parsedAttributes
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.text = decoder.decodeStringForKey("text", orElse: "")
|
||||
self.attributes = decoder.decodeObjectArrayWithDecoderForKey("attributes")
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
self.text = (try? container.decode(String.self, forKey: "text")) ?? ""
|
||||
self.attributes = (try? container.decode([ChatTextInputStateTextAttribute].self, forKey: "attributes")) ?? []
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeString(self.text, forKey: "text")
|
||||
encoder.encodeObjectArray(self.attributes, forKey: "attributes")
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
try container.encode(self.text, forKey: "text")
|
||||
try container.encode(self.attributes, forKey: "attributes")
|
||||
}
|
||||
|
||||
static public func ==(lhs: ChatTextInputStateText, rhs: ChatTextInputStateText) -> Bool {
|
||||
|
|
@ -351,34 +339,6 @@ public enum ChatControllerPresentationMode: Equatable {
|
|||
case inline(NavigationController?)
|
||||
}
|
||||
|
||||
public final class ChatEmbeddedInterfaceState: PeerChatListEmbeddedInterfaceState {
|
||||
public let timestamp: Int32
|
||||
public let text: NSAttributedString
|
||||
|
||||
public init(timestamp: Int32, text: NSAttributedString) {
|
||||
self.timestamp = timestamp
|
||||
self.text = text
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.timestamp = decoder.decodeInt32ForKey("d", orElse: 0)
|
||||
self.text = ((decoder.decodeObjectForKey("at", decoder: { ChatTextInputStateText(decoder: $0) }) as? ChatTextInputStateText) ?? ChatTextInputStateText()).attributedText()
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeInt32(self.timestamp, forKey: "d")
|
||||
encoder.encodeObject(ChatTextInputStateText(attributedText: self.text), forKey: "at")
|
||||
}
|
||||
|
||||
public func isEqual(to: PeerChatListEmbeddedInterfaceState) -> Bool {
|
||||
if let to = to as? ChatEmbeddedInterfaceState {
|
||||
return self.timestamp == to.timestamp && self.text.isEqual(to: to.text)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ChatPresentationInputQueryResult: Equatable {
|
||||
case stickers([FoundStickerItem])
|
||||
case hashtags([String])
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import SwiftSignalKit
|
|||
|
||||
public typealias DeviceContactStableId = String
|
||||
|
||||
public protocol DeviceContactDataManager: class {
|
||||
public protocol DeviceContactDataManager: AnyObject {
|
||||
func personNameDisplayOrder() -> Signal<PresentationPersonNameOrder, NoError>
|
||||
func basicData() -> Signal<[DeviceContactStableId: DeviceContactBasicData], NoError>
|
||||
func basicDataForNormalizedPhoneNumber(_ normalizedNumber: DeviceContactNormalizedPhoneNumber) -> Signal<[(DeviceContactStableId, DeviceContactBasicData)], NoError>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import Postbox
|
|||
import TelegramUIPreferences
|
||||
import SwiftSignalKit
|
||||
|
||||
public protocol DownloadedMediaStoreManager: class {
|
||||
public protocol DownloadedMediaStoreManager: AnyObject {
|
||||
func store(_ media: AnyMediaReference, timestamp: Int32, peerType: MediaAutoDownloadPeerType)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ public func isMediaStreamable(message: Message, media: TelegramMediaFile) -> Boo
|
|||
return false
|
||||
}
|
||||
for attribute in media.attributes {
|
||||
if case let .Video(video) = attribute {
|
||||
if video.flags.contains(.supportsStreaming) {
|
||||
if case let .Video(_, _, flags) = attribute {
|
||||
if flags.contains(.supportsStreaming) {
|
||||
return true
|
||||
}
|
||||
break
|
||||
|
|
@ -41,8 +41,8 @@ public func isMediaStreamable(media: TelegramMediaFile) -> Bool {
|
|||
return false
|
||||
}
|
||||
for attribute in media.attributes {
|
||||
if case let .Video(video) = attribute {
|
||||
if video.flags.contains(.supportsStreaming) {
|
||||
if case let .Video(_, _, flags) = attribute {
|
||||
if flags.contains(.supportsStreaming) {
|
||||
return true
|
||||
}
|
||||
break
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ public enum MediaManagerPlayerType {
|
|||
case file
|
||||
}
|
||||
|
||||
public protocol MediaManager: class {
|
||||
public protocol MediaManager: AnyObject {
|
||||
var audioSession: ManagedAudioSession { get }
|
||||
var galleryHiddenMediaManager: GalleryHiddenMediaManager { get }
|
||||
var universalVideoManager: UniversalVideoManager { get }
|
||||
|
|
@ -177,11 +177,11 @@ public enum GalleryHiddenMediaId: Hashable {
|
|||
}
|
||||
}
|
||||
|
||||
public protocol GalleryHiddenMediaTarget: class {
|
||||
public protocol GalleryHiddenMediaTarget: AnyObject {
|
||||
func getTransitionInfo(messageId: MessageId, media: Media) -> ((UIView) -> Void, ASDisplayNode, () -> (UIView?, UIView?))?
|
||||
}
|
||||
|
||||
public protocol GalleryHiddenMediaManager: class {
|
||||
public protocol GalleryHiddenMediaManager: AnyObject {
|
||||
func hiddenIds() -> Signal<Set<GalleryHiddenMediaId>, NoError>
|
||||
func addSource(_ signal: Signal<GalleryHiddenMediaId?, NoError>) -> Int
|
||||
func removeSource(_ index: Int)
|
||||
|
|
@ -190,7 +190,7 @@ public protocol GalleryHiddenMediaManager: class {
|
|||
func findTarget(messageId: MessageId, media: Media) -> ((UIView) -> Void, ASDisplayNode, () -> (UIView?, UIView?))?
|
||||
}
|
||||
|
||||
public protocol UniversalVideoManager: class {
|
||||
public protocol UniversalVideoManager: AnyObject {
|
||||
func attachUniversalVideoContent(content: UniversalVideoContent, priority: UniversalVideoPriority, create: () -> UniversalVideoContentNode & ASDisplayNode, update: @escaping (((UniversalVideoContentNode & ASDisplayNode), Bool)?) -> Void) -> (AnyHashable, Int32)
|
||||
func detachUniversalVideoContent(id: AnyHashable, index: Int32)
|
||||
func withUniversalVideoContent(id: AnyHashable, _ f: ((UniversalVideoContentNode & ASDisplayNode)?) -> Void)
|
||||
|
|
@ -218,7 +218,7 @@ public struct RecordedAudioData {
|
|||
}
|
||||
}
|
||||
|
||||
public protocol ManagedAudioRecorder: class {
|
||||
public protocol ManagedAudioRecorder: AnyObject {
|
||||
var beginWithTone: Bool { get }
|
||||
var micLevel: Signal<Float, NoError> { get }
|
||||
var recordingState: Signal<AudioRecordingState, NoError> { get }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import Foundation
|
||||
|
||||
public protocol OverlayAudioPlayerController: class {
|
||||
public protocol OverlayAudioPlayerController: AnyObject {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public final class OverlayMediaControllerEmbeddingItem {
|
|||
}
|
||||
}
|
||||
|
||||
public protocol OverlayMediaController: class {
|
||||
public protocol OverlayMediaController: AnyObject {
|
||||
var updatePossibleEmbeddingItem: ((OverlayMediaControllerEmbeddingItem?) -> Void)? { get set }
|
||||
var embedPossibleEmbeddingItem: ((OverlayMediaControllerEmbeddingItem) -> Bool)? { get set }
|
||||
|
||||
|
|
|
|||
|
|
@ -40,8 +40,9 @@ public final class PeerSelectionControllerParams {
|
|||
public let createNewGroup: (() -> Void)?
|
||||
public let pretendPresentedInModal: Bool
|
||||
public let multipleSelection: Bool
|
||||
public let forwardedMessagesCount: Int
|
||||
|
||||
public init(context: AccountContext, filter: ChatListNodePeersFilter = [.onlyWriteable], hasChatListSelector: Bool = true, hasContactSelector: Bool = true, hasGlobalSearch: Bool = true, title: String? = nil, attemptSelection: ((Peer) -> Void)? = nil, createNewGroup: (() -> Void)? = nil, pretendPresentedInModal: Bool = false, multipleSelection: Bool = false) {
|
||||
public init(context: AccountContext, filter: ChatListNodePeersFilter = [.onlyWriteable], hasChatListSelector: Bool = true, hasContactSelector: Bool = true, hasGlobalSearch: Bool = true, title: String? = nil, attemptSelection: ((Peer) -> Void)? = nil, createNewGroup: (() -> Void)? = nil, pretendPresentedInModal: Bool = false, multipleSelection: Bool = false, forwardedMessagesCount: Int = 0) {
|
||||
self.context = context
|
||||
self.filter = filter
|
||||
self.hasChatListSelector = hasChatListSelector
|
||||
|
|
@ -52,6 +53,7 @@ public final class PeerSelectionControllerParams {
|
|||
self.createNewGroup = createNewGroup
|
||||
self.pretendPresentedInModal = pretendPresentedInModal
|
||||
self.multipleSelection = multipleSelection
|
||||
self.forwardedMessagesCount = forwardedMessagesCount
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +65,7 @@ public enum PeerSelectionControllerSendMode {
|
|||
|
||||
public protocol PeerSelectionController: ViewController {
|
||||
var peerSelected: ((Peer) -> Void)? { get set }
|
||||
var multiplePeersSelected: (([Peer], NSAttributedString, PeerSelectionControllerSendMode) -> Void)? { get set }
|
||||
var multiplePeersSelected: (([Peer], [PeerId: Peer], NSAttributedString, PeerSelectionControllerSendMode) -> Void)? { get set }
|
||||
var inProgress: Bool { get set }
|
||||
var customDismiss: (() -> Void)? { get set }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ public final class PresentationCallVideoView {
|
|||
}
|
||||
}
|
||||
|
||||
public protocol PresentationCall: class {
|
||||
public protocol PresentationCall: AnyObject {
|
||||
var context: AccountContext { get }
|
||||
var isIntegratedWithCallKit: Bool { get }
|
||||
var internalId: CallSessionInternalId { get }
|
||||
|
|
@ -168,6 +168,26 @@ public protocol PresentationCall: class {
|
|||
func makeOutgoingVideoView(completion: @escaping (PresentationCallVideoView?) -> Void)
|
||||
}
|
||||
|
||||
public struct VoiceChatConfiguration {
|
||||
public static var defaultValue: VoiceChatConfiguration {
|
||||
return VoiceChatConfiguration(videoParticipantsMaxCount: 30)
|
||||
}
|
||||
|
||||
public let videoParticipantsMaxCount: Int32
|
||||
|
||||
fileprivate init(videoParticipantsMaxCount: Int32) {
|
||||
self.videoParticipantsMaxCount = videoParticipantsMaxCount
|
||||
}
|
||||
|
||||
public static func with(appConfiguration: AppConfiguration) -> VoiceChatConfiguration {
|
||||
if let data = appConfiguration.data, let value = data["groupcall_video_participants_max"] as? Double {
|
||||
return VoiceChatConfiguration(videoParticipantsMaxCount: Int32(value))
|
||||
} else {
|
||||
return .defaultValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct PresentationGroupCallState: Equatable {
|
||||
public enum NetworkState {
|
||||
case connecting
|
||||
|
|
@ -191,6 +211,7 @@ public struct PresentationGroupCallState: Equatable {
|
|||
public var scheduleTimestamp: Int32?
|
||||
public var subscribedToScheduled: Bool
|
||||
public var isVideoEnabled: Bool
|
||||
public var isVideoWatchersLimitReached: Bool
|
||||
|
||||
public init(
|
||||
myPeerId: PeerId,
|
||||
|
|
@ -204,7 +225,8 @@ public struct PresentationGroupCallState: Equatable {
|
|||
raisedHand: Bool,
|
||||
scheduleTimestamp: Int32?,
|
||||
subscribedToScheduled: Bool,
|
||||
isVideoEnabled: Bool
|
||||
isVideoEnabled: Bool,
|
||||
isVideoWatchersLimitReached: Bool
|
||||
) {
|
||||
self.myPeerId = myPeerId
|
||||
self.networkState = networkState
|
||||
|
|
@ -218,6 +240,7 @@ public struct PresentationGroupCallState: Equatable {
|
|||
self.scheduleTimestamp = scheduleTimestamp
|
||||
self.subscribedToScheduled = subscribedToScheduled
|
||||
self.isVideoEnabled = isVideoEnabled
|
||||
self.isVideoWatchersLimitReached = isVideoWatchersLimitReached
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -368,7 +391,7 @@ public extension GroupCallParticipantsContext.Participant {
|
|||
}
|
||||
}
|
||||
|
||||
public protocol PresentationGroupCall: class {
|
||||
public protocol PresentationGroupCall: AnyObject {
|
||||
var account: Account { get }
|
||||
var accountContext: AccountContext { get }
|
||||
var internalId: CallSessionInternalId { get }
|
||||
|
|
@ -436,11 +459,11 @@ public protocol PresentationGroupCall: class {
|
|||
func loadMoreMembers(token: String)
|
||||
}
|
||||
|
||||
public protocol PresentationCallManager: class {
|
||||
public protocol PresentationCallManager: AnyObject {
|
||||
var currentCallSignal: Signal<PresentationCall?, NoError> { get }
|
||||
var currentGroupCallSignal: Signal<PresentationGroupCall?, NoError> { get }
|
||||
|
||||
func requestCall(context: AccountContext, peerId: PeerId, isVideo: Bool, endCurrentIfAny: Bool) -> RequestCallResult
|
||||
func joinGroupCall(context: AccountContext, peerId: PeerId, invite: String?, requestJoinAsPeerId: ((@escaping (PeerId?) -> Void) -> Void)?, initialCall: CachedChannelData.ActiveCall, endCurrentIfAny: Bool) -> JoinGroupCallManagerResult
|
||||
func joinGroupCall(context: AccountContext, peerId: PeerId, invite: String?, requestJoinAsPeerId: ((@escaping (PeerId?) -> Void) -> Void)?, initialCall: EngineGroupCallDescription, endCurrentIfAny: Bool) -> JoinGroupCallManagerResult
|
||||
func scheduleGroupCall(context: AccountContext, peerId: PeerId, endCurrentIfAny: Bool) -> RequestScheduleGroupCallResult
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ public protocol SharedMediaPlaylistLocation {
|
|||
func isEqual(to: SharedMediaPlaylistLocation) -> Bool
|
||||
}
|
||||
|
||||
public protocol SharedMediaPlaylist: class {
|
||||
public protocol SharedMediaPlaylist: AnyObject {
|
||||
var id: SharedMediaPlaylistId { get }
|
||||
var location: SharedMediaPlaylistLocation { get }
|
||||
var state: Signal<SharedMediaPlaylistState, NoError> { get }
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@ import SwiftSignalKit
|
|||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
|
||||
public protocol ThemeUpdateManager: class {
|
||||
public protocol ThemeUpdateManager: AnyObject {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import Display
|
|||
import TelegramAudio
|
||||
import UniversalMediaPlayer
|
||||
|
||||
public protocol UniversalVideoContentNode: class {
|
||||
public protocol UniversalVideoContentNode: AnyObject {
|
||||
var ready: Signal<Void, NoError> { get }
|
||||
var status: Signal<MediaPlayerStatus, NoError> { get }
|
||||
var bufferingStatus: Signal<(IndexSet, Int)?, NoError> { get }
|
||||
|
|
@ -47,7 +47,7 @@ public extension UniversalVideoContent {
|
|||
}
|
||||
}
|
||||
|
||||
public protocol UniversalVideoDecoration: class {
|
||||
public protocol UniversalVideoDecoration: AnyObject {
|
||||
var backgroundNode: ASDisplayNode? { get }
|
||||
var contentContainerNode: ASDisplayNode { get }
|
||||
var foregroundNode: ASDisplayNode? { get }
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public enum WallpaperUploadManagerStatus {
|
|||
}
|
||||
}
|
||||
|
||||
public protocol WallpaperUploadManager: class {
|
||||
public protocol WallpaperUploadManager: AnyObject {
|
||||
func stateSignal() -> Signal<WallpaperUploadManagerStatus, NoError>
|
||||
func presentationDataUpdated(_ presentationData: PresentationData)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ public struct WatchRunningTasks: Equatable {
|
|||
}
|
||||
}
|
||||
|
||||
public protocol WatchManager: class {
|
||||
public protocol WatchManager: AnyObject {
|
||||
var watchAppInstalled: Signal<Bool, NoError> { get }
|
||||
var navigateToMessageRequested: Signal<MessageId, NoError> { get }
|
||||
var runningTasks: Signal<WatchRunningTasks?, NoError> { get }
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/Postbox:Postbox",
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
|
|
|
|||
|
|
@ -3,21 +3,20 @@ import UIKit
|
|||
import AsyncDisplayKit
|
||||
import Display
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import TelegramPresentationData
|
||||
import AvatarNode
|
||||
import AccountContext
|
||||
|
||||
public class ActionSheetPeerItem: ActionSheetItem {
|
||||
public let context: AccountContext
|
||||
public let peer: Peer
|
||||
public let peer: EnginePeer
|
||||
public let theme: PresentationTheme
|
||||
public let title: String
|
||||
public let isSelected: Bool
|
||||
public let strings: PresentationStrings
|
||||
public let action: () -> Void
|
||||
|
||||
public init(context: AccountContext, peer: Peer, title: String, isSelected: Bool, strings: PresentationStrings, theme: PresentationTheme, action: @escaping () -> Void) {
|
||||
public init(context: AccountContext, peer: EnginePeer, title: String, isSelected: Bool, strings: PresentationStrings, theme: PresentationTheme, action: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.peer = peer
|
||||
self.title = title
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/Display:Display",
|
||||
],
|
||||
|
|
|
|||
|
|
@ -6,11 +6,13 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
"//submodules/AvatarNode:AvatarNode",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import Display
|
|||
import AsyncDisplayKit
|
||||
import AvatarNode
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import AccountContext
|
||||
import AudioBlob
|
||||
|
|
@ -13,12 +12,12 @@ public final class AnimatedAvatarSetContext {
|
|||
public final class Content {
|
||||
fileprivate final class Item {
|
||||
fileprivate struct Key: Hashable {
|
||||
var peerId: PeerId
|
||||
var peerId: EnginePeer.Id
|
||||
}
|
||||
|
||||
fileprivate let peer: Peer
|
||||
fileprivate let peer: EnginePeer
|
||||
|
||||
fileprivate init(peer: Peer) {
|
||||
fileprivate init(peer: EnginePeer) {
|
||||
self.peer = peer
|
||||
}
|
||||
}
|
||||
|
|
@ -31,20 +30,20 @@ public final class AnimatedAvatarSetContext {
|
|||
}
|
||||
|
||||
private final class ItemState {
|
||||
let peer: Peer
|
||||
let peer: EnginePeer
|
||||
|
||||
init(peer: Peer) {
|
||||
init(peer: EnginePeer) {
|
||||
self.peer = peer
|
||||
}
|
||||
}
|
||||
|
||||
private var peers: [Peer] = []
|
||||
private var itemStates: [PeerId: ItemState] = [:]
|
||||
private var peers: [EnginePeer] = []
|
||||
private var itemStates: [EnginePeer.Id: ItemState] = [:]
|
||||
|
||||
public init() {
|
||||
}
|
||||
|
||||
public func update(peers: [Peer], animated: Bool) -> Content {
|
||||
public func update(peers: [EnginePeer], animated: Bool) -> Content {
|
||||
var items: [(Content.Item.Key, Content.Item)] = []
|
||||
for peer in peers {
|
||||
items.append((Content.Item.Key(peerId: peer.id), Content.Item(peer: peer)))
|
||||
|
|
@ -63,7 +62,7 @@ private final class ContentNode: ASDisplayNode {
|
|||
|
||||
private var disposable: Disposable?
|
||||
|
||||
init(context: AccountContext, peer: Peer, synchronousLoad: Bool) {
|
||||
init(context: AccountContext, peer: EnginePeer, synchronousLoad: Bool) {
|
||||
self.unclippedNode = ASImageNode()
|
||||
self.clippedNode = ASImageNode()
|
||||
|
||||
|
|
@ -72,7 +71,7 @@ private final class ContentNode: ASDisplayNode {
|
|||
self.addSubnode(self.unclippedNode)
|
||||
self.addSubnode(self.clippedNode)
|
||||
|
||||
if let representation = peer.smallProfileImage, let signal = peerAvatarImage(account: context.account, peerReference: PeerReference(peer), authorOfMessage: nil, representation: representation, displayDimensions: CGSize(width: 30.0, height: 30.0), synchronousLoad: synchronousLoad) {
|
||||
if let representation = peer.smallProfileImage, let signal = peerAvatarImage(account: context.account, peerReference: PeerReference(peer._asPeer()), authorOfMessage: nil, representation: representation, displayDimensions: CGSize(width: 30.0, height: 30.0), synchronousLoad: synchronousLoad) {
|
||||
let image = generateImage(CGSize(width: 30.0, height: 30.0), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(UIColor.lightGray.cgColor)
|
||||
|
|
@ -252,8 +251,7 @@ public final class AnimatedAvatarSetNode: ASDisplayNode {
|
|||
return CGSize(width: contentWidth, height: contentHeight)
|
||||
}
|
||||
|
||||
public func updateAudioLevels(color: UIColor, backgroundColor: UIColor, levels: [PeerId: Float]) {
|
||||
//print("updateAudioLevels visible: \(self.contentNodes.keys.map(\.peerId.id)) data: \(levels)")
|
||||
public func updateAudioLevels(color: UIColor, backgroundColor: UIColor, levels: [EnginePeer.Id: Float]) {
|
||||
for (key, itemNode) in self.contentNodes {
|
||||
if let value = levels[key.peerId] {
|
||||
itemNode.updateAudioLevel(color: color, backgroundColor: backgroundColor, value: value)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ public final class AnimatedStickerFrame {
|
|||
}
|
||||
}
|
||||
|
||||
public protocol AnimatedStickerFrameSource: class {
|
||||
public protocol AnimatedStickerFrameSource: AnyObject {
|
||||
var frameRate: Int { get }
|
||||
var frameCount: Int { get }
|
||||
var frameIndex: Int { get }
|
||||
|
|
@ -139,7 +139,10 @@ public final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource
|
|||
var frameRate = 0
|
||||
var frameCount = 0
|
||||
|
||||
if !self.data.withUnsafeBytes({ (bytes: UnsafePointer<UInt8>) -> Bool in
|
||||
if !self.data.withUnsafeBytes({ buffer -> Bool in
|
||||
guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||
return false
|
||||
}
|
||||
var frameRateValue: Int32 = 0
|
||||
var frameCountValue: Int32 = 0
|
||||
var widthValue: Int32 = 0
|
||||
|
|
@ -180,7 +183,10 @@ public final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource
|
|||
self.decodeBuffer = Data(count: self.bytesPerRow * height)
|
||||
self.frameBuffer = Data(count: self.bytesPerRow * height)
|
||||
let frameBufferLength = self.frameBuffer.count
|
||||
self.frameBuffer.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
self.frameBuffer.withUnsafeMutableBytes { buffer -> Void in
|
||||
guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||
return
|
||||
}
|
||||
memset(bytes, 0, frameBufferLength)
|
||||
}
|
||||
}
|
||||
|
|
@ -199,12 +205,19 @@ public final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource
|
|||
|
||||
let frameIndex = self.frameIndex
|
||||
|
||||
self.data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
|
||||
self.data.withUnsafeBytes { buffer -> Void in
|
||||
guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||
return
|
||||
}
|
||||
|
||||
if self.offset + 4 > dataLength {
|
||||
if self.dataComplete {
|
||||
self.frameIndex = 0
|
||||
self.offset = self.initialOffset
|
||||
self.frameBuffer.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
self.frameBuffer.withUnsafeMutableBytes { buffer -> Void in
|
||||
guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||
return
|
||||
}
|
||||
memset(bytes, 0, frameBufferLength)
|
||||
}
|
||||
}
|
||||
|
|
@ -221,9 +234,21 @@ public final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource
|
|||
self.offset += 4
|
||||
|
||||
if draw {
|
||||
self.scratchBuffer.withUnsafeMutableBytes { (scratchBytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
self.decodeBuffer.withUnsafeMutableBytes { (decodeBytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
self.frameBuffer.withUnsafeMutableBytes { (frameBytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
self.scratchBuffer.withUnsafeMutableBytes { scratchBuffer -> Void in
|
||||
guard let scratchBytes = scratchBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||
return
|
||||
}
|
||||
|
||||
self.decodeBuffer.withUnsafeMutableBytes { decodeBuffer -> Void in
|
||||
guard let decodeBytes = decodeBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||
return
|
||||
}
|
||||
|
||||
self.frameBuffer.withUnsafeMutableBytes { frameBuffer -> Void in
|
||||
guard let frameBytes = frameBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||
return
|
||||
}
|
||||
|
||||
compression_decode_buffer(decodeBytes, decodeBufferLength, bytes.advanced(by: self.offset), Int(frameLength), UnsafeMutableRawPointer(scratchBytes), COMPRESSION_LZFSE)
|
||||
|
||||
var lhs = UnsafeMutableRawPointer(frameBytes).assumingMemoryBound(to: UInt64.self)
|
||||
|
|
@ -253,7 +278,10 @@ public final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource
|
|||
isLastFrame = true
|
||||
self.frameIndex = 0
|
||||
self.offset = self.initialOffset
|
||||
self.frameBuffer.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
self.frameBuffer.withUnsafeMutableBytes { buffer -> Void in
|
||||
guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||
return
|
||||
}
|
||||
memset(bytes, 0, frameBufferLength)
|
||||
}
|
||||
}
|
||||
|
|
@ -351,7 +379,10 @@ private final class ManagedFileImpl {
|
|||
assert(queue.isCurrent())
|
||||
}
|
||||
var result = Data(count: count)
|
||||
result.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<Int8>) -> Void in
|
||||
result.withUnsafeMutableBytes { buffer -> Void in
|
||||
guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||
return
|
||||
}
|
||||
let readCount = self.read(bytes, count)
|
||||
assert(readCount == count)
|
||||
}
|
||||
|
|
@ -399,7 +430,7 @@ private func compressFrame(width: Int, height: Int, rgbData: Data) -> Data? {
|
|||
assert(yuvaPixelsPerAlphaRow % 2 == 0)
|
||||
|
||||
let yuvaLength = Int(width) * Int(height) * 2 + yuvaPixelsPerAlphaRow * Int(height) / 2
|
||||
var yuvaFrameData = malloc(yuvaLength)!
|
||||
let yuvaFrameData = malloc(yuvaLength)!
|
||||
defer {
|
||||
free(yuvaFrameData)
|
||||
}
|
||||
|
|
@ -422,7 +453,10 @@ private func compressFrame(width: Int, height: Int, rgbData: Data) -> Data? {
|
|||
|
||||
var maybeResultSize: Int?
|
||||
|
||||
compressedFrameData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
compressedFrameData.withUnsafeMutableBytes { buffer -> Void in
|
||||
guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||
return
|
||||
}
|
||||
let length = compression_encode_buffer(bytes, compressedFrameDataLength, yuvaFrameData.assumingMemoryBound(to: UInt8.self), yuvaLength, scratchData, COMPRESSION_LZFSE)
|
||||
maybeResultSize = length
|
||||
}
|
||||
|
|
@ -579,9 +613,21 @@ private final class AnimatedStickerDirectFrameSourceCache {
|
|||
|
||||
let decodeBufferLength = self.decodeBuffer.count
|
||||
|
||||
compressedData.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
|
||||
self.scratchBuffer.withUnsafeMutableBytes { (scratchBytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
self.decodeBuffer.withUnsafeMutableBytes { (decodeBytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
compressedData.withUnsafeBytes { buffer -> Void in
|
||||
guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||
return
|
||||
}
|
||||
|
||||
self.scratchBuffer.withUnsafeMutableBytes { scratchBuffer -> Void in
|
||||
guard let scratchBytes = scratchBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||
return
|
||||
}
|
||||
|
||||
self.decodeBuffer.withUnsafeMutableBytes { decodeBuffer -> Void in
|
||||
guard let decodeBytes = decodeBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||
return
|
||||
}
|
||||
|
||||
let resultLength = compression_decode_buffer(decodeBytes, decodeBufferLength, bytes, length, UnsafeMutableRawPointer(scratchBytes), COMPRESSION_LZFSE)
|
||||
|
||||
frameData = Data(bytes: decodeBytes, count: resultLength)
|
||||
|
|
@ -644,7 +690,11 @@ private final class AnimatedStickerDirectFrameSource: AnimatedStickerFrameSource
|
|||
return AnimatedStickerFrame(data: yuvData, type: .yuva, width: self.width, height: self.height, bytesPerRow: 0, index: frameIndex, isLastFrame: frameIndex == self.frameCount - 1, totalFrames: self.frameCount)
|
||||
} else {
|
||||
var frameData = Data(count: self.bytesPerRow * self.height)
|
||||
frameData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
frameData.withUnsafeMutableBytes { buffer -> Void in
|
||||
guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||
return
|
||||
}
|
||||
|
||||
memset(bytes, 0, self.bytesPerRow * self.height)
|
||||
self.animation.renderFrame(with: Int32(frameIndex), into: bytes, width: Int32(self.width), height: Int32(self.height), bytesPerRow: Int32(self.bytesPerRow))
|
||||
}
|
||||
|
|
@ -853,7 +903,7 @@ public final class AnimatedStickerNode: ASDisplayNode {
|
|||
strongSelf.isSetUpForPlayback = false
|
||||
strongSelf.isPlaying = true
|
||||
}
|
||||
var fromIndex = strongSelf.playFromIndex
|
||||
let fromIndex = strongSelf.playFromIndex
|
||||
strongSelf.playFromIndex = nil
|
||||
strongSelf.play(fromIndex: fromIndex)
|
||||
} else if strongSelf.canDisplayFirstFrame {
|
||||
|
|
|
|||
|
|
@ -19,15 +19,25 @@ final class SoftwareAnimationRenderer: ASDisplayNode, AnimationRenderer {
|
|||
break
|
||||
}
|
||||
|
||||
let image = generateImagePixel(CGSize(width: CGFloat(width), height: CGFloat(height)), scale: 1.0, pixelGenerator: { _, pixelData, bytesPerRow in
|
||||
let image = generateImagePixel(CGSize(width: CGFloat(width), height: CGFloat(height)), scale: 1.0, pixelGenerator: { _, pixelData, contextBytesPerRow in
|
||||
switch type {
|
||||
case .yuva:
|
||||
data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
|
||||
decodeYUVAToRGBA(bytes, pixelData, Int32(width), Int32(height), Int32(bytesPerRow))
|
||||
data.withUnsafeBytes { bytes -> Void in
|
||||
guard let baseAddress = bytes.baseAddress else {
|
||||
return
|
||||
}
|
||||
if bytesPerRow * height > bytes.count {
|
||||
assert(false)
|
||||
return
|
||||
}
|
||||
decodeYUVAToRGBA(baseAddress.assumingMemoryBound(to: UInt8.self), pixelData, Int32(width), Int32(height), Int32(contextBytesPerRow))
|
||||
}
|
||||
case .argb:
|
||||
data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
|
||||
memcpy(pixelData, bytes, data.count)
|
||||
data.withUnsafeBytes { bytes -> Void in
|
||||
guard let baseAddress = bytes.baseAddress else {
|
||||
return
|
||||
}
|
||||
memcpy(pixelData, baseAddress.assumingMemoryBound(to: UInt8.self), bytes.count)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -6,17 +6,11 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/YuvConversion:YuvConversion",
|
||||
"//submodules/StickerResources:StickerResources",
|
||||
"//submodules/MediaResources:MediaResources",
|
||||
"//submodules/Tuples:Tuples",
|
||||
"//submodules/GZip:GZip",
|
||||
"//submodules/rlottie:RLottieBinding",
|
||||
"//submodules/lottie-ios:Lottie",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ public final class AppLockContextImpl: AppLockContext {
|
|||
strongSelf.autolockTimeout.set(nil)
|
||||
strongSelf.autolockReportTimeout.set(nil)
|
||||
} else {
|
||||
if let autolockTimeout = passcodeSettings.autolockTimeout, !appInForeground {
|
||||
if let _ = passcodeSettings.autolockTimeout, !appInForeground {
|
||||
shouldDisplayCoveringView = true
|
||||
}
|
||||
|
||||
|
|
@ -184,7 +184,7 @@ public final class AppLockContextImpl: AppLockContext {
|
|||
}
|
||||
passcodeController.ensureInputFocused()
|
||||
} else {
|
||||
let passcodeController = PasscodeEntryController(applicationBindings: strongSelf.applicationBindings, accountManager: strongSelf.accountManager, appLockContext: strongSelf, presentationData: presentationData, presentationDataSignal: strongSelf.presentationDataSignal, statusBarHost: window?.statusBarHost, challengeData: accessChallengeData.data, biometrics: biometrics, arguments: PasscodeEntryControllerPresentationArguments(animated: !becameActiveRecently, lockIconInitialFrame: { [weak self] in
|
||||
let passcodeController = PasscodeEntryController(applicationBindings: strongSelf.applicationBindings, accountManager: strongSelf.accountManager, appLockContext: strongSelf, presentationData: presentationData, presentationDataSignal: strongSelf.presentationDataSignal, statusBarHost: window?.statusBarHost, challengeData: accessChallengeData.data, biometrics: biometrics, arguments: PasscodeEntryControllerPresentationArguments(animated: !becameActiveRecently, lockIconInitialFrame: {
|
||||
if let lockViewFrame = lockIconInitialFrame() {
|
||||
return lockViewFrame
|
||||
} else {
|
||||
|
|
@ -203,7 +203,7 @@ public final class AppLockContextImpl: AppLockContext {
|
|||
passcodeController.isOpaqueWhenInOverlay = true
|
||||
strongSelf.passcodeController = passcodeController
|
||||
if let rootViewController = strongSelf.rootController {
|
||||
if let presentedViewController = rootViewController.presentedViewController as? UIActivityViewController {
|
||||
if let _ = rootViewController.presentedViewController as? UIActivityViewController {
|
||||
} else {
|
||||
rootViewController.dismiss(animated: false, completion: nil)
|
||||
}
|
||||
|
|
@ -227,14 +227,14 @@ public final class AppLockContextImpl: AppLockContext {
|
|||
window.coveringView = coveringView
|
||||
|
||||
if let rootViewController = strongSelf.rootController {
|
||||
if let presentedViewController = rootViewController.presentedViewController as? UIActivityViewController {
|
||||
if let _ = rootViewController.presentedViewController as? UIActivityViewController {
|
||||
} else {
|
||||
rootViewController.dismiss(animated: false, completion: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let coveringView = strongSelf.coveringView {
|
||||
if let _ = strongSelf.coveringView {
|
||||
strongSelf.coveringView = nil
|
||||
strongSelf.window?.coveringView = nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
|
|
|
|||
|
|
@ -151,14 +151,14 @@ private final class ArchivedStickersNoticeAlertContentNode: AlertContentNode {
|
|||
}
|
||||
|
||||
private func dequeueTransition() {
|
||||
guard let layout = self.validLayout, let transition = self.enqueuedTransitions.first else {
|
||||
guard let _ = self.validLayout, let transition = self.enqueuedTransitions.first else {
|
||||
return
|
||||
}
|
||||
self.enqueuedTransitions.remove(at: 0)
|
||||
|
||||
var options = ListViewDeleteAndInsertOptions()
|
||||
let options = ListViewDeleteAndInsertOptions()
|
||||
|
||||
self.listView.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { [weak self] _ in
|
||||
self.listView.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { _ in
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -302,14 +302,14 @@ public func archivedStickerPacksNoticeController(context: AccountContext, archiv
|
|||
})])
|
||||
|
||||
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode)
|
||||
let presentationDataDisposable = context.sharedContext.presentationData.start(next: { [weak controller, weak contentNode] presentationData in
|
||||
let presentationDataDisposable = context.sharedContext.presentationData.start(next: { [weak controller] presentationData in
|
||||
controller?.theme = AlertControllerTheme(presentationData: presentationData)
|
||||
})
|
||||
controller.dismissed = {
|
||||
presentationDataDisposable.dispose()
|
||||
disposable.dispose()
|
||||
}
|
||||
dismissImpl = { [weak controller, weak contentNode] in
|
||||
dismissImpl = { [weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
}
|
||||
return controller
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
|
|
|
|||
|
|
@ -253,12 +253,10 @@ private final class AuthDataTransferSplashScreenNode: ViewControllerTracingNode
|
|||
let animationFitSize = CGSize(width: min(500.0, layout.size.width - sideInset + 20.0), height: 500.0)
|
||||
let animationSize = self.animationNode?.preferredSize()?.fitted(animationFitSize) ?? animationFitSize
|
||||
let iconSize: CGSize = animationSize
|
||||
var iconOffset = CGPoint()
|
||||
let iconOffset = CGPoint()
|
||||
|
||||
let titleSize = self.titleNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: layout.size.height))
|
||||
|
||||
let hasRTL = self.badgeTextNodes.first?.cachedLayout?.hasRTL ?? false
|
||||
|
||||
var badgeTextSizes: [CGSize] = []
|
||||
var textSizes: [CGSize] = []
|
||||
var textContentHeight: CGFloat = 0.0
|
||||
|
|
@ -290,9 +288,9 @@ private final class AuthDataTransferSplashScreenNode: ViewControllerTracingNode
|
|||
|
||||
let buttonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonWidth) / 2.0), y: layout.size.height - bottomInset - buttonHeight), size: CGSize(width: buttonWidth, height: buttonHeight))
|
||||
transition.updateFrame(node: self.buttonNode, frame: buttonFrame)
|
||||
self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition)
|
||||
let _ = self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition)
|
||||
|
||||
var maxContentVerticalOrigin = buttonFrame.minY - 12.0 - contentHeight
|
||||
let maxContentVerticalOrigin = buttonFrame.minY - 12.0 - contentHeight
|
||||
|
||||
contentVerticalOrigin = min(contentVerticalOrigin, maxContentVerticalOrigin)
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ private func generateFrameImage() -> UIImage? {
|
|||
context.setLineWidth(4.0)
|
||||
context.setLineCap(.round)
|
||||
|
||||
var path = CGMutablePath();
|
||||
let path = CGMutablePath()
|
||||
path.move(to: CGPoint(x: 2.0, y: 2.0 + 26.0))
|
||||
path.addArc(tangent1End: CGPoint(x: 2.0, y: 2.0), tangent2End: CGPoint(x: 2.0 + 26.0, y: 2.0), radius: 6.0)
|
||||
path.addLine(to: CGPoint(x: 2.0 + 26.0, y: 2.0))
|
||||
|
|
@ -412,8 +412,8 @@ private final class AuthTransferScanScreenNode: ViewControllerTracingNode, UIScr
|
|||
let dimAlpha: CGFloat
|
||||
let dimRect: CGRect
|
||||
let controlsAlpha: CGFloat
|
||||
var centerDimAlpha: CGFloat = 0.0
|
||||
var frameAlpha: CGFloat = 1.0
|
||||
let centerDimAlpha: CGFloat = 0.0
|
||||
let frameAlpha: CGFloat = 1.0
|
||||
if let focusedRect = self.focusedRect {
|
||||
controlsAlpha = 0.0
|
||||
dimAlpha = 1.0
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import Display
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
|
|
@ -28,8 +27,8 @@ public enum AvatarNodeClipStyle {
|
|||
|
||||
private class AvatarNodeParameters: NSObject {
|
||||
let theme: PresentationTheme?
|
||||
let accountPeerId: PeerId?
|
||||
let peerId: PeerId?
|
||||
let accountPeerId: EnginePeer.Id?
|
||||
let peerId: EnginePeer.Id?
|
||||
let letters: [String]
|
||||
let font: UIFont
|
||||
let icon: AvatarNodeIcon
|
||||
|
|
@ -37,7 +36,7 @@ private class AvatarNodeParameters: NSObject {
|
|||
let hasImage: Bool
|
||||
let clipStyle: AvatarNodeClipStyle
|
||||
|
||||
init(theme: PresentationTheme?, accountPeerId: PeerId?, peerId: PeerId?, letters: [String], font: UIFont, icon: AvatarNodeIcon, explicitColorIndex: Int?, hasImage: Bool, clipStyle: AvatarNodeClipStyle) {
|
||||
init(theme: PresentationTheme?, accountPeerId: EnginePeer.Id?, peerId: EnginePeer.Id?, letters: [String], font: UIFont, icon: AvatarNodeIcon, explicitColorIndex: Int?, hasImage: Bool, clipStyle: AvatarNodeClipStyle) {
|
||||
self.theme = theme
|
||||
self.accountPeerId = accountPeerId
|
||||
self.peerId = peerId
|
||||
|
|
@ -85,7 +84,7 @@ public enum AvatarNodeExplicitIcon {
|
|||
|
||||
private enum AvatarNodeState: Equatable {
|
||||
case empty
|
||||
case peerAvatar(PeerId, [String], TelegramMediaImageRepresentation?)
|
||||
case peerAvatar(EnginePeer.Id, [String], TelegramMediaImageRepresentation?)
|
||||
case custom(letter: [String], explicitColorIndex: Int?, explicitIcon: AvatarNodeExplicitIcon?)
|
||||
}
|
||||
|
||||
|
|
@ -303,7 +302,7 @@ public final class AvatarNode: ASDisplayNode {
|
|||
self.imageNode.isHidden = true
|
||||
}
|
||||
|
||||
public func setPeer(context: AccountContext, theme: PresentationTheme, peer: Peer?, authorOfMessage: MessageReference? = nil, overrideImage: AvatarNodeImageOverride? = nil, emptyColor: UIColor? = nil, clipStyle: AvatarNodeClipStyle = .round, synchronousLoad: Bool = false, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0), storeUnrounded: Bool = false) {
|
||||
public func setPeer(context: AccountContext, theme: PresentationTheme, peer: EnginePeer?, authorOfMessage: MessageReference? = nil, overrideImage: AvatarNodeImageOverride? = nil, emptyColor: UIColor? = nil, clipStyle: AvatarNodeClipStyle = .round, synchronousLoad: Bool = false, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0), storeUnrounded: Bool = false) {
|
||||
var synchronousLoad = synchronousLoad
|
||||
var representation: TelegramMediaImageRepresentation?
|
||||
var icon = AvatarNodeIcon.none
|
||||
|
|
@ -336,7 +335,7 @@ public final class AvatarNode: ASDisplayNode {
|
|||
} else if peer?.restrictionText(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) == nil {
|
||||
representation = peer?.smallProfileImage
|
||||
}
|
||||
let updatedState: AvatarNodeState = .peerAvatar(peer?.id ?? PeerId(0), peer?.displayLetters ?? [], representation)
|
||||
let updatedState: AvatarNodeState = .peerAvatar(peer?.id ?? EnginePeer.Id(0), peer?.displayLetters ?? [], representation)
|
||||
if updatedState != self.state || overrideImage != self.overrideImage || theme !== self.theme {
|
||||
self.state = updatedState
|
||||
self.overrideImage = overrideImage
|
||||
|
|
@ -344,7 +343,7 @@ public final class AvatarNode: ASDisplayNode {
|
|||
|
||||
let parameters: AvatarNodeParameters
|
||||
|
||||
if let peer = peer, let signal = peerAvatarImage(account: context.account, peerReference: PeerReference(peer), authorOfMessage: authorOfMessage, representation: representation, displayDimensions: displayDimensions, emptyColor: emptyColor, synchronousLoad: synchronousLoad, provideUnrounded: storeUnrounded) {
|
||||
if let peer = peer, let signal = peerAvatarImage(account: context.account, peerReference: PeerReference(peer._asPeer()), authorOfMessage: authorOfMessage, representation: representation, displayDimensions: displayDimensions, emptyColor: emptyColor, synchronousLoad: synchronousLoad, provideUnrounded: storeUnrounded) {
|
||||
self.contents = nil
|
||||
self.displaySuspended = true
|
||||
self.imageReady.set(self.imageNode.contentReady)
|
||||
|
|
@ -380,7 +379,7 @@ public final class AvatarNode: ASDisplayNode {
|
|||
}
|
||||
|
||||
self.editOverlayNode?.isHidden = true
|
||||
parameters = AvatarNodeParameters(theme: theme, accountPeerId: context.account.peerId, peerId: peer?.id ?? PeerId(0), letters: peer?.displayLetters ?? [], font: self.font, icon: icon, explicitColorIndex: nil, hasImage: false, clipStyle: clipStyle)
|
||||
parameters = AvatarNodeParameters(theme: theme, accountPeerId: context.account.peerId, peerId: peer?.id ?? EnginePeer.Id(0), letters: peer?.displayLetters ?? [], font: self.font, icon: icon, explicitColorIndex: nil, hasImage: false, clipStyle: clipStyle)
|
||||
}
|
||||
if self.parameters == nil || self.parameters != parameters {
|
||||
self.parameters = parameters
|
||||
|
|
@ -593,7 +592,7 @@ public final class AvatarNode: ASDisplayNode {
|
|||
}
|
||||
}
|
||||
|
||||
static func asyncLayout(_ node: AvatarNode?) -> (_ context: AccountContext, _ peer: Peer, _ font: UIFont) -> () -> AvatarNode? {
|
||||
static func asyncLayout(_ node: AvatarNode?) -> (_ context: AccountContext, _ peer: EnginePeer, _ font: UIFont) -> () -> AvatarNode? {
|
||||
let currentState = node?.state
|
||||
let createNode = node == nil
|
||||
return { [weak node] context, peer, font in
|
||||
|
|
@ -622,7 +621,7 @@ public final class AvatarNode: ASDisplayNode {
|
|||
}
|
||||
}
|
||||
|
||||
public func drawPeerAvatarLetters(context: CGContext, size: CGSize, round: Bool = true, font: UIFont, letters: [String], peerId: PeerId) {
|
||||
public func drawPeerAvatarLetters(context: CGContext, size: CGSize, round: Bool = true, font: UIFont, letters: [String], peerId: EnginePeer.Id) {
|
||||
if round {
|
||||
context.beginPath()
|
||||
context.addEllipse(in: CGRect(x: 0.0, y: 0.0, width: size.width, height:
|
||||
|
|
|
|||
|
|
@ -60,8 +60,7 @@ public func peerAvatarImageData(account: Account, peerReference: PeerReference?,
|
|||
subscriber.putNext(nil)
|
||||
}
|
||||
}
|
||||
}, error: { error in
|
||||
subscriber.putError(error)
|
||||
}, error: { _ in
|
||||
}, completed: {
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -6,9 +6,11 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
"//submodules/LocalAuth:LocalAuth",
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ final class BotCheckoutActionButton: HighlightableButtonNode {
|
|||
let previousState = self.state
|
||||
self.state = state
|
||||
|
||||
if let (absoluteRect, containerSize) = self.validLayout, let previousState = previousState {
|
||||
if let (absoluteRect, containerSize) = self.validLayout, let _ = previousState {
|
||||
self.updateLayout(absoluteRect: absoluteRect, containerSize: containerSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import Display
|
|||
import AsyncDisplayKit
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
|
||||
|
|
@ -25,7 +24,7 @@ public final class BotCheckoutController: ViewController {
|
|||
self.validatedFormInfo = validatedFormInfo
|
||||
}
|
||||
|
||||
public static func fetch(context: AccountContext, messageId: MessageId) -> Signal<InputData, FetchError> {
|
||||
public static func fetch(context: AccountContext, messageId: EngineMessage.Id) -> Signal<InputData, FetchError> {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let themeParams: [String: Any] = [
|
||||
"bg_color": Int32(bitPattern: presentationData.theme.list.plainBackgroundColor.argb),
|
||||
|
|
@ -78,8 +77,8 @@ public final class BotCheckoutController: ViewController {
|
|||
|
||||
private let context: AccountContext
|
||||
private let invoice: TelegramMediaInvoice
|
||||
private let messageId: MessageId
|
||||
private let completed: (String, MessageId?) -> Void
|
||||
private let messageId: EngineMessage.Id
|
||||
private let completed: (String, EngineMessage.Id?) -> Void
|
||||
|
||||
private var presentationData: PresentationData
|
||||
|
||||
|
|
@ -87,7 +86,7 @@ public final class BotCheckoutController: ViewController {
|
|||
|
||||
private let inputData: Promise<BotCheckoutController.InputData?>
|
||||
|
||||
public init(context: AccountContext, invoice: TelegramMediaInvoice, messageId: MessageId, inputData: Promise<BotCheckoutController.InputData?>, completed: @escaping (String, MessageId?) -> Void) {
|
||||
public init(context: AccountContext, invoice: TelegramMediaInvoice, messageId: EngineMessage.Id, inputData: Promise<BotCheckoutController.InputData?>, completed: @escaping (String, EngineMessage.Id?) -> Void) {
|
||||
self.context = context
|
||||
self.invoice = invoice
|
||||
self.messageId = messageId
|
||||
|
|
@ -120,8 +119,6 @@ public final class BotCheckoutController: ViewController {
|
|||
self?.dismiss()
|
||||
}, completed: self.completed)
|
||||
|
||||
//displayNode.enableInteractiveDismiss = true
|
||||
|
||||
displayNode.dismiss = { [weak self] in
|
||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import Foundation
|
|||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import PassKit
|
||||
|
|
@ -327,7 +326,7 @@ private func currentTotalPrice(paymentForm: BotPaymentForm?, validatedFormInfo:
|
|||
return totalPrice
|
||||
}
|
||||
|
||||
private func botCheckoutControllerEntries(presentationData: PresentationData, state: BotCheckoutControllerState, invoice: TelegramMediaInvoice, paymentForm: BotPaymentForm?, formInfo: BotPaymentRequestedInfo?, validatedFormInfo: BotPaymentValidatedFormInfo?, currentShippingOptionId: String?, currentPaymentMethod: BotCheckoutPaymentMethod?, currentTip: Int64?, botPeer: Peer?) -> [BotCheckoutEntry] {
|
||||
private func botCheckoutControllerEntries(presentationData: PresentationData, state: BotCheckoutControllerState, invoice: TelegramMediaInvoice, paymentForm: BotPaymentForm?, formInfo: BotPaymentRequestedInfo?, validatedFormInfo: BotPaymentValidatedFormInfo?, currentShippingOptionId: String?, currentPaymentMethod: BotCheckoutPaymentMethod?, currentTip: Int64?, botPeer: EnginePeer?) -> [BotCheckoutEntry] {
|
||||
var entries: [BotCheckoutEntry] = []
|
||||
|
||||
var botName = ""
|
||||
|
|
@ -460,7 +459,8 @@ private func formSupportApplePay(_ paymentForm: BotPaymentForm) -> Bool {
|
|||
"yandex",
|
||||
"privatbank",
|
||||
"tranzzo",
|
||||
"paymaster"
|
||||
"paymaster",
|
||||
"smartglocal",
|
||||
])
|
||||
if !applePayProviders.contains(nativeProvider.name) {
|
||||
return false
|
||||
|
|
@ -503,10 +503,10 @@ private func availablePaymentMethods(form: BotPaymentForm, current: BotCheckoutP
|
|||
final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthorizationViewControllerDelegate {
|
||||
private weak var controller: BotCheckoutController?
|
||||
private let context: AccountContext
|
||||
private let messageId: MessageId
|
||||
private let messageId: EngineMessage.Id
|
||||
private let present: (ViewController, Any?) -> Void
|
||||
private let dismissAnimated: () -> Void
|
||||
private let completed: (String, MessageId?) -> Void
|
||||
private let completed: (String, EngineMessage.Id?) -> Void
|
||||
|
||||
private var stateValue = BotCheckoutControllerState()
|
||||
private let state = ValuePromise(BotCheckoutControllerState(), ignoreRepeated: true)
|
||||
|
|
@ -537,7 +537,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||
private var passwordTip: String?
|
||||
private var passwordTipDisposable: Disposable?
|
||||
|
||||
init(controller: BotCheckoutController?, navigationBar: NavigationBar, context: AccountContext, invoice: TelegramMediaInvoice, messageId: MessageId, inputData: Promise<BotCheckoutController.InputData?>, present: @escaping (ViewController, Any?) -> Void, dismissAnimated: @escaping () -> Void, completed: @escaping (String, MessageId?) -> Void) {
|
||||
init(controller: BotCheckoutController?, navigationBar: NavigationBar, context: AccountContext, invoice: TelegramMediaInvoice, messageId: EngineMessage.Id, inputData: Promise<BotCheckoutController.InputData?>, present: @escaping (ViewController, Any?) -> Void, dismissAnimated: @escaping () -> Void, completed: @escaping (String, EngineMessage.Id?) -> Void) {
|
||||
self.controller = controller
|
||||
self.context = context
|
||||
self.messageId = messageId
|
||||
|
|
@ -565,14 +565,22 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||
ensureTipInputVisibleImpl?()
|
||||
})
|
||||
|
||||
let paymentBotPeer = paymentFormAndInfo.get()
|
||||
|> map { paymentFormAndInfo -> PeerId? in
|
||||
return paymentFormAndInfo?.0.paymentBotId
|
||||
let paymentBotPeer: Signal<EnginePeer?, NoError> = paymentFormAndInfo.get()
|
||||
|> map { paymentFormAndInfo -> EnginePeer.Id? in
|
||||
if let paymentBotId = paymentFormAndInfo?.0.paymentBotId {
|
||||
return paymentBotId
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|> mapToSignal { peerId -> Signal<Peer?, NoError> in
|
||||
return context.account.postbox.transaction { transaction -> Peer? in
|
||||
return peerId.flatMap(transaction.getPeer)
|
||||
|> mapToSignal { peerId -> Signal<EnginePeer?, NoError> in
|
||||
if let peerId = peerId {
|
||||
return context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)
|
||||
)
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1123,9 +1131,10 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||
}
|
||||
|
||||
let botPeerId = self.messageId.peerId
|
||||
let _ = (self.context.account.postbox.transaction({ transaction -> Peer? in
|
||||
return transaction.getPeer(botPeerId)
|
||||
}) |> deliverOnMainQueue).start(next: { [weak self] botPeer in
|
||||
let _ = (context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: botPeerId)
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] botPeer in
|
||||
if let strongSelf = self, let botPeer = botPeer {
|
||||
let request = PKPaymentRequest()
|
||||
|
||||
|
|
@ -1191,10 +1200,17 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||
}
|
||||
|
||||
if !liabilityNoticeAccepted {
|
||||
let botPeer: Signal<Peer?, NoError> = self.context.account.postbox.transaction { transaction -> Peer? in
|
||||
return transaction.getPeer(paymentForm.paymentBotId)
|
||||
}
|
||||
let _ = (combineLatest(ApplicationSpecificNotice.getBotPaymentLiability(accountManager: self.context.sharedContext.accountManager, peerId: paymentForm.paymentBotId), botPeer, self.context.account.postbox.loadedPeerWithId(paymentForm.providerId))
|
||||
let botPeer: Signal<EnginePeer?, NoError> = context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: paymentForm.paymentBotId)
|
||||
)
|
||||
let providerPeer: Signal<EnginePeer?, NoError> = context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: paymentForm.providerId)
|
||||
)
|
||||
let _ = (combineLatest(
|
||||
ApplicationSpecificNotice.getBotPaymentLiability(accountManager: self.context.sharedContext.accountManager, peerId: paymentForm.paymentBotId),
|
||||
botPeer,
|
||||
providerPeer
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] value, botPeer, providerPeer in
|
||||
if let strongSelf = self, let botPeer = botPeer {
|
||||
if value {
|
||||
|
|
@ -1202,7 +1218,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||
} else {
|
||||
let paymentText = strongSelf.presentationData.strings.Checkout_PaymentLiabilityAlert
|
||||
.replacingOccurrences(of: "{target}", with: botPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
.replacingOccurrences(of: "{payment_system}", with: providerPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
.replacingOccurrences(of: "{payment_system}", with: providerPeer?.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder) ?? "")
|
||||
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: strongSelf.presentationData.strings.Checkout_LiabilityAlertTitle, text: paymentText, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: { }), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {
|
||||
if let strongSelf = self {
|
||||
|
|
@ -1243,7 +1259,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
|||
applePayController.presentingViewController?.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
let proceedWithCompletion: (Bool, MessageId?) -> Void = { success, receiptMessageId in
|
||||
let proceedWithCompletion: (Bool, EngineMessage.Id?) -> Void = { success, receiptMessageId in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import UIKit
|
|||
import SwiftSignalKit
|
||||
import Display
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import TelegramPresentationData
|
||||
import ProgressNavigationButtonNode
|
||||
import AccountContext
|
||||
|
|
@ -31,7 +30,7 @@ final class BotCheckoutInfoController: ViewController {
|
|||
|
||||
private let context: AccountContext
|
||||
private let invoice: BotPaymentInvoice
|
||||
private let messageId: MessageId
|
||||
private let messageId: EngineMessage.Id
|
||||
private let initialFormInfo: BotPaymentRequestedInfo
|
||||
private let focus: BotCheckoutInfoControllerFocus
|
||||
|
||||
|
|
@ -44,7 +43,14 @@ final class BotCheckoutInfoController: ViewController {
|
|||
private var doneItem: UIBarButtonItem?
|
||||
private var activityItem: UIBarButtonItem?
|
||||
|
||||
public init(context: AccountContext, invoice: BotPaymentInvoice, messageId: MessageId, initialFormInfo: BotPaymentRequestedInfo, focus: BotCheckoutInfoControllerFocus, formInfoUpdated: @escaping (BotPaymentRequestedInfo, BotPaymentValidatedFormInfo) -> Void) {
|
||||
public init(
|
||||
context: AccountContext,
|
||||
invoice: BotPaymentInvoice,
|
||||
messageId: EngineMessage.Id,
|
||||
initialFormInfo: BotPaymentRequestedInfo,
|
||||
focus: BotCheckoutInfoControllerFocus,
|
||||
formInfoUpdated: @escaping (BotPaymentRequestedInfo, BotPaymentValidatedFormInfo) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.invoice = invoice
|
||||
self.messageId = messageId
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import UIKit
|
|||
import AsyncDisplayKit
|
||||
import Display
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
|
|
@ -96,7 +95,7 @@ enum BotCheckoutInfoControllerStatus {
|
|||
final class BotCheckoutInfoControllerNode: ViewControllerTracingNode, UIScrollViewDelegate {
|
||||
private let context: AccountContext
|
||||
private let invoice: BotPaymentInvoice
|
||||
private let messageId: MessageId
|
||||
private let messageId: EngineMessage.Id
|
||||
private var focus: BotCheckoutInfoControllerFocus?
|
||||
|
||||
private let dismiss: () -> Void
|
||||
|
|
@ -124,7 +123,20 @@ final class BotCheckoutInfoControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||
private let verifyDisposable = MetaDisposable()
|
||||
private var isVerifying = false
|
||||
|
||||
init(context: AccountContext, invoice: BotPaymentInvoice, messageId: MessageId, formInfo: BotPaymentRequestedInfo, focus: BotCheckoutInfoControllerFocus, theme: PresentationTheme, strings: PresentationStrings, dismiss: @escaping () -> Void, openCountrySelection: @escaping () -> Void, updateStatus: @escaping (BotCheckoutInfoControllerStatus) -> Void, formInfoUpdated: @escaping (BotPaymentRequestedInfo, BotPaymentValidatedFormInfo) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
||||
init(
|
||||
context: AccountContext,
|
||||
invoice: BotPaymentInvoice,
|
||||
messageId: EngineMessage.Id,
|
||||
formInfo: BotPaymentRequestedInfo,
|
||||
focus: BotCheckoutInfoControllerFocus,
|
||||
theme: PresentationTheme,
|
||||
strings: PresentationStrings,
|
||||
dismiss: @escaping () -> Void,
|
||||
openCountrySelection: @escaping () -> Void,
|
||||
updateStatus: @escaping (BotCheckoutInfoControllerStatus) -> Void,
|
||||
formInfoUpdated: @escaping (BotPaymentRequestedInfo, BotPaymentValidatedFormInfo) -> Void,
|
||||
present: @escaping (ViewController, Any?) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.invoice = invoice
|
||||
self.messageId = messageId
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import AsyncDisplayKit
|
|||
import SwiftSignalKit
|
||||
import Display
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import TelegramPresentationData
|
||||
import ProgressNavigationButtonNode
|
||||
import AccountContext
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import UIKit
|
|||
import AsyncDisplayKit
|
||||
import Display
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import Stripe
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ final class BotCheckoutPaymentMethodSheetController: ActionSheetController {
|
|||
|
||||
init(context: AccountContext, currentMethod: BotCheckoutPaymentMethod?, methods: [BotCheckoutPaymentMethod], applyValue: @escaping (BotCheckoutPaymentMethod) -> Void, newCard: @escaping () -> Void) {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let theme = presentationData.theme
|
||||
let strings = presentationData.strings
|
||||
|
||||
super.init(theme: ActionSheetControllerTheme(presentationData: presentationData))
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ final class BotCheckoutPaymentShippingOptionSheetController: ActionSheetControll
|
|||
|
||||
init(context: AccountContext, currency: String, options: [BotPaymentShippingOption], currentId: String?, applyValue: @escaping (String) -> Void) {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let theme = presentationData.theme
|
||||
let strings = presentationData.strings
|
||||
|
||||
super.init(theme: ActionSheetControllerTheme(presentationData: presentationData))
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import Display
|
|||
import AsyncDisplayKit
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import Display
|
|||
import AsyncDisplayKit
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
|
||||
|
|
@ -19,13 +18,13 @@ public final class BotReceiptController: ViewController {
|
|||
}
|
||||
|
||||
private let context: AccountContext
|
||||
private let messageId: MessageId
|
||||
private let messageId: EngineMessage.Id
|
||||
|
||||
private var presentationData: PresentationData
|
||||
|
||||
private var didPlayPresentationAnimation = false
|
||||
|
||||
public init(context: AccountContext, messageId: MessageId) {
|
||||
public init(context: AccountContext, messageId: EngineMessage.Id) {
|
||||
self.context = context
|
||||
self.messageId = messageId
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import Foundation
|
|||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
|
|
@ -174,7 +173,7 @@ enum BotReceiptEntry: ItemListNodeEntry {
|
|||
}
|
||||
}
|
||||
|
||||
private func botReceiptControllerEntries(presentationData: PresentationData, invoice: TelegramMediaInvoice?, formInvoice: BotPaymentInvoice?, formInfo: BotPaymentRequestedInfo?, shippingOption: BotPaymentShippingOption?, paymentMethodTitle: String?, botPeer: Peer?, tipAmount: Int64?) -> [BotReceiptEntry] {
|
||||
private func botReceiptControllerEntries(presentationData: PresentationData, invoice: TelegramMediaInvoice?, formInvoice: BotPaymentInvoice?, formInfo: BotPaymentRequestedInfo?, shippingOption: BotPaymentShippingOption?, paymentMethodTitle: String?, botPeer: EnginePeer?, tipAmount: Int64?) -> [BotReceiptEntry] {
|
||||
var entries: [BotReceiptEntry] = []
|
||||
|
||||
var botName = ""
|
||||
|
|
@ -279,7 +278,7 @@ final class BotReceiptControllerNode: ItemListControllerNode {
|
|||
private let actionButtonPanelSeparator: ASDisplayNode
|
||||
private let actionButton: BotCheckoutActionButton
|
||||
|
||||
init(controller: ItemListController?, navigationBar: NavigationBar, context: AccountContext, messageId: MessageId, dismissAnimated: @escaping () -> Void) {
|
||||
init(controller: ItemListController?, navigationBar: NavigationBar, context: AccountContext, messageId: EngineMessage.Id, dismissAnimated: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.dismissAnimated = dismissAnimated
|
||||
|
||||
|
|
@ -287,7 +286,13 @@ final class BotReceiptControllerNode: ItemListControllerNode {
|
|||
|
||||
let arguments = BotReceiptControllerArguments(account: context.account)
|
||||
|
||||
let signal: Signal<(ItemListPresentationData, (ItemListNodeState, Any)), NoError> = combineLatest(context.sharedContext.presentationData, receiptData.get(), context.account.postbox.loadedPeerWithId(messageId.peerId))
|
||||
let signal: Signal<(ItemListPresentationData, (ItemListNodeState, Any)), NoError> = combineLatest(
|
||||
context.sharedContext.presentationData,
|
||||
receiptData.get(),
|
||||
context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: messageId.peerId)
|
||||
)
|
||||
)
|
||||
|> map { presentationData, receiptData, botPeer -> (ItemListPresentationData, (ItemListNodeState, Any)) in
|
||||
let nodeState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: botReceiptControllerEntries(presentationData: presentationData, invoice: receiptData?.4, formInvoice: receiptData?.0, formInfo: receiptData?.1, shippingOption: receiptData?.2, paymentMethodTitle: receiptData?.3, botPeer: botPeer, tipAmount: receiptData?.5), style: .blocks, focusItemTag: nil, emptyStateItem: nil, animateChanges: false)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,11 +6,13 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import TelegramCore
|
||||
|
|
@ -68,8 +67,8 @@ class CallListCallItem: ListViewItem {
|
|||
let dateTimeFormat: PresentationDateTimeFormat
|
||||
let context: AccountContext
|
||||
let style: ItemListStyle
|
||||
let topMessage: Message
|
||||
let messages: [Message]
|
||||
let topMessage: EngineMessage
|
||||
let messages: [EngineMessage]
|
||||
let editing: Bool
|
||||
let revealed: Bool
|
||||
let interaction: CallListNodeInteraction
|
||||
|
|
@ -78,7 +77,7 @@ class CallListCallItem: ListViewItem {
|
|||
let headerAccessoryItem: ListViewAccessoryItem?
|
||||
let header: ListViewItemHeader?
|
||||
|
||||
init(presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, context: AccountContext, style: ItemListStyle, topMessage: Message, messages: [Message], editing: Bool, revealed: Bool, displayHeader: Bool, interaction: CallListNodeInteraction) {
|
||||
init(presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, context: AccountContext, style: ItemListStyle, topMessage: EngineMessage, messages: [EngineMessage], editing: Bool, revealed: Bool, displayHeader: Bool, interaction: CallListNodeInteraction) {
|
||||
self.presentationData = presentationData
|
||||
self.dateTimeFormat = dateTimeFormat
|
||||
self.context = context
|
||||
|
|
@ -488,7 +487,7 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode {
|
|||
if peer.isDeleted {
|
||||
overrideImage = .deletedIcon
|
||||
}
|
||||
strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoads)
|
||||
strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: EnginePeer(peer), overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoads)
|
||||
}
|
||||
|
||||
return (strongSelf.avatarNode.ready, { [weak strongSelf] animated in
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import Foundation
|
|||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
|
|
@ -205,10 +204,11 @@ public final class CallListController: TelegramBaseController {
|
|||
}
|
||||
}, openInfo: { [weak self] peerId, messages in
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.context.account.postbox.loadedPeerWithId(peerId)
|
||||
|> take(1)
|
||||
let _ = (strongSelf.context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
if let strongSelf = self, let controller = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .calls(messages: messages), avatarInitiallyExpanded: false, fromChat: false) {
|
||||
if let strongSelf = self, let peer = peer, let controller = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer._asPeer(), mode: .calls(messages: messages.map({ $0._asMessage() })), avatarInitiallyExpanded: false, fromChat: false) {
|
||||
(strongSelf.navigationController as? NavigationController)?.pushViewController(controller)
|
||||
}
|
||||
})
|
||||
|
|
@ -436,7 +436,7 @@ public final class CallListController: TelegramBaseController {
|
|||
}
|
||||
}
|
||||
|
||||
private func call(_ peerId: PeerId, isVideo: Bool, began: (() -> Void)? = nil) {
|
||||
private func call(_ peerId: EnginePeer.Id, isVideo: Bool, began: (() -> Void)? = nil) {
|
||||
self.peerViewDisposable.set((self.context.account.viewTracker.peerView(peerId)
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] view in
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import Foundation
|
|||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
|
|
@ -25,8 +24,8 @@ private struct CallListNodeListViewTransition {
|
|||
let stationaryItemRange: (Int, Int)?
|
||||
}
|
||||
|
||||
private extension CallListViewEntry {
|
||||
var lowestIndex: MessageIndex {
|
||||
private extension EngineCallList.Item {
|
||||
var lowestIndex: EngineMessage.Index {
|
||||
switch self {
|
||||
case let .hole(index):
|
||||
return index
|
||||
|
|
@ -42,7 +41,7 @@ private extension CallListViewEntry {
|
|||
}
|
||||
}
|
||||
|
||||
var highestIndex: MessageIndex {
|
||||
var highestIndex: EngineMessage.Index {
|
||||
switch self {
|
||||
case let .hole(index):
|
||||
return index
|
||||
|
|
@ -60,14 +59,14 @@ private extension CallListViewEntry {
|
|||
}
|
||||
|
||||
final class CallListNodeInteraction {
|
||||
let setMessageIdWithRevealedOptions: (MessageId?, MessageId?) -> Void
|
||||
let call: (PeerId, Bool) -> Void
|
||||
let openInfo: (PeerId, [Message]) -> Void
|
||||
let delete: ([MessageId]) -> Void
|
||||
let setMessageIdWithRevealedOptions: (EngineMessage.Id?, EngineMessage.Id?) -> Void
|
||||
let call: (EnginePeer.Id, Bool) -> Void
|
||||
let openInfo: (EnginePeer.Id, [EngineMessage]) -> Void
|
||||
let delete: ([EngineMessage.Id]) -> Void
|
||||
let updateShowCallsTab: (Bool) -> Void
|
||||
let openGroupCall: (PeerId) -> Void
|
||||
let openGroupCall: (EnginePeer.Id) -> Void
|
||||
|
||||
init(setMessageIdWithRevealedOptions: @escaping (MessageId?, MessageId?) -> Void, call: @escaping (PeerId, Bool) -> Void, openInfo: @escaping (PeerId, [Message]) -> Void, delete: @escaping ([MessageId]) -> Void, updateShowCallsTab: @escaping (Bool) -> Void, openGroupCall: @escaping (PeerId) -> Void) {
|
||||
init(setMessageIdWithRevealedOptions: @escaping (EngineMessage.Id?, EngineMessage.Id?) -> Void, call: @escaping (EnginePeer.Id, Bool) -> Void, openInfo: @escaping (EnginePeer.Id, [EngineMessage]) -> Void, delete: @escaping ([EngineMessage.Id]) -> Void, updateShowCallsTab: @escaping (Bool) -> Void, openGroupCall: @escaping (EnginePeer.Id) -> Void) {
|
||||
self.setMessageIdWithRevealedOptions = setMessageIdWithRevealedOptions
|
||||
self.call = call
|
||||
self.openInfo = openInfo
|
||||
|
|
@ -82,7 +81,7 @@ struct CallListNodeState: Equatable {
|
|||
let dateTimeFormat: PresentationDateTimeFormat
|
||||
let disableAnimations: Bool
|
||||
let editing: Bool
|
||||
let messageIdWithRevealedOptions: MessageId?
|
||||
let messageIdWithRevealedOptions: EngineMessage.Id?
|
||||
|
||||
func withUpdatedPresentationData(presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, disableAnimations: Bool) -> CallListNodeState {
|
||||
return CallListNodeState(presentationData: presentationData, dateTimeFormat: dateTimeFormat, disableAnimations: disableAnimations, editing: self.editing, messageIdWithRevealedOptions: self.messageIdWithRevealedOptions)
|
||||
|
|
@ -92,7 +91,7 @@ struct CallListNodeState: Equatable {
|
|||
return CallListNodeState(presentationData: self.presentationData, dateTimeFormat: self.dateTimeFormat, disableAnimations: self.disableAnimations, editing: editing, messageIdWithRevealedOptions: self.messageIdWithRevealedOptions)
|
||||
}
|
||||
|
||||
func withUpdatedMessageIdWithRevealedOptions(_ messageIdWithRevealedOptions: MessageId?) -> CallListNodeState {
|
||||
func withUpdatedMessageIdWithRevealedOptions(_ messageIdWithRevealedOptions: EngineMessage.Id?) -> CallListNodeState {
|
||||
return CallListNodeState(presentationData: self.presentationData, dateTimeFormat: self.dateTimeFormat, disableAnimations: self.disableAnimations, editing: self.editing, messageIdWithRevealedOptions: messageIdWithRevealedOptions)
|
||||
}
|
||||
|
||||
|
|
@ -177,9 +176,9 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
return _ready.get()
|
||||
}
|
||||
|
||||
var peerSelected: ((PeerId) -> Void)?
|
||||
var peerSelected: ((EnginePeer.Id) -> Void)?
|
||||
var activateSearch: (() -> Void)?
|
||||
var deletePeerChat: ((PeerId) -> Void)?
|
||||
var deletePeerChat: ((EnginePeer.Id) -> Void)?
|
||||
var startNewCall: (() -> Void)?
|
||||
|
||||
private let viewProcessingQueue = Queue()
|
||||
|
|
@ -191,7 +190,7 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
private var currentState: CallListNodeState
|
||||
private let statePromise: ValuePromise<CallListNodeState>
|
||||
|
||||
private var currentLocationAndType = CallListNodeLocationAndType(location: .initial(count: 50), type: .all)
|
||||
private var currentLocationAndType = CallListNodeLocationAndType(location: .initial(count: 50), scope: .all)
|
||||
private let callListLocationAndType = ValuePromise<CallListNodeLocationAndType>()
|
||||
private let callListDisposable = MetaDisposable()
|
||||
|
||||
|
|
@ -205,9 +204,9 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
private let emptyButtonIconNode: ASImageNode
|
||||
private let emptyButtonTextNode: ImmediateTextNode
|
||||
|
||||
private let call: (PeerId, Bool) -> Void
|
||||
private let joinGroupCall: (PeerId, CachedChannelData.ActiveCall) -> Void
|
||||
private let openInfo: (PeerId, [Message]) -> Void
|
||||
private let call: (EnginePeer.Id, Bool) -> Void
|
||||
private let joinGroupCall: (EnginePeer.Id, EngineGroupCallDescription) -> Void
|
||||
private let openInfo: (EnginePeer.Id, [EngineMessage]) -> Void
|
||||
private let emptyStateUpdated: (Bool) -> Void
|
||||
|
||||
private let emptyStatePromise = Promise<Bool>()
|
||||
|
|
@ -215,7 +214,7 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
|
||||
private let openGroupCallDisposable = MetaDisposable()
|
||||
|
||||
init(controller: CallListController, context: AccountContext, mode: CallListControllerMode, presentationData: PresentationData, call: @escaping (PeerId, Bool) -> Void, joinGroupCall: @escaping (PeerId, CachedChannelData.ActiveCall) -> Void, openInfo: @escaping (PeerId, [Message]) -> Void, emptyStateUpdated: @escaping (Bool) -> Void) {
|
||||
init(controller: CallListController, context: AccountContext, mode: CallListControllerMode, presentationData: PresentationData, call: @escaping (EnginePeer.Id, Bool) -> Void, joinGroupCall: @escaping (EnginePeer.Id, EngineGroupCallDescription) -> Void, openInfo: @escaping (EnginePeer.Id, [EngineMessage]) -> Void, emptyStateUpdated: @escaping (Bool) -> Void) {
|
||||
self.controller = controller
|
||||
self.context = context
|
||||
self.mode = mode
|
||||
|
|
@ -322,13 +321,12 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
}, openInfo: { [weak self] peerId, messages in
|
||||
self?.openInfo(peerId, messages)
|
||||
}, delete: { [weak self] messageIds in
|
||||
guard let strongSelf = self, let peerId = messageIds.first?.peerId else {
|
||||
guard let peerId = messageIds.first?.peerId else {
|
||||
return
|
||||
}
|
||||
|
||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> Peer? in
|
||||
return transaction.getPeer(peerId)
|
||||
}
|
||||
let _ = (context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
guard let strongSelf = self, let peer = peer else {
|
||||
return
|
||||
|
|
@ -381,19 +379,12 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
}
|
||||
|
||||
let disposable = strongSelf.openGroupCallDisposable
|
||||
|
||||
let account = strongSelf.context.account
|
||||
|
||||
let engine = strongSelf.context.engine
|
||||
var signal: Signal<CachedChannelData.ActiveCall?, NoError> = strongSelf.context.account.postbox.transaction { transaction -> CachedChannelData.ActiveCall? in
|
||||
let cachedData = transaction.getPeerCachedData(peerId: peerId)
|
||||
if let cachedData = cachedData as? CachedChannelData {
|
||||
return cachedData.activeCall
|
||||
} else if let cachedData = cachedData as? CachedGroupData {
|
||||
return cachedData.activeCall
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|> mapToSignal { activeCall -> Signal<CachedChannelData.ActiveCall?, NoError> in
|
||||
var signal: Signal<EngineGroupCallDescription?, NoError> = context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.GroupCallDescription(id: peerId)
|
||||
)
|
||||
|> mapToSignal { activeCall -> Signal<EngineGroupCallDescription?, NoError> in
|
||||
if let activeCall = activeCall {
|
||||
return .single(activeCall)
|
||||
} else {
|
||||
|
|
@ -446,7 +437,7 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
let callListViewUpdate = self.callListLocationAndType.get()
|
||||
|> distinctUntilChanged
|
||||
|> mapToSignal { locationAndType in
|
||||
return callListViewForLocationAndType(locationAndType: locationAndType, account: context.account)
|
||||
return callListViewForLocationAndType(locationAndType: locationAndType, engine: context.engine)
|
||||
}
|
||||
|
||||
let previousView = Atomic<CallListNodeView?>(value: nil)
|
||||
|
|
@ -468,10 +459,10 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
return value
|
||||
}
|
||||
|
||||
let currentGroupCallPeerId: Signal<PeerId?, NoError>
|
||||
let currentGroupCallPeerId: Signal<EnginePeer.Id?, NoError>
|
||||
if let callManager = context.sharedContext.callManager {
|
||||
currentGroupCallPeerId = callManager.currentGroupCallSignal
|
||||
|> map { call -> PeerId? in
|
||||
|> map { call -> EnginePeer.Id? in
|
||||
call?.peerId
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
|
@ -479,19 +470,14 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
currentGroupCallPeerId = .single(nil)
|
||||
}
|
||||
|
||||
let groupCalls = context.account.postbox.tailChatListView(groupId: .root, count: 100, summaryComponents: ChatListEntrySummaryComponents())
|
||||
|> map { view -> [Peer] in
|
||||
var result: [Peer] = []
|
||||
for entry in view.0.entries {
|
||||
switch entry {
|
||||
case let .MessageEntry(_, _, _, _, _, renderedPeer, _, _, _, _):
|
||||
if let channel = renderedPeer.peer as? TelegramChannel, channel.flags.contains(.hasActiveVoiceChat) {
|
||||
result.append(channel)
|
||||
} else if let group = renderedPeer.peer as? TelegramGroup, group.flags.contains(.hasActiveVoiceChat) {
|
||||
result.append(group)
|
||||
}
|
||||
default:
|
||||
break
|
||||
let groupCalls: Signal<[EnginePeer], NoError> = context.engine.messages.chatList(group: .root, count: 100)
|
||||
|> map { chatList -> [EnginePeer] in
|
||||
var result: [EnginePeer] = []
|
||||
for item in chatList.items {
|
||||
if case let .channel(channel) = item.renderedPeer.peer, channel.flags.contains(.hasActiveVoiceChat) {
|
||||
result.append(.channel(channel))
|
||||
} else if case let .legacyGroup(group) = item.renderedPeer.peer, group.flags.contains(.hasActiveVoiceChat) {
|
||||
result.append(.legacyGroup(group))
|
||||
}
|
||||
}
|
||||
return result.sorted(by: { lhs, rhs in
|
||||
|
|
@ -503,19 +489,15 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
return lhs.id < rhs.id
|
||||
})
|
||||
}
|
||||
|> distinctUntilChanged(isEqual: { lhs, rhs in
|
||||
if lhs.count != rhs.count {
|
||||
return false
|
||||
}
|
||||
for i in 0 ..< lhs.count {
|
||||
if !lhs[i].isEqual(rhs[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|> distinctUntilChanged
|
||||
|
||||
let callListNodeViewTransition = combineLatest(callListViewUpdate, self.statePromise.get(), groupCalls, showCallsTab, currentGroupCallPeerId)
|
||||
let callListNodeViewTransition = combineLatest(
|
||||
callListViewUpdate,
|
||||
self.statePromise.get(),
|
||||
groupCalls,
|
||||
showCallsTab,
|
||||
currentGroupCallPeerId
|
||||
)
|
||||
|> mapToQueue { (updateAndType, state, groupCalls, showCallsTab, currentGroupCallPeerId) -> Signal<CallListNodeListViewTransition, NoError> in
|
||||
let (update, type) = updateAndType
|
||||
|
||||
|
|
@ -545,7 +527,7 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
}
|
||||
} else {
|
||||
if previous?.originalView === update.view {
|
||||
let previousCalls = previous?.filteredEntries.compactMap { item -> PeerId? in
|
||||
let previousCalls = previous?.filteredEntries.compactMap { item -> EnginePeer.Id? in
|
||||
switch item {
|
||||
case let .groupCall(peer, _, _):
|
||||
return peer.id
|
||||
|
|
@ -553,7 +535,7 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
let updatedCalls = processedView.filteredEntries.compactMap { item -> PeerId? in
|
||||
let updatedCalls = processedView.filteredEntries.compactMap { item -> EnginePeer.Id? in
|
||||
switch item {
|
||||
case let .groupCall(peer, _, _):
|
||||
return peer.id
|
||||
|
|
@ -582,12 +564,14 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
}
|
||||
}
|
||||
|
||||
return preparedCallListNodeViewTransition(from: previous, to: processedView, reason: reason, disableAnimations: disableAnimations, account: context.account, scrollPosition: update.scrollPosition)
|
||||
return preparedCallListNodeViewTransition(from: previous, to: processedView, reason: reason, disableAnimations: disableAnimations, context: context, scrollPosition: update.scrollPosition)
|
||||
|> map({ mappedCallListNodeViewListTransition(context: context, presentationData: state.presentationData, showSettings: showSettings, nodeInteraction: nodeInteraction, transition: $0) })
|
||||
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
|
||||
}
|
||||
|
||||
let appliedTransition = callListNodeViewTransition |> deliverOnMainQueue |> mapToQueue { [weak self] transition -> Signal<Void, NoError> in
|
||||
let appliedTransition = callListNodeViewTransition
|
||||
|> deliverOnMainQueue
|
||||
|> mapToQueue { [weak self] transition -> Signal<Void, NoError> in
|
||||
if let strongSelf = self {
|
||||
return strongSelf.enqueueTransition(transition)
|
||||
}
|
||||
|
|
@ -597,14 +581,14 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
self.listNode.displayedItemRangeChanged = { [weak self] range, transactionOpaqueState in
|
||||
if let strongSelf = self, let range = range.loadedRange, let view = (transactionOpaqueState as? CallListOpaqueTransactionState)?.callListView.originalView {
|
||||
var location: CallListNodeLocation?
|
||||
if range.firstIndex < 5 && view.later != nil {
|
||||
location = .navigation(index: view.entries[view.entries.count - 1].highestIndex)
|
||||
} else if range.firstIndex >= 5 && range.lastIndex >= view.entries.count - 5 && view.earlier != nil {
|
||||
location = .navigation(index: view.entries[0].lowestIndex)
|
||||
if range.firstIndex < 5 && view.hasLater {
|
||||
location = .navigation(index: view.items[view.items.count - 1].highestIndex)
|
||||
} else if range.firstIndex >= 5 && range.lastIndex >= view.items.count - 5 && view.hasEarlier {
|
||||
location = .navigation(index: view.items[0].lowestIndex)
|
||||
}
|
||||
|
||||
if let location = location, location != strongSelf.currentLocationAndType.location {
|
||||
strongSelf.currentLocationAndType = CallListNodeLocationAndType(location: location, type: strongSelf.currentLocationAndType.type)
|
||||
strongSelf.currentLocationAndType = CallListNodeLocationAndType(location: location, scope: strongSelf.currentLocationAndType.scope)
|
||||
strongSelf.callListLocationAndType.set(strongSelf.currentLocationAndType)
|
||||
}
|
||||
}
|
||||
|
|
@ -615,9 +599,10 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
self.callListLocationAndType.set(self.currentLocationAndType)
|
||||
|
||||
let emptySignal = self.emptyStatePromise.get() |> distinctUntilChanged
|
||||
let typeSignal = self.callListLocationAndType.get() |> map { locationAndType -> CallListViewType in
|
||||
return locationAndType.type
|
||||
} |> distinctUntilChanged
|
||||
let typeSignal = self.callListLocationAndType.get() |> map { locationAndType -> EngineCallList.Scope in
|
||||
return locationAndType.scope
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
self.emptyStateDisposable.set((combineLatest(emptySignal, typeSignal, self.statePromise.get()) |> deliverOnMainQueue).start(next: { [weak self] isEmpty, type, state in
|
||||
if let strongSelf = self {
|
||||
|
|
@ -649,7 +634,7 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
|
||||
self.emptyButtonIconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Call List/CallIcon"), color: presentationData.theme.list.itemAccentColor)
|
||||
|
||||
self.updateEmptyPlaceholder(theme: presentationData.theme, strings: presentationData.strings, type: self.currentLocationAndType.type, isHidden: self.emptyTextNode.alpha.isZero)
|
||||
self.updateEmptyPlaceholder(theme: presentationData.theme, strings: presentationData.strings, type: self.currentLocationAndType.scope, isHidden: self.emptyTextNode.alpha.isZero)
|
||||
|
||||
self.updateState {
|
||||
return $0.withUpdatedPresentationData(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, disableAnimations: true)
|
||||
|
|
@ -666,7 +651,7 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
private let textFont = Font.regular(16.0)
|
||||
private let buttonFont = Font.regular(17.0)
|
||||
|
||||
func updateEmptyPlaceholder(theme: PresentationTheme, strings: PresentationStrings, type: CallListViewType, isHidden: Bool) {
|
||||
func updateEmptyPlaceholder(theme: PresentationTheme, strings: PresentationStrings, type: EngineCallList.Scope, isHidden: Bool) {
|
||||
let alpha: CGFloat = isHidden ? 0.0 : 1.0
|
||||
let previousAlpha = self.emptyTextNode.alpha
|
||||
self.emptyTextNode.alpha = alpha
|
||||
|
|
@ -691,7 +676,7 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
self.emptyButtonNode.isUserInteractionEnabled = !isHidden
|
||||
|
||||
if !isHidden {
|
||||
let type = self.currentLocationAndType.type
|
||||
let type = self.currentLocationAndType.scope
|
||||
let emptyText: String
|
||||
let buttonText = strings.Calls_StartNewCall
|
||||
if type == .missed {
|
||||
|
|
@ -730,16 +715,16 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
}
|
||||
}
|
||||
|
||||
func updateType(_ type: CallListViewType) {
|
||||
if type != self.currentLocationAndType.type {
|
||||
func updateType(_ type: EngineCallList.Scope) {
|
||||
if type != self.currentLocationAndType.scope {
|
||||
if let view = self.callListView?.originalView {
|
||||
var index: MessageIndex
|
||||
if !view.entries.isEmpty {
|
||||
index = view.entries[view.entries.count - 1].highestIndex
|
||||
var index: EngineMessage.Index
|
||||
if !view.items.isEmpty {
|
||||
index = view.items[view.items.count - 1].highestIndex
|
||||
} else {
|
||||
index = MessageIndex.absoluteUpperBound()
|
||||
index = EngineMessage.Index.absoluteUpperBound()
|
||||
}
|
||||
self.currentLocationAndType = CallListNodeLocationAndType(location: .changeType(index: index), type: type)
|
||||
self.currentLocationAndType = CallListNodeLocationAndType(location: .changeType(index: index), scope: type)
|
||||
self.emptyStatePromise.set(.single(false))
|
||||
self.callListLocationAndType.set(self.currentLocationAndType)
|
||||
}
|
||||
|
|
@ -799,11 +784,11 @@ final class CallListControllerNode: ASDisplayNode {
|
|||
}
|
||||
|
||||
func scrollToLatest() {
|
||||
if let view = self.callListView?.originalView, view.later == nil {
|
||||
if let view = self.callListView?.originalView, !view.hasLater {
|
||||
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
} else {
|
||||
let location: CallListNodeLocation = .scroll(index: MessageIndex.absoluteUpperBound(), sourceIndex: MessageIndex.absoluteLowerBound(), scrollPosition: .top(0.0), animated: true)
|
||||
self.currentLocationAndType = CallListNodeLocationAndType(location: location, type: self.currentLocationAndType.type)
|
||||
let location: CallListNodeLocation = .scroll(index: EngineMessage.Index.absoluteUpperBound(), sourceIndex: EngineMessage.Index.absoluteLowerBound(), scrollPosition: .top(0.0), animated: true)
|
||||
self.currentLocationAndType = CallListNodeLocationAndType(location: location, scope: self.currentLocationAndType.scope)
|
||||
self.callListLocationAndType.set(self.currentLocationAndType)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import TelegramCore
|
||||
|
|
@ -60,7 +59,7 @@ class CallListGroupCallItem: ListViewItem {
|
|||
let presentationData: ItemListPresentationData
|
||||
let context: AccountContext
|
||||
let style: ItemListStyle
|
||||
let peer: Peer
|
||||
let peer: EnginePeer
|
||||
let isActive: Bool
|
||||
let editing: Bool
|
||||
let interaction: CallListNodeInteraction
|
||||
|
|
@ -69,7 +68,7 @@ class CallListGroupCallItem: ListViewItem {
|
|||
let headerAccessoryItem: ListViewAccessoryItem?
|
||||
let header: ListViewItemHeader?
|
||||
|
||||
init(presentationData: ItemListPresentationData, context: AccountContext, style: ItemListStyle, peer: Peer, isActive: Bool, editing: Bool, interaction: CallListNodeInteraction) {
|
||||
init(presentationData: ItemListPresentationData, context: AccountContext, style: ItemListStyle, peer: EnginePeer, isActive: Bool, editing: Bool, interaction: CallListNodeInteraction) {
|
||||
self.presentationData = presentationData
|
||||
self.context = context
|
||||
self.style = style
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import MergeLists
|
||||
|
||||
enum CallListNodeEntryId: Hashable {
|
||||
case setting(Int32)
|
||||
case groupCall(PeerId)
|
||||
case hole(MessageIndex)
|
||||
case message(MessageIndex)
|
||||
case groupCall(EnginePeer.Id)
|
||||
case hole(EngineMessage.Index)
|
||||
case message(EngineMessage.Index)
|
||||
}
|
||||
|
||||
private func areMessagesEqual(_ lhsMessage: Message, _ rhsMessage: Message) -> Bool {
|
||||
private func areMessagesEqual(_ lhsMessage: EngineMessage, _ rhsMessage: EngineMessage) -> Bool {
|
||||
if lhsMessage.stableVersion != rhsMessage.stableVersion {
|
||||
return false
|
||||
}
|
||||
|
|
@ -26,9 +25,9 @@ enum CallListNodeEntry: Comparable, Identifiable {
|
|||
enum SortIndex: Comparable {
|
||||
case displayTab
|
||||
case displayTabInfo
|
||||
case groupCall(PeerId, String)
|
||||
case message(MessageIndex)
|
||||
case hole(MessageIndex)
|
||||
case groupCall(EnginePeer.Id, String)
|
||||
case message(EngineMessage.Index)
|
||||
case hole(EngineMessage.Index)
|
||||
|
||||
static func <(lhs: SortIndex, rhs: SortIndex) -> Bool {
|
||||
switch lhs {
|
||||
|
|
@ -79,9 +78,9 @@ enum CallListNodeEntry: Comparable, Identifiable {
|
|||
|
||||
case displayTab(PresentationTheme, String, Bool)
|
||||
case displayTabInfo(PresentationTheme, String)
|
||||
case groupCall(peer: Peer, editing: Bool, isActive: Bool)
|
||||
case messageEntry(topMessage: Message, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, editing: Bool, hasActiveRevealControls: Bool, displayHeader: Bool, missed: Bool)
|
||||
case holeEntry(index: MessageIndex, theme: PresentationTheme)
|
||||
case groupCall(peer: EnginePeer, editing: Bool, isActive: Bool)
|
||||
case messageEntry(topMessage: EngineMessage, messages: [EngineMessage], theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, editing: Bool, hasActiveRevealControls: Bool, displayHeader: Bool, missed: Bool)
|
||||
case holeEntry(index: EngineMessage.Index, theme: PresentationTheme)
|
||||
|
||||
var sortIndex: SortIndex {
|
||||
switch self {
|
||||
|
|
@ -133,7 +132,7 @@ enum CallListNodeEntry: Comparable, Identifiable {
|
|||
}
|
||||
case let .groupCall(lhsPeer, lhsEditing, lhsIsActive):
|
||||
if case let .groupCall(rhsPeer, rhsEditing, rhsIsActive) = rhs {
|
||||
if !lhsPeer.isEqual(rhsPeer) {
|
||||
if lhsPeer != rhsPeer {
|
||||
return false
|
||||
}
|
||||
if lhsEditing != rhsEditing {
|
||||
|
|
@ -194,9 +193,9 @@ enum CallListNodeEntry: Comparable, Identifiable {
|
|||
}
|
||||
}
|
||||
|
||||
func callListNodeEntriesForView(view: CallListView, groupCalls: [Peer], state: CallListNodeState, showSettings: Bool, showCallsTab: Bool, isRecentCalls: Bool, currentGroupCallPeerId: PeerId?) -> [CallListNodeEntry] {
|
||||
func callListNodeEntriesForView(view: EngineCallList, groupCalls: [EnginePeer], state: CallListNodeState, showSettings: Bool, showCallsTab: Bool, isRecentCalls: Bool, currentGroupCallPeerId: EnginePeer.Id?) -> [CallListNodeEntry] {
|
||||
var result: [CallListNodeEntry] = []
|
||||
for entry in view.entries {
|
||||
for entry in view.items {
|
||||
switch entry {
|
||||
case let .message(topMessage, messages):
|
||||
result.append(.messageEntry(topMessage: topMessage, messages: messages, theme: state.presentationData.theme, strings: state.presentationData.strings, dateTimeFormat: state.dateTimeFormat, editing: state.editing, hasActiveRevealControls: state.messageIdWithRevealedOptions == topMessage.id, displayHeader: !showSettings && isRecentCalls, missed: !isRecentCalls))
|
||||
|
|
@ -205,7 +204,7 @@ func callListNodeEntriesForView(view: CallListView, groupCalls: [Peer], state: C
|
|||
}
|
||||
}
|
||||
|
||||
if view.later == nil {
|
||||
if !view.hasLater {
|
||||
if !showSettings && isRecentCalls {
|
||||
for peer in groupCalls.sorted(by: { lhs, rhs in
|
||||
let lhsTitle = lhs.compactDisplayTitle
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import Display
|
||||
|
||||
enum CallListNodeLocation: Equatable {
|
||||
case initial(count: Int)
|
||||
case changeType(index: MessageIndex)
|
||||
case navigation(index: MessageIndex)
|
||||
case scroll(index: MessageIndex, sourceIndex: MessageIndex, scrollPosition: ListViewScrollPosition, animated: Bool)
|
||||
case changeType(index: EngineMessage.Index)
|
||||
case navigation(index: EngineMessage.Index)
|
||||
case scroll(index: EngineMessage.Index, sourceIndex: EngineMessage.Index, scrollPosition: ListViewScrollPosition, animated: Bool)
|
||||
|
||||
static func ==(lhs: CallListNodeLocation, rhs: CallListNodeLocation) -> Bool {
|
||||
switch lhs {
|
||||
|
|
@ -28,11 +27,7 @@ enum CallListNodeLocation: Equatable {
|
|||
|
||||
struct CallListNodeLocationAndType: Equatable {
|
||||
let location: CallListNodeLocation
|
||||
let type: CallListViewType
|
||||
|
||||
static func ==(lhs: CallListNodeLocationAndType, rhs: CallListNodeLocationAndType) -> Bool {
|
||||
return lhs.location == rhs.location && lhs.type == rhs.type
|
||||
}
|
||||
let scope: EngineCallList.Scope
|
||||
}
|
||||
|
||||
enum CallListNodeViewUpdateType {
|
||||
|
|
@ -44,47 +39,67 @@ enum CallListNodeViewUpdateType {
|
|||
}
|
||||
|
||||
struct CallListNodeViewUpdate {
|
||||
let view: CallListView
|
||||
let view: EngineCallList
|
||||
let type: CallListNodeViewUpdateType
|
||||
let scrollPosition: CallListNodeViewScrollPosition?
|
||||
}
|
||||
|
||||
func callListViewForLocationAndType(locationAndType: CallListNodeLocationAndType, account: Account) -> Signal<(CallListNodeViewUpdate, CallListViewType), NoError> {
|
||||
func callListViewForLocationAndType(locationAndType: CallListNodeLocationAndType, engine: TelegramEngine) -> Signal<(CallListNodeViewUpdate, EngineCallList.Scope), NoError> {
|
||||
switch locationAndType.location {
|
||||
case let .initial(count):
|
||||
return account.viewTracker.callListView(type: locationAndType.type, index: MessageIndex.absoluteUpperBound(), count: count) |> map { view -> (CallListNodeViewUpdate, CallListViewType) in
|
||||
return (CallListNodeViewUpdate(view: view, type: .Generic, scrollPosition: nil), locationAndType.type)
|
||||
case let .initial(count):
|
||||
return engine.messages.callList(
|
||||
scope: locationAndType.scope,
|
||||
index: EngineMessage.Index.absoluteUpperBound(),
|
||||
itemCount: count
|
||||
)
|
||||
|> map { view -> (CallListNodeViewUpdate, EngineCallList.Scope) in
|
||||
return (CallListNodeViewUpdate(view: view, type: .Generic, scrollPosition: nil), locationAndType.scope)
|
||||
}
|
||||
case let .changeType(index):
|
||||
return engine.messages.callList(
|
||||
scope: locationAndType.scope,
|
||||
index: index,
|
||||
itemCount: 120
|
||||
)
|
||||
|> map { view -> (CallListNodeViewUpdate, EngineCallList.Scope) in
|
||||
return (CallListNodeViewUpdate(view: view, type: .ReloadAnimated, scrollPosition: nil), locationAndType.scope)
|
||||
}
|
||||
case let .navigation(index):
|
||||
var first = true
|
||||
return engine.messages.callList(
|
||||
scope: locationAndType.scope,
|
||||
index: index,
|
||||
itemCount: 120
|
||||
)
|
||||
|> map { view -> (CallListNodeViewUpdate, EngineCallList.Scope) in
|
||||
let genericType: CallListNodeViewUpdateType
|
||||
if first {
|
||||
first = false
|
||||
genericType = .UpdateVisible
|
||||
} else {
|
||||
genericType = .Generic
|
||||
}
|
||||
case let .changeType(index):
|
||||
return account.viewTracker.callListView(type: locationAndType.type, index: index, count: 120) |> map { view -> (CallListNodeViewUpdate, CallListViewType) in
|
||||
return (CallListNodeViewUpdate(view: view, type: .ReloadAnimated, scrollPosition: nil), locationAndType.type)
|
||||
}
|
||||
case let .navigation(index):
|
||||
var first = true
|
||||
return account.viewTracker.callListView(type: locationAndType.type, index: index, count: 120) |> map { view -> (CallListNodeViewUpdate, CallListViewType) in
|
||||
let genericType: CallListNodeViewUpdateType
|
||||
if first {
|
||||
first = false
|
||||
genericType = .UpdateVisible
|
||||
} else {
|
||||
genericType = .Generic
|
||||
}
|
||||
return (CallListNodeViewUpdate(view: view, type: genericType, scrollPosition: nil), locationAndType.type)
|
||||
}
|
||||
case let .scroll(index, sourceIndex, scrollPosition, animated):
|
||||
let directionHint: ListViewScrollToItemDirectionHint = sourceIndex > index ? .Down : .Up
|
||||
let callScrollPosition: CallListNodeViewScrollPosition = .index(index: index, position: scrollPosition, directionHint: directionHint, animated: animated)
|
||||
var first = true
|
||||
return account.viewTracker.callListView(type: locationAndType.type, index: index, count: 120) |> map { view -> (CallListNodeViewUpdate, CallListViewType) in
|
||||
let genericType: CallListNodeViewUpdateType
|
||||
let scrollPosition: CallListNodeViewScrollPosition? = first ? callScrollPosition : nil
|
||||
if first {
|
||||
first = false
|
||||
genericType = .UpdateVisible
|
||||
} else {
|
||||
genericType = .Generic
|
||||
}
|
||||
return (CallListNodeViewUpdate(view: view, type: genericType, scrollPosition: scrollPosition), locationAndType.type)
|
||||
return (CallListNodeViewUpdate(view: view, type: genericType, scrollPosition: nil), locationAndType.scope)
|
||||
}
|
||||
case let .scroll(index, sourceIndex, scrollPosition, animated):
|
||||
let directionHint: ListViewScrollToItemDirectionHint = sourceIndex > index ? .Down : .Up
|
||||
let callScrollPosition: CallListNodeViewScrollPosition = .index(index: index, position: scrollPosition, directionHint: directionHint, animated: animated)
|
||||
var first = true
|
||||
return engine.messages.callList(
|
||||
scope: locationAndType.scope,
|
||||
index: index,
|
||||
itemCount: 120
|
||||
)
|
||||
|> map { view -> (CallListNodeViewUpdate, EngineCallList.Scope) in
|
||||
let genericType: CallListNodeViewUpdateType
|
||||
let scrollPosition: CallListNodeViewScrollPosition? = first ? callScrollPosition : nil
|
||||
if first {
|
||||
first = false
|
||||
genericType = .UpdateVisible
|
||||
} else {
|
||||
genericType = .Generic
|
||||
}
|
||||
return (CallListNodeViewUpdate(view: view, type: genericType, scrollPosition: scrollPosition), locationAndType.scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import Display
|
||||
import MergeLists
|
||||
import ItemListUI
|
||||
import AccountContext
|
||||
|
||||
struct CallListNodeView {
|
||||
let originalView: CallListView
|
||||
let originalView: EngineCallList
|
||||
let filteredEntries: [CallListNodeEntry]
|
||||
let presentationData: ItemListPresentationData
|
||||
}
|
||||
|
|
@ -45,10 +45,10 @@ struct CallListNodeViewTransition {
|
|||
}
|
||||
|
||||
enum CallListNodeViewScrollPosition {
|
||||
case index(index: MessageIndex, position: ListViewScrollPosition, directionHint: ListViewScrollToItemDirectionHint, animated: Bool)
|
||||
case index(index: EngineMessage.Index, position: ListViewScrollPosition, directionHint: ListViewScrollToItemDirectionHint, animated: Bool)
|
||||
}
|
||||
|
||||
func preparedCallListNodeViewTransition(from fromView: CallListNodeView?, to toView: CallListNodeView, reason: CallListNodeViewTransitionReason, disableAnimations: Bool, account: Account, scrollPosition: CallListNodeViewScrollPosition?) -> Signal<CallListNodeViewTransition, NoError> {
|
||||
func preparedCallListNodeViewTransition(from fromView: CallListNodeView?, to toView: CallListNodeView, reason: CallListNodeViewTransitionReason, disableAnimations: Bool, context: AccountContext, scrollPosition: CallListNodeViewScrollPosition?) -> Signal<CallListNodeViewTransition, NoError> {
|
||||
return Signal { subscriber in
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromView?.filteredEntries ?? [], rightList: toView.filteredEntries, allUpdated: fromView?.presentationData != toView.presentationData)
|
||||
|
||||
|
|
@ -68,11 +68,11 @@ func preparedCallListNodeViewTransition(from fromView: CallListNodeView?, to toV
|
|||
|
||||
var options: ListViewDeleteAndInsertOptions = []
|
||||
var maxAnimatedInsertionIndex = -1
|
||||
var stationaryItemRange: (Int, Int)?
|
||||
var scrollToItem: ListViewScrollToItem?
|
||||
let stationaryItemRange: (Int, Int)? = nil
|
||||
var scrollToItem: ListViewScrollToItem? = nil
|
||||
|
||||
var wasEmpty = false
|
||||
if let fromView = fromView, fromView.originalView.entries.isEmpty {
|
||||
if let fromView = fromView, fromView.originalView.items.isEmpty {
|
||||
wasEmpty = true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
|
|
|||
|
|
@ -1,14 +1,4 @@
|
|||
import Foundation
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
|
||||
public enum ChatHistoryImportTasks {
|
||||
public final class Context {
|
||||
|
||||
}
|
||||
|
||||
public static func importState(peerId: PeerId) -> Signal<Float?, NoError> {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
|
|
|
|||
|
|
@ -6,11 +6,13 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/TextFormat:TextFormat",
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
|
|
|
|||
|
|
@ -1,80 +1,89 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TextFormat
|
||||
import AccountContext
|
||||
import SwiftSignalKit
|
||||
|
||||
public enum ChatTextInputMediaRecordingButtonMode: Int32 {
|
||||
case audio = 0
|
||||
case video = 1
|
||||
}
|
||||
|
||||
public struct ChatInterfaceSelectionState: PostboxCoding, Equatable {
|
||||
public let selectedIds: Set<MessageId>
|
||||
public struct ChatInterfaceSelectionState: Codable, Equatable {
|
||||
public let selectedIds: Set<EngineMessage.Id>
|
||||
|
||||
public static func ==(lhs: ChatInterfaceSelectionState, rhs: ChatInterfaceSelectionState) -> Bool {
|
||||
return lhs.selectedIds == rhs.selectedIds
|
||||
}
|
||||
|
||||
public init(selectedIds: Set<MessageId>) {
|
||||
public init(selectedIds: Set<EngineMessage.Id>) {
|
||||
self.selectedIds = selectedIds
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
if let data = decoder.decodeBytesForKeyNoCopy("i") {
|
||||
self.selectedIds = Set(MessageId.decodeArrayFromBuffer(data))
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
if let data = try? container.decodeIfPresent(Data.self, forKey: "i") {
|
||||
self.selectedIds = Set(EngineMessage.Id.decodeArrayFromData(data))
|
||||
} else {
|
||||
self.selectedIds = Set()
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
let buffer = WriteBuffer()
|
||||
MessageId.encodeArrayToBuffer(Array(selectedIds), buffer: buffer)
|
||||
encoder.encodeBytes(buffer, forKey: "i")
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
let data = EngineMessage.Id.encodeArrayToData(Array(selectedIds))
|
||||
|
||||
try container.encode(data, forKey: "i")
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatEditMessageState: PostboxCoding, Equatable {
|
||||
public let messageId: MessageId
|
||||
public struct ChatEditMessageState: Codable, Equatable {
|
||||
public let messageId: EngineMessage.Id
|
||||
public let inputState: ChatTextInputState
|
||||
public let disableUrlPreview: String?
|
||||
public let inputTextMaxLength: Int32?
|
||||
|
||||
public init(messageId: MessageId, inputState: ChatTextInputState, disableUrlPreview: String?, inputTextMaxLength: Int32?) {
|
||||
public init(messageId: EngineMessage.Id, inputState: ChatTextInputState, disableUrlPreview: String?, inputTextMaxLength: Int32?) {
|
||||
self.messageId = messageId
|
||||
self.inputState = inputState
|
||||
self.disableUrlPreview = disableUrlPreview
|
||||
self.inputTextMaxLength = inputTextMaxLength
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
self.messageId = EngineMessage.Id(
|
||||
peerId: EnginePeer.Id((try? container.decode(Int64.self, forKey: "mp")) ?? 0),
|
||||
namespace: (try? container.decode(Int32.self, forKey: "mn")) ?? 0,
|
||||
id: (try? container.decode(Int32.self, forKey: "mi")) ?? 0
|
||||
)
|
||||
|
||||
if let inputState = try? container.decode(ChatTextInputState.self, forKey: "is") {
|
||||
self.inputState = inputState
|
||||
} else {
|
||||
self.inputState = ChatTextInputState()
|
||||
}
|
||||
self.disableUrlPreview = decoder.decodeOptionalStringForKey("dup")
|
||||
self.inputTextMaxLength = decoder.decodeOptionalInt32ForKey("tl")
|
||||
|
||||
self.disableUrlPreview = try? container.decodeIfPresent(String.self, forKey: "dup")
|
||||
self.inputTextMaxLength = try? container.decodeIfPresent(Int32.self, forKey: "tl")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeInt64(self.messageId.peerId.toInt64(), forKey: "mp")
|
||||
encoder.encodeInt32(self.messageId.namespace, forKey: "mn")
|
||||
encoder.encodeInt32(self.messageId.id, forKey: "mi")
|
||||
encoder.encodeObject(self.inputState, forKey: "is")
|
||||
if let disableUrlPreview = self.disableUrlPreview {
|
||||
encoder.encodeString(disableUrlPreview, forKey: "dup")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "dup")
|
||||
}
|
||||
if let inputTextMaxLength = self.inputTextMaxLength {
|
||||
encoder.encodeInt32(inputTextMaxLength, forKey: "ml")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "ml")
|
||||
}
|
||||
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encode(self.messageId.peerId.toInt64(), forKey: "mp")
|
||||
try container.encode(self.messageId.namespace, forKey: "mn")
|
||||
try container.encode(self.messageId.id, forKey: "mi")
|
||||
|
||||
try container.encode(self.inputState, forKey: "is")
|
||||
|
||||
try container.encodeIfPresent(self.disableUrlPreview, forKey: "dup")
|
||||
try container.encodeIfPresent(self.inputTextMaxLength, forKey: "tl")
|
||||
}
|
||||
|
||||
public static func ==(lhs: ChatEditMessageState, rhs: ChatEditMessageState) -> Bool {
|
||||
|
|
@ -90,11 +99,11 @@ public struct ChatEditMessageState: PostboxCoding, Equatable {
|
|||
}
|
||||
}
|
||||
|
||||
public struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
||||
public var closedButtonKeyboardMessageId: MessageId?
|
||||
public var dismissedButtonKeyboardMessageId: MessageId?
|
||||
public var processedSetupReplyMessageId: MessageId?
|
||||
public var closedPinnedMessageId: MessageId?
|
||||
public struct ChatInterfaceMessageActionsState: Codable, Equatable {
|
||||
public var closedButtonKeyboardMessageId: EngineMessage.Id?
|
||||
public var dismissedButtonKeyboardMessageId: EngineMessage.Id?
|
||||
public var processedSetupReplyMessageId: EngineMessage.Id?
|
||||
public var closedPinnedMessageId: EngineMessage.Id?
|
||||
public var closedPeerSpecificPackSetup: Bool = false
|
||||
public var dismissedAddContactPhoneNumber: String?
|
||||
|
||||
|
|
@ -111,7 +120,7 @@ public struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
|||
self.dismissedAddContactPhoneNumber = nil
|
||||
}
|
||||
|
||||
public init(closedButtonKeyboardMessageId: MessageId?, dismissedButtonKeyboardMessageId: MessageId?, processedSetupReplyMessageId: MessageId?, closedPinnedMessageId: MessageId?, closedPeerSpecificPackSetup: Bool, dismissedAddContactPhoneNumber: String?) {
|
||||
public init(closedButtonKeyboardMessageId: EngineMessage.Id?, dismissedButtonKeyboardMessageId: EngineMessage.Id?, processedSetupReplyMessageId: EngineMessage.Id?, closedPinnedMessageId: EngineMessage.Id?, closedPeerSpecificPackSetup: Bool, dismissedAddContactPhoneNumber: String?) {
|
||||
self.closedButtonKeyboardMessageId = closedButtonKeyboardMessageId
|
||||
self.dismissedButtonKeyboardMessageId = dismissedButtonKeyboardMessageId
|
||||
self.processedSetupReplyMessageId = processedSetupReplyMessageId
|
||||
|
|
@ -120,105 +129,122 @@ public struct ChatInterfaceMessageActionsState: PostboxCoding, Equatable {
|
|||
self.dismissedAddContactPhoneNumber = dismissedAddContactPhoneNumber
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
if let closedMessageIdPeerId = decoder.decodeOptionalInt64ForKey("cb.p"), let closedMessageIdNamespace = decoder.decodeOptionalInt32ForKey("cb.n"), let closedMessageIdId = decoder.decodeOptionalInt32ForKey("cb.i") {
|
||||
self.closedButtonKeyboardMessageId = MessageId(peerId: PeerId(closedMessageIdPeerId), namespace: closedMessageIdNamespace, id: closedMessageIdId)
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
if let closedMessageIdPeerId = try? container.decodeIfPresent(Int64.self, forKey: "cb.p"), let closedMessageIdNamespace = try? container.decodeIfPresent(Int32.self, forKey: "cb.n"), let closedMessageIdId = try? container.decodeIfPresent(Int32.self, forKey: "cb.i") {
|
||||
self.closedButtonKeyboardMessageId = EngineMessage.Id(peerId: EnginePeer.Id(closedMessageIdPeerId), namespace: closedMessageIdNamespace, id: closedMessageIdId)
|
||||
} else {
|
||||
self.closedButtonKeyboardMessageId = nil
|
||||
}
|
||||
|
||||
if let messageIdPeerId = decoder.decodeOptionalInt64ForKey("dismissedbuttons.p"), let messageIdNamespace = decoder.decodeOptionalInt32ForKey("dismissedbuttons.n"), let messageIdId = decoder.decodeOptionalInt32ForKey("dismissedbuttons.i") {
|
||||
self.dismissedButtonKeyboardMessageId = MessageId(peerId: PeerId(messageIdPeerId), namespace: messageIdNamespace, id: messageIdId)
|
||||
if let messageIdPeerId = try? container.decodeIfPresent(Int64.self, forKey: "dismissedbuttons.p"), let messageIdNamespace = try? container.decodeIfPresent(Int32.self, forKey: "dismissedbuttons.n"), let messageIdId = try? container.decodeIfPresent(Int32.self, forKey: "dismissedbuttons.i") {
|
||||
self.dismissedButtonKeyboardMessageId = EngineMessage.Id(peerId: EnginePeer.Id(messageIdPeerId), namespace: messageIdNamespace, id: messageIdId)
|
||||
} else {
|
||||
self.dismissedButtonKeyboardMessageId = nil
|
||||
}
|
||||
|
||||
if let processedMessageIdPeerId = decoder.decodeOptionalInt64ForKey("pb.p"), let processedMessageIdNamespace = decoder.decodeOptionalInt32ForKey("pb.n"), let processedMessageIdId = decoder.decodeOptionalInt32ForKey("pb.i") {
|
||||
self.processedSetupReplyMessageId = MessageId(peerId: PeerId(processedMessageIdPeerId), namespace: processedMessageIdNamespace, id: processedMessageIdId)
|
||||
if let processedMessageIdPeerId = try? container.decodeIfPresent(Int64.self, forKey: "pb.p"), let processedMessageIdNamespace = try? container.decodeIfPresent(Int32.self, forKey: "pb.n"), let processedMessageIdId = try? container.decodeIfPresent(Int32.self, forKey: "pb.i") {
|
||||
self.processedSetupReplyMessageId = EngineMessage.Id(peerId: EnginePeer.Id(processedMessageIdPeerId), namespace: processedMessageIdNamespace, id: processedMessageIdId)
|
||||
} else {
|
||||
self.processedSetupReplyMessageId = nil
|
||||
}
|
||||
|
||||
if let closedPinnedMessageIdPeerId = decoder.decodeOptionalInt64ForKey("cp.p"), let closedPinnedMessageIdNamespace = decoder.decodeOptionalInt32ForKey("cp.n"), let closedPinnedMessageIdId = decoder.decodeOptionalInt32ForKey("cp.i") {
|
||||
self.closedPinnedMessageId = MessageId(peerId: PeerId(closedPinnedMessageIdPeerId), namespace: closedPinnedMessageIdNamespace, id: closedPinnedMessageIdId)
|
||||
if let closedPinnedMessageIdPeerId = try? container.decodeIfPresent(Int64.self, forKey: "cp.p"), let closedPinnedMessageIdNamespace = try? container.decodeIfPresent(Int32.self, forKey: "cp.n"), let closedPinnedMessageIdId = try? container.decodeIfPresent(Int32.self, forKey: "cp.i") {
|
||||
self.closedPinnedMessageId = EngineMessage.Id(peerId: EnginePeer.Id(closedPinnedMessageIdPeerId), namespace: closedPinnedMessageIdNamespace, id: closedPinnedMessageIdId)
|
||||
} else {
|
||||
self.closedPinnedMessageId = nil
|
||||
}
|
||||
|
||||
self.closedPeerSpecificPackSetup = decoder.decodeInt32ForKey("cpss", orElse: 0) != 0
|
||||
self.closedPeerSpecificPackSetup = ((try? container.decode(Int32.self, forKey: "cpss")) ?? 0) != 0
|
||||
|
||||
self.dismissedAddContactPhoneNumber = try? container.decodeIfPresent(String.self, forKey: "dismissedAddContactPhoneNumber")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
if let closedButtonKeyboardMessageId = self.closedButtonKeyboardMessageId {
|
||||
encoder.encodeInt64(closedButtonKeyboardMessageId.peerId.toInt64(), forKey: "cb.p")
|
||||
encoder.encodeInt32(closedButtonKeyboardMessageId.namespace, forKey: "cb.n")
|
||||
encoder.encodeInt32(closedButtonKeyboardMessageId.id, forKey: "cb.i")
|
||||
try container.encode(closedButtonKeyboardMessageId.peerId.toInt64(), forKey: "cb.p")
|
||||
try container.encode(closedButtonKeyboardMessageId.namespace, forKey: "cb.n")
|
||||
try container.encode(closedButtonKeyboardMessageId.id, forKey: "cb.i")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "cb.p")
|
||||
encoder.encodeNil(forKey: "cb.n")
|
||||
encoder.encodeNil(forKey: "cb.i")
|
||||
try container.encodeNil(forKey: "cb.p")
|
||||
try container.encodeNil(forKey: "cb.n")
|
||||
try container.encodeNil(forKey: "cb.i")
|
||||
}
|
||||
|
||||
if let dismissedButtonKeyboardMessageId = self.dismissedButtonKeyboardMessageId {
|
||||
encoder.encodeInt64(dismissedButtonKeyboardMessageId.peerId.toInt64(), forKey: "dismissedbuttons.p")
|
||||
encoder.encodeInt32(dismissedButtonKeyboardMessageId.namespace, forKey: "dismissedbuttons.n")
|
||||
encoder.encodeInt32(dismissedButtonKeyboardMessageId.id, forKey: "dismissedbuttons.i")
|
||||
try container.encode(dismissedButtonKeyboardMessageId.peerId.toInt64(), forKey: "dismissedbuttons.p")
|
||||
try container.encode(dismissedButtonKeyboardMessageId.namespace, forKey: "dismissedbuttons.n")
|
||||
try container.encode(dismissedButtonKeyboardMessageId.id, forKey: "dismissedbuttons.i")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "dismissedbuttons.p")
|
||||
encoder.encodeNil(forKey: "dismissedbuttons.n")
|
||||
encoder.encodeNil(forKey: "dismissedbuttons.i")
|
||||
try container.encodeNil(forKey: "dismissedbuttons.p")
|
||||
try container.encodeNil(forKey: "dismissedbuttons.n")
|
||||
try container.encodeNil(forKey: "dismissedbuttons.i")
|
||||
}
|
||||
|
||||
if let processedSetupReplyMessageId = self.processedSetupReplyMessageId {
|
||||
encoder.encodeInt64(processedSetupReplyMessageId.peerId.toInt64(), forKey: "pb.p")
|
||||
encoder.encodeInt32(processedSetupReplyMessageId.namespace, forKey: "pb.n")
|
||||
encoder.encodeInt32(processedSetupReplyMessageId.id, forKey: "pb.i")
|
||||
try container.encode(processedSetupReplyMessageId.peerId.toInt64(), forKey: "pb.p")
|
||||
try container.encode(processedSetupReplyMessageId.namespace, forKey: "pb.n")
|
||||
try container.encode(processedSetupReplyMessageId.id, forKey: "pb.i")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "pb.p")
|
||||
encoder.encodeNil(forKey: "pb.n")
|
||||
encoder.encodeNil(forKey: "pb.i")
|
||||
try container.encodeNil(forKey: "pb.p")
|
||||
try container.encodeNil(forKey: "pb.n")
|
||||
try container.encodeNil(forKey: "pb.i")
|
||||
}
|
||||
|
||||
if let closedPinnedMessageId = self.closedPinnedMessageId {
|
||||
encoder.encodeInt64(closedPinnedMessageId.peerId.toInt64(), forKey: "cp.p")
|
||||
encoder.encodeInt32(closedPinnedMessageId.namespace, forKey: "cp.n")
|
||||
encoder.encodeInt32(closedPinnedMessageId.id, forKey: "cp.i")
|
||||
try container.encode(closedPinnedMessageId.peerId.toInt64(), forKey: "cp.p")
|
||||
try container.encode(closedPinnedMessageId.namespace, forKey: "cp.n")
|
||||
try container.encode(closedPinnedMessageId.id, forKey: "cp.i")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "cp.p")
|
||||
encoder.encodeNil(forKey: "cp.n")
|
||||
encoder.encodeNil(forKey: "cp.i")
|
||||
try container.encodeNil(forKey: "cp.p")
|
||||
try container.encodeNil(forKey: "cp.n")
|
||||
try container.encodeNil(forKey: "cp.i")
|
||||
}
|
||||
|
||||
encoder.encodeInt32(self.closedPeerSpecificPackSetup ? 1 : 0, forKey: "cpss")
|
||||
try container.encode((self.closedPeerSpecificPackSetup ? 1 : 0) as Int32, forKey: "cpss")
|
||||
|
||||
if let dismissedAddContactPhoneNumber = self.dismissedAddContactPhoneNumber {
|
||||
encoder.encodeString(dismissedAddContactPhoneNumber, forKey: "dismissedAddContactPhoneNumber")
|
||||
try container.encode(dismissedAddContactPhoneNumber, forKey: "dismissedAddContactPhoneNumber")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "dismissedAddContactPhoneNumber")
|
||||
try container.encodeNil(forKey: "dismissedAddContactPhoneNumber")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatInterfaceHistoryScrollState: PostboxCoding, Equatable {
|
||||
public let messageIndex: MessageIndex
|
||||
public struct ChatInterfaceHistoryScrollState: Codable, Equatable {
|
||||
public let messageIndex: EngineMessage.Index
|
||||
public let relativeOffset: Double
|
||||
|
||||
public init(messageIndex: MessageIndex, relativeOffset: Double) {
|
||||
public init(messageIndex: EngineMessage.Index, relativeOffset: Double) {
|
||||
self.messageIndex = messageIndex
|
||||
self.relativeOffset = relativeOffset
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.messageIndex = MessageIndex(id: MessageId(peerId: PeerId(decoder.decodeInt64ForKey("m.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("m.n", orElse: 0), id: decoder.decodeInt32ForKey("m.i", orElse: 0)), timestamp: decoder.decodeInt32ForKey("m.t", orElse: 0))
|
||||
self.relativeOffset = decoder.decodeDoubleForKey("ro", orElse: 0.0)
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
self.messageIndex = EngineMessage.Index(
|
||||
id: EngineMessage.Id(
|
||||
peerId: EnginePeer.Id((try? container.decode(Int64.self, forKey: "m.p")) ?? 0),
|
||||
namespace: (try? container.decode(Int32.self, forKey: "m.n")) ?? 0,
|
||||
id: (try? container.decode(Int32.self, forKey: "m.i")) ?? 0
|
||||
),
|
||||
timestamp: (try? container.decode(Int32.self, forKey: "m.t")) ?? 0
|
||||
)
|
||||
self.relativeOffset = (try? container.decode(Double.self, forKey: "ro")) ?? 0.0
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeInt32(self.messageIndex.timestamp, forKey: "m.t")
|
||||
encoder.encodeInt64(self.messageIndex.id.peerId.toInt64(), forKey: "m.p")
|
||||
encoder.encodeInt32(self.messageIndex.id.namespace, forKey: "m.n")
|
||||
encoder.encodeInt32(self.messageIndex.id.id, forKey: "m.i")
|
||||
encoder.encodeDouble(self.relativeOffset, forKey: "ro")
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encode(self.messageIndex.timestamp, forKey: "m.t")
|
||||
try container.encode(self.messageIndex.id.peerId.toInt64(), forKey: "m.p")
|
||||
try container.encode(self.messageIndex.id.namespace, forKey: "m.n")
|
||||
try container.encode(self.messageIndex.id.id, forKey: "m.i")
|
||||
try container.encode(self.relativeOffset, forKey: "ro")
|
||||
}
|
||||
|
||||
public static func ==(lhs: ChatInterfaceHistoryScrollState, rhs: ChatInterfaceHistoryScrollState) -> Bool {
|
||||
|
|
@ -232,12 +258,12 @@ public struct ChatInterfaceHistoryScrollState: PostboxCoding, Equatable {
|
|||
}
|
||||
}
|
||||
|
||||
public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equatable {
|
||||
public final class ChatInterfaceState: Codable, Equatable {
|
||||
public let timestamp: Int32
|
||||
public let composeInputState: ChatTextInputState
|
||||
public let composeDisableUrlPreview: String?
|
||||
public let replyMessageId: MessageId?
|
||||
public let forwardMessageIds: [MessageId]?
|
||||
public let replyMessageId: EngineMessage.Id?
|
||||
public let forwardMessageIds: [EngineMessage.Id]?
|
||||
public let editMessage: ChatEditMessageState?
|
||||
public let selectionState: ChatInterfaceSelectionState?
|
||||
public let messageActionsState: ChatInterfaceMessageActionsState
|
||||
|
|
@ -246,35 +272,15 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
|||
public let silentPosting: Bool
|
||||
public let inputLanguage: String?
|
||||
|
||||
public var associatedMessageIds: [MessageId] {
|
||||
var ids: [MessageId] = []
|
||||
if let editMessage = self.editMessage {
|
||||
ids.append(editMessage.messageId)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
public var chatListEmbeddedState: PeerChatListEmbeddedInterfaceState? {
|
||||
if self.composeInputState.inputText.length != 0 && self.timestamp != 0 {
|
||||
return ChatEmbeddedInterfaceState(timestamp: self.timestamp, text: self.composeInputState.inputText)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public var synchronizeableInputState: SynchronizeableChatInputState? {
|
||||
if self.composeInputState.inputText.length == 0 {
|
||||
return nil
|
||||
} else {
|
||||
return SynchronizeableChatInputState(replyToMessageId: self.replyMessageId, text: self.composeInputState.inputText.string, entities: generateChatInputTextEntities(self.composeInputState.inputText), timestamp: self.timestamp)
|
||||
return SynchronizeableChatInputState(replyToMessageId: self.replyMessageId, text: self.composeInputState.inputText.string, entities: generateChatInputTextEntities(self.composeInputState.inputText), timestamp: self.timestamp, textSelection: self.composeInputState.selectionRange)
|
||||
}
|
||||
}
|
||||
|
||||
public var historyScrollMessageIndex: MessageIndex? {
|
||||
return self.historyScrollState?.messageIndex
|
||||
}
|
||||
|
||||
public func withUpdatedSynchronizeableInputState(_ state: SynchronizeableChatInputState?) -> SynchronizeableChatInterfaceState {
|
||||
|
||||
public func withUpdatedSynchronizeableInputState(_ state: SynchronizeableChatInputState?) -> ChatInterfaceState {
|
||||
var result = self.withUpdatedComposeInputState(ChatTextInputState(inputText: chatInputStateStringWithAppliedEntities(state?.text ?? "", entities: state?.entities ?? []))).withUpdatedReplyMessageId(state?.replyToMessageId)
|
||||
if let timestamp = state?.timestamp {
|
||||
result = result.withUpdatedTimestamp(timestamp)
|
||||
|
|
@ -282,6 +288,10 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
|||
return result
|
||||
}
|
||||
|
||||
public var historyScrollMessageIndex: EngineMessage.Index? {
|
||||
return self.historyScrollState?.messageIndex
|
||||
}
|
||||
|
||||
public var effectiveInputState: ChatTextInputState {
|
||||
if let editMessage = self.editMessage {
|
||||
return editMessage.inputState
|
||||
|
|
@ -305,7 +315,7 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
|||
self.inputLanguage = nil
|
||||
}
|
||||
|
||||
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?) {
|
||||
public init(timestamp: Int32, composeInputState: ChatTextInputState, composeDisableUrlPreview: String?, replyMessageId: EngineMessage.Id?, forwardMessageIds: [EngineMessage.Id]?, editMessage: ChatEditMessageState?, selectionState: ChatInterfaceSelectionState?, messageActionsState: ChatInterfaceMessageActionsState, historyScrollState: ChatInterfaceHistoryScrollState?, mediaRecordingMode: ChatTextInputMediaRecordingButtonMode, silentPosting: Bool, inputLanguage: String?) {
|
||||
self.timestamp = timestamp
|
||||
self.composeInputState = composeInputState
|
||||
self.composeDisableUrlPreview = composeDisableUrlPreview
|
||||
|
|
@ -320,114 +330,108 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
|||
self.inputLanguage = inputLanguage
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.timestamp = decoder.decodeInt32ForKey("ts", orElse: 0)
|
||||
if let inputState = decoder.decodeObjectForKey("is", decoder: { return ChatTextInputState(decoder: $0) }) as? ChatTextInputState {
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
self.timestamp = (try? container.decode(Int32.self, forKey: "ts")) ?? 0
|
||||
if let inputState = try? container.decode(ChatTextInputState.self, forKey: "is") {
|
||||
self.composeInputState = inputState
|
||||
} else {
|
||||
self.composeInputState = ChatTextInputState()
|
||||
}
|
||||
if let composeDisableUrlPreview = decoder.decodeOptionalStringForKey("dup") {
|
||||
if let composeDisableUrlPreview = try? container.decodeIfPresent(String.self, forKey: "dup") {
|
||||
self.composeDisableUrlPreview = composeDisableUrlPreview
|
||||
} else {
|
||||
self.composeDisableUrlPreview = nil
|
||||
}
|
||||
let replyMessageIdPeerId: Int64? = decoder.decodeOptionalInt64ForKey("r.p")
|
||||
let replyMessageIdNamespace: Int32? = decoder.decodeOptionalInt32ForKey("r.n")
|
||||
let replyMessageIdId: Int32? = decoder.decodeOptionalInt32ForKey("r.i")
|
||||
let replyMessageIdPeerId: Int64? = try? container.decodeIfPresent(Int64.self, forKey: "r.p")
|
||||
let replyMessageIdNamespace: Int32? = try? container.decodeIfPresent(Int32.self, forKey: "r.n")
|
||||
let replyMessageIdId: Int32? = try? container.decodeIfPresent(Int32.self, forKey: "r.i")
|
||||
if let replyMessageIdPeerId = replyMessageIdPeerId, let replyMessageIdNamespace = replyMessageIdNamespace, let replyMessageIdId = replyMessageIdId {
|
||||
self.replyMessageId = MessageId(peerId: PeerId(replyMessageIdPeerId), namespace: replyMessageIdNamespace, id: replyMessageIdId)
|
||||
self.replyMessageId = EngineMessage.Id(peerId: EnginePeer.Id(replyMessageIdPeerId), namespace: replyMessageIdNamespace, id: replyMessageIdId)
|
||||
} else {
|
||||
self.replyMessageId = nil
|
||||
}
|
||||
if let forwardMessageIdsData = decoder.decodeBytesForKeyNoCopy("fm") {
|
||||
self.forwardMessageIds = MessageId.decodeArrayFromBuffer(forwardMessageIdsData)
|
||||
if let forwardMessageIdsData = try? container.decodeIfPresent(Data.self, forKey: "fm") {
|
||||
self.forwardMessageIds = EngineMessage.Id.decodeArrayFromData(forwardMessageIdsData)
|
||||
} else {
|
||||
self.forwardMessageIds = nil
|
||||
}
|
||||
if let editMessage = decoder.decodeObjectForKey("em", decoder: { ChatEditMessageState(decoder: $0) }) as? ChatEditMessageState {
|
||||
if let editMessage = try? container.decodeIfPresent(ChatEditMessageState.self, forKey: "em") {
|
||||
self.editMessage = editMessage
|
||||
} else {
|
||||
self.editMessage = nil
|
||||
}
|
||||
if let selectionState = decoder.decodeObjectForKey("ss", decoder: { return ChatInterfaceSelectionState(decoder: $0) }) as? ChatInterfaceSelectionState {
|
||||
if let selectionState = try? container.decodeIfPresent(ChatInterfaceSelectionState.self, forKey: "ss") {
|
||||
self.selectionState = selectionState
|
||||
} else {
|
||||
self.selectionState = nil
|
||||
}
|
||||
|
||||
if let messageActionsState = decoder.decodeObjectForKey("as", decoder: { ChatInterfaceMessageActionsState(decoder: $0) }) as? ChatInterfaceMessageActionsState {
|
||||
|
||||
if let messageActionsState = try? container.decodeIfPresent(ChatInterfaceMessageActionsState.self, forKey: "as") {
|
||||
self.messageActionsState = messageActionsState
|
||||
} else {
|
||||
self.messageActionsState = ChatInterfaceMessageActionsState()
|
||||
}
|
||||
|
||||
self.historyScrollState = try? container.decodeIfPresent(ChatInterfaceHistoryScrollState.self, forKey: "hss")
|
||||
|
||||
self.historyScrollState = decoder.decodeObjectForKey("hss", decoder: { ChatInterfaceHistoryScrollState(decoder: $0) }) as? ChatInterfaceHistoryScrollState
|
||||
self.mediaRecordingMode = ChatTextInputMediaRecordingButtonMode(rawValue: (try? container.decodeIfPresent(Int32.self, forKey: "mrm")) ?? 0) ?? .audio
|
||||
|
||||
self.mediaRecordingMode = ChatTextInputMediaRecordingButtonMode(rawValue: decoder.decodeInt32ForKey("mrm", orElse: 0))!
|
||||
|
||||
self.silentPosting = decoder.decodeInt32ForKey("sip", orElse: 0) != 0
|
||||
self.inputLanguage = decoder.decodeOptionalStringForKey("inputLanguage")
|
||||
self.silentPosting = ((try? container.decode(Int32.self, forKey: "sip")) ?? 0) != 0
|
||||
self.inputLanguage = try? container.decodeIfPresent(String.self, forKey: "inputLanguage")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeInt32(self.timestamp, forKey: "ts")
|
||||
encoder.encodeObject(self.composeInputState, forKey: "is")
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encode(self.timestamp, forKey: "ts")
|
||||
try container.encode(self.composeInputState, forKey: "is")
|
||||
if let composeDisableUrlPreview = self.composeDisableUrlPreview {
|
||||
encoder.encodeString(composeDisableUrlPreview, forKey: "dup")
|
||||
try container.encode(composeDisableUrlPreview, forKey: "dup")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "dup")
|
||||
try container.encodeNil(forKey: "dup")
|
||||
}
|
||||
if let replyMessageId = self.replyMessageId {
|
||||
encoder.encodeInt64(replyMessageId.peerId.toInt64(), forKey: "r.p")
|
||||
encoder.encodeInt32(replyMessageId.namespace, forKey: "r.n")
|
||||
encoder.encodeInt32(replyMessageId.id, forKey: "r.i")
|
||||
try container.encode(replyMessageId.peerId.toInt64(), forKey: "r.p")
|
||||
try container.encode(replyMessageId.namespace, forKey: "r.n")
|
||||
try container.encode(replyMessageId.id, forKey: "r.i")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "r.p")
|
||||
encoder.encodeNil(forKey: "r.n")
|
||||
encoder.encodeNil(forKey: "r.i")
|
||||
try container.encodeNil(forKey: "r.p")
|
||||
try container.encodeNil(forKey: "r.n")
|
||||
try container.encodeNil(forKey: "r.i")
|
||||
}
|
||||
if let forwardMessageIds = self.forwardMessageIds {
|
||||
let buffer = WriteBuffer()
|
||||
MessageId.encodeArrayToBuffer(forwardMessageIds, buffer: buffer)
|
||||
encoder.encodeBytes(buffer, forKey: "fm")
|
||||
try container.encode(EngineMessage.Id.encodeArrayToData(forwardMessageIds), forKey: "fm")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "fm")
|
||||
try container.encodeNil(forKey: "fm")
|
||||
}
|
||||
if let editMessage = self.editMessage {
|
||||
encoder.encodeObject(editMessage, forKey: "em")
|
||||
try container.encode(editMessage, forKey: "em")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "em")
|
||||
try container.encodeNil(forKey: "em")
|
||||
}
|
||||
if let selectionState = self.selectionState {
|
||||
encoder.encodeObject(selectionState, forKey: "ss")
|
||||
try container.encode(selectionState, forKey: "ss")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "ss")
|
||||
try container.encodeNil(forKey: "ss")
|
||||
}
|
||||
if self.messageActionsState.isEmpty {
|
||||
encoder.encodeNil(forKey: "as")
|
||||
try container.encodeNil(forKey: "as")
|
||||
} else {
|
||||
encoder.encodeObject(self.messageActionsState, forKey: "as")
|
||||
try container.encode(self.messageActionsState, forKey: "as")
|
||||
}
|
||||
if let historyScrollState = self.historyScrollState {
|
||||
encoder.encodeObject(historyScrollState, forKey: "hss")
|
||||
try container.encode(historyScrollState, forKey: "hss")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "hss")
|
||||
try container.encodeNil(forKey: "hss")
|
||||
}
|
||||
encoder.encodeInt32(self.mediaRecordingMode.rawValue, forKey: "mrm")
|
||||
encoder.encodeInt32(self.silentPosting ? 1 : 0, forKey: "sip")
|
||||
try container.encode(self.mediaRecordingMode.rawValue, forKey: "mrm")
|
||||
try container.encode((self.silentPosting ? 1 : 0) as Int32, forKey: "sip")
|
||||
if let inputLanguage = self.inputLanguage {
|
||||
encoder.encodeString(inputLanguage, forKey: "inputLanguage")
|
||||
try container.encode(inputLanguage, forKey: "inputLanguage")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "inputLanguage")
|
||||
}
|
||||
}
|
||||
|
||||
public func isEqual(to: PeerChatInterfaceState) -> Bool {
|
||||
if let to = to as? ChatInterfaceState, self == to {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
try container.encodeNil(forKey: "inputLanguage")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -482,16 +486,16 @@ 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)
|
||||
}
|
||||
|
||||
public func withUpdatedReplyMessageId(_ replyMessageId: MessageId?) -> ChatInterfaceState {
|
||||
public func withUpdatedReplyMessageId(_ replyMessageId: EngineMessage.Id?) -> 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)
|
||||
}
|
||||
|
||||
public func withUpdatedForwardMessageIds(_ forwardMessageIds: [MessageId]?) -> ChatInterfaceState {
|
||||
public func withUpdatedForwardMessageIds(_ forwardMessageIds: [EngineMessage.Id]?) -> 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)
|
||||
}
|
||||
|
||||
public func withUpdatedSelectedMessages(_ messageIds: [MessageId]) -> ChatInterfaceState {
|
||||
var selectedIds = Set<MessageId>()
|
||||
public func withUpdatedSelectedMessages(_ messageIds: [EngineMessage.Id]) -> ChatInterfaceState {
|
||||
var selectedIds = Set<EngineMessage.Id>()
|
||||
if let selectionState = self.selectionState {
|
||||
selectedIds.formUnion(selectionState.selectedIds)
|
||||
}
|
||||
|
|
@ -501,8 +505,8 @@ 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)
|
||||
}
|
||||
|
||||
public func withToggledSelectedMessages(_ messageIds: [MessageId], value: Bool) -> ChatInterfaceState {
|
||||
var selectedIds = Set<MessageId>()
|
||||
public func withToggledSelectedMessages(_ messageIds: [EngineMessage.Id], value: Bool) -> ChatInterfaceState {
|
||||
var selectedIds = Set<EngineMessage.Id>()
|
||||
if let selectionState = self.selectionState {
|
||||
selectedIds.formUnion(selectionState.selectedIds)
|
||||
}
|
||||
|
|
@ -547,4 +551,34 @@ public final class ChatInterfaceState: SynchronizeableChatInterfaceState, Equata
|
|||
public func withUpdatedInputLanguage(_ inputLanguage: String?) -> ChatInterfaceState {
|
||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreview: self.composeDisableUrlPreview, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, silentPosting: self.silentPosting, inputLanguage: inputLanguage)
|
||||
}
|
||||
|
||||
public static func parse(_ state: OpaqueChatInterfaceState) -> ChatInterfaceState {
|
||||
guard let opaqueData = state.opaqueData else {
|
||||
return ChatInterfaceState().withUpdatedSynchronizeableInputState(state.synchronizeableInputState)
|
||||
}
|
||||
guard var decodedState = try? EngineDecoder.decode(ChatInterfaceState.self, from: opaqueData) else {
|
||||
return ChatInterfaceState().withUpdatedSynchronizeableInputState(state.synchronizeableInputState)
|
||||
}
|
||||
decodedState = decodedState.withUpdatedSynchronizeableInputState(state.synchronizeableInputState)
|
||||
return decodedState
|
||||
}
|
||||
|
||||
public static func update(engine: TelegramEngine, peerId: EnginePeer.Id, threadId: Int64?, _ f: @escaping (ChatInterfaceState) -> ChatInterfaceState) -> Signal<Never, NoError> {
|
||||
return engine.peers.getOpaqueChatInterfaceState(peerId: peerId, threadId: threadId)
|
||||
|> mapToSignal { previousOpaqueState -> Signal<Never, NoError> in
|
||||
let previousState = previousOpaqueState.flatMap(ChatInterfaceState.parse)
|
||||
let updatedState = f(previousState ?? ChatInterfaceState())
|
||||
|
||||
let updatedOpaqueData = try? EngineEncoder.encode(updatedState)
|
||||
|
||||
return engine.peers.setOpaqueChatInterfaceState(
|
||||
peerId: peerId,
|
||||
threadId: threadId,
|
||||
state: OpaqueChatInterfaceState(
|
||||
opaqueData: updatedOpaqueData,
|
||||
historyScrollMessageIndex: updatedState.historyScrollMessageIndex,
|
||||
synchronizeableInputState: updatedState.synchronizeableInputState
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
|
|
|
|||
|
|
@ -6,11 +6,13 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
"//submodules/SearchBarNode:SearchBarNode",
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
|
|
|
|||
|
|
@ -6,11 +6,13 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/ListSectionHeaderNode:ListSectionHeaderNode",
|
||||
"//submodules/HorizontalPeerItem:HorizontalPeerItem",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import UIKit
|
|||
import AsyncDisplayKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import MergeLists
|
||||
|
|
@ -32,13 +31,13 @@ private func calculateItemCustomWidth(width: CGFloat) -> CGFloat {
|
|||
|
||||
private struct ChatListSearchRecentPeersEntry: Comparable, Identifiable {
|
||||
let index: Int
|
||||
let peer: Peer
|
||||
let presence: PeerPresence?
|
||||
let peer: EnginePeer
|
||||
let presence: EnginePeer.Presence?
|
||||
let unreadBadge: (Int32, Bool)?
|
||||
let theme: PresentationTheme
|
||||
let strings: PresentationStrings
|
||||
let itemCustomWidth: CGFloat?
|
||||
var stableId: PeerId {
|
||||
var stableId: EnginePeer.Id {
|
||||
return self.peer.id
|
||||
}
|
||||
|
||||
|
|
@ -49,14 +48,10 @@ private struct ChatListSearchRecentPeersEntry: Comparable, Identifiable {
|
|||
if lhs.itemCustomWidth != rhs.itemCustomWidth {
|
||||
return false
|
||||
}
|
||||
if !lhs.peer.isEqual(rhs.peer) {
|
||||
if lhs.peer != rhs.peer {
|
||||
return false
|
||||
}
|
||||
if let lhsPresence = lhs.presence, let rhsPresence = rhs.presence {
|
||||
if !lhsPresence.isEqual(to: rhsPresence) {
|
||||
return false
|
||||
}
|
||||
} else if (lhs.presence != nil) != (rhs.presence != nil) {
|
||||
if lhs.presence != rhs.presence {
|
||||
return false
|
||||
}
|
||||
if lhs.unreadBadge?.0 != rhs.unreadBadge?.0 {
|
||||
|
|
@ -78,7 +73,7 @@ private struct ChatListSearchRecentPeersEntry: Comparable, Identifiable {
|
|||
return lhs.index < rhs.index
|
||||
}
|
||||
|
||||
func item(context: AccountContext, mode: HorizontalPeerItemMode, peerSelected: @escaping (Peer) -> Void, peerContextAction: @escaping (Peer, ASDisplayNode, ContextGesture?) -> Void, isPeerSelected: @escaping (PeerId) -> Bool) -> ListViewItem {
|
||||
func item(context: AccountContext, mode: HorizontalPeerItemMode, peerSelected: @escaping (EnginePeer) -> Void, peerContextAction: @escaping (EnginePeer, ASDisplayNode, ContextGesture?) -> Void, isPeerSelected: @escaping (EnginePeer.Id) -> Bool) -> ListViewItem {
|
||||
return HorizontalPeerItem(theme: self.theme, strings: self.strings, mode: mode, context: context, peer: self.peer, presence: self.presence, unreadBadge: self.unreadBadge, action: peerSelected, contextAction: { peer, node, gesture in
|
||||
peerContextAction(peer, node, gesture)
|
||||
}, isPeerSelected: isPeerSelected, customWidth: self.itemCustomWidth)
|
||||
|
|
@ -93,7 +88,7 @@ private struct ChatListSearchRecentNodeTransition {
|
|||
let animated: Bool
|
||||
}
|
||||
|
||||
private func preparedRecentPeersTransition(context: AccountContext, mode: HorizontalPeerItemMode, peerSelected: @escaping (Peer) -> Void, peerContextAction: @escaping (Peer, ASDisplayNode, ContextGesture?) -> Void, isPeerSelected: @escaping (PeerId) -> Bool, share: Bool = false, from fromEntries: [ChatListSearchRecentPeersEntry], to toEntries: [ChatListSearchRecentPeersEntry], firstTime: Bool, animated: Bool) -> ChatListSearchRecentNodeTransition {
|
||||
private func preparedRecentPeersTransition(context: AccountContext, mode: HorizontalPeerItemMode, peerSelected: @escaping (EnginePeer) -> Void, peerContextAction: @escaping (EnginePeer, ASDisplayNode, ContextGesture?) -> Void, isPeerSelected: @escaping (EnginePeer.Id) -> Bool, share: Bool = false, from fromEntries: [ChatListSearchRecentPeersEntry], to toEntries: [ChatListSearchRecentPeersEntry], firstTime: Bool, animated: Bool) -> ChatListSearchRecentNodeTransition {
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||
|
||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||
|
|
@ -111,9 +106,9 @@ public final class ChatListSearchRecentPeersNode: ASDisplayNode {
|
|||
private let listView: ListView
|
||||
private let share: Bool
|
||||
|
||||
private let peerSelected: (Peer) -> Void
|
||||
private let peerContextAction: (Peer, ASDisplayNode, ContextGesture?) -> Void
|
||||
private let isPeerSelected: (PeerId) -> Bool
|
||||
private let peerSelected: (EnginePeer) -> Void
|
||||
private let peerContextAction: (EnginePeer, ASDisplayNode, ContextGesture?) -> Void
|
||||
private let isPeerSelected: (EnginePeer.Id) -> Bool
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
private let itemCustomWidthValuePromise: ValuePromise<CGFloat?> = ValuePromise(nil, ignoreRepeated: true)
|
||||
|
|
@ -127,7 +122,7 @@ public final class ChatListSearchRecentPeersNode: ASDisplayNode {
|
|||
return self.ready.get()
|
||||
}
|
||||
|
||||
public init(context: AccountContext, theme: PresentationTheme, mode: HorizontalPeerItemMode, strings: PresentationStrings, peerSelected: @escaping (Peer) -> Void, peerContextAction: @escaping (Peer, ASDisplayNode, ContextGesture?) -> Void, isPeerSelected: @escaping (PeerId) -> Bool, share: Bool = false) {
|
||||
public init(context: AccountContext, theme: PresentationTheme, mode: HorizontalPeerItemMode, strings: PresentationStrings, peerSelected: @escaping (EnginePeer) -> Void, peerContextAction: @escaping (EnginePeer, ASDisplayNode, ContextGesture?) -> Void, isPeerSelected: @escaping (EnginePeer.Id) -> Bool, share: Bool = false) {
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
self.themeAndStringsPromise = Promise((self.theme, self.strings))
|
||||
|
|
@ -149,7 +144,7 @@ public final class ChatListSearchRecentPeersNode: ASDisplayNode {
|
|||
|
||||
let peersDisposable = DisposableSet()
|
||||
|
||||
let recent: Signal<([Peer], [PeerId: (Int32, Bool)], [PeerId : PeerPresence]), NoError> = context.engine.peers.recentPeers()
|
||||
let recent: Signal<([EnginePeer], [EnginePeer.Id: (Int32, Bool)], [EnginePeer.Id : EnginePeer.Presence]), NoError> = context.engine.peers.recentPeers()
|
||||
|> filter { value -> Bool in
|
||||
switch value {
|
||||
case .disabled:
|
||||
|
|
@ -163,14 +158,21 @@ public final class ChatListSearchRecentPeersNode: ASDisplayNode {
|
|||
case .disabled:
|
||||
return .single(([], [:], [:]))
|
||||
case let .peers(peers):
|
||||
return combineLatest(queue: .mainQueue(), peers.filter { !$0.isDeleted }.map {context.account.postbox.peerView(id: $0.id)}) |> mapToSignal { peerViews -> Signal<([Peer], [PeerId: (Int32, Bool)], [PeerId: PeerPresence]), NoError> in
|
||||
return combineLatest(queue: .mainQueue(),
|
||||
peers.filter {
|
||||
!$0.isDeleted
|
||||
}.map {
|
||||
context.account.postbox.peerView(id: $0.id)
|
||||
}
|
||||
)
|
||||
|> mapToSignal { peerViews -> Signal<([EnginePeer], [EnginePeer.Id: (Int32, Bool)], [EnginePeer.Id: EnginePeer.Presence]), NoError> in
|
||||
return context.account.postbox.unreadMessageCountsView(items: peerViews.map {
|
||||
.peer($0.peerId)
|
||||
})
|
||||
|> map { values in
|
||||
var peers: [Peer] = []
|
||||
var unread: [PeerId: (Int32, Bool)] = [:]
|
||||
var presences: [PeerId: PeerPresence] = [:]
|
||||
var peers: [EnginePeer] = []
|
||||
var unread: [EnginePeer.Id: (Int32, Bool)] = [:]
|
||||
var presences: [EnginePeer.Id: EnginePeer.Presence] = [:]
|
||||
for peerView in peerViews {
|
||||
if let peer = peerViewMainPeer(peerView) {
|
||||
var isMuted: Bool = false
|
||||
|
|
@ -189,10 +191,10 @@ public final class ChatListSearchRecentPeersNode: ASDisplayNode {
|
|||
}
|
||||
|
||||
if let presence = peerView.peerPresences[peer.id] {
|
||||
presences[peer.id] = presence
|
||||
presences[peer.id] = EnginePeer.Presence(presence)
|
||||
}
|
||||
|
||||
peers.append(peer)
|
||||
peers.append(EnginePeer(peer))
|
||||
}
|
||||
}
|
||||
return (peers, unread, presences)
|
||||
|
|
@ -286,7 +288,7 @@ public final class ChatListSearchRecentPeersNode: ASDisplayNode {
|
|||
self.itemCustomWidthValuePromise.set(itemCustomWidth)
|
||||
}
|
||||
|
||||
public func viewAndPeerAtPoint(_ point: CGPoint) -> (UIView, PeerId)? {
|
||||
public func viewAndPeerAtPoint(_ point: CGPoint) -> (UIView, EnginePeer.Id)? {
|
||||
let adjustedPoint = self.view.convert(point, to: self.listView.view)
|
||||
var selectedItemNode: ASDisplayNode?
|
||||
self.listView.forEachItemNode { itemNode in
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
|
|||
})))
|
||||
}
|
||||
|
||||
let archiveEnabled = !isSavedMessages && peerId != PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(777000)) && peerId == context.account.peerId
|
||||
let archiveEnabled = !isSavedMessages && peerId != PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id. _internalFromInt64Value(777000)) && peerId == context.account.peerId
|
||||
if let (group, _) = groupAndIndex {
|
||||
if archiveEnabled {
|
||||
let isArchived = group == Namespaces.PeerGroup.archive
|
||||
|
|
@ -361,14 +361,15 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
|
|||
|
||||
joinChannelDisposable.set((createSignal
|
||||
|> deliverOnMainQueue).start(next: { _ in
|
||||
if let navigationController = (chatListController?.navigationController as? NavigationController) {
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId)))
|
||||
}
|
||||
}, error: { _ in
|
||||
if let chatListController = chatListController {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
chatListController.present(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}
|
||||
}, completed: {
|
||||
if let navigationController = (chatListController?.navigationController as? NavigationController) {
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId)))
|
||||
}
|
||||
}))
|
||||
f(.default)
|
||||
})))
|
||||
|
|
|
|||
|
|
@ -611,8 +611,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
if let layout = strongSelf.validLayout, case .regular = layout.metrics.widthClass {
|
||||
scrollToEndIfExists = true
|
||||
}
|
||||
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), activateInput: activateInput && !peer.isDeleted, scrollToEndIfExists: scrollToEndIfExists, animated: !scrollToEndIfExists, options: strongSelf.groupId == PeerGroupId.root ? [.removeOnMasterDetails] : [], parentGroupId: strongSelf.groupId, completion: { [weak self] controller in
|
||||
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), activateInput: activateInput && !peer.isDeleted, scrollToEndIfExists: scrollToEndIfExists, animated: !scrollToEndIfExists, options: strongSelf.groupId == PeerGroupId.root ? [.removeOnMasterDetails] : [], parentGroupId: strongSelf.groupId, chatListFilter: strongSelf.chatListDisplayNode.containerNode.currentItemNode.chatListFilter?.data, completion: { [weak self] controller in
|
||||
self?.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true)
|
||||
if let promoInfo = promoInfo {
|
||||
switch promoInfo {
|
||||
|
|
@ -836,10 +836,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
}
|
||||
|
||||
switch item.content {
|
||||
case let .groupReference(groupReference):
|
||||
let chatListController = ChatListControllerImpl(context: strongSelf.context, groupId: groupReference.groupId, controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: true, enableDebugActions: false)
|
||||
case let .groupReference(groupId, _, _, _, _):
|
||||
let chatListController = ChatListControllerImpl(context: strongSelf.context, groupId: groupId, controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: true, enableDebugActions: false)
|
||||
chatListController.navigationPresentation = .master
|
||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: archiveContextMenuItems(context: strongSelf.context, groupId: groupReference.groupId, chatListController: strongSelf), reactionItems: [], gesture: gesture)
|
||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: archiveContextMenuItems(context: strongSelf.context, groupId: groupId, chatListController: strongSelf), reactionItems: [], gesture: gesture)
|
||||
strongSelf.presentInGlobalOverlay(contextController)
|
||||
case let .peer(_, peer, _, _, _, _, _, _, promoInfo, _, _, _):
|
||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peerId), subject: nil, botStart: nil, mode: .standard(previewing: true))
|
||||
|
|
@ -1126,6 +1126,26 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
|
||||
self.chatListDisplayNode.containerNode.updateEnableAdjacentFilterLoading(true)
|
||||
|
||||
self.chatListDisplayNode.containerNode.didBeginSelectingChats = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if !strongSelf.chatListDisplayNode.didBeginSelectingChatsWhileEditing {
|
||||
var isEditing = false
|
||||
strongSelf.chatListDisplayNode.containerNode.updateState { state in
|
||||
isEditing = state.editing
|
||||
return state
|
||||
}
|
||||
if !isEditing {
|
||||
strongSelf.editPressed()
|
||||
}
|
||||
strongSelf.chatListDisplayNode.didBeginSelectingChatsWhileEditing = true
|
||||
if let layout = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(layout: layout, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
guard case .root = self.groupId else {
|
||||
return
|
||||
}
|
||||
|
|
@ -1265,27 +1285,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
return true
|
||||
})
|
||||
}
|
||||
|
||||
self.chatListDisplayNode.containerNode.didBeginSelectingChats = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if !strongSelf.chatListDisplayNode.didBeginSelectingChatsWhileEditing {
|
||||
var isEditing = false
|
||||
strongSelf.chatListDisplayNode.containerNode.updateState { state in
|
||||
isEditing = state.editing
|
||||
return state
|
||||
}
|
||||
if !isEditing {
|
||||
strongSelf.editPressed()
|
||||
}
|
||||
strongSelf.chatListDisplayNode.didBeginSelectingChatsWhileEditing = true
|
||||
if let layout = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(layout: layout, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if !self.processedFeaturedFilters {
|
||||
let initializedFeatured = self.context.account.postbox.preferencesView(keys: [
|
||||
PreferencesKeys.chatListFiltersFeaturedState
|
||||
|
|
@ -1481,8 +1481,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
switch entry {
|
||||
case .all:
|
||||
return nil
|
||||
case let .filter(filter):
|
||||
return filter.id
|
||||
case let .filter(id, _, _):
|
||||
return id
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1996,7 +1996,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
return false
|
||||
}
|
||||
if value == .commit {
|
||||
let context = strongSelf.context
|
||||
let presentationData = strongSelf.presentationData
|
||||
let progressSignal = Signal<Never, NoError> { subscriber in
|
||||
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
|
||||
|
|
@ -2228,7 +2227,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
}
|
||||
|
||||
if canRemoveGlobally, (mainPeer is TelegramGroup || mainPeer is TelegramChannel) {
|
||||
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: mainPeer, chatPeer: chatPeer, action: .deleteAndLeave, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: EnginePeer(mainPeer), chatPeer: EnginePeer(chatPeer), action: .deleteAndLeave, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
|
@ -2266,7 +2265,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
], parseMarkdown: true), in: .window(.root))
|
||||
}))
|
||||
} else {
|
||||
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: mainPeer, chatPeer: chatPeer, action: .delete, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: EnginePeer(mainPeer), chatPeer: EnginePeer(chatPeer), action: .delete, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
|
||||
if canClear {
|
||||
let beginClear: (InteractiveHistoryClearingType) -> Void = { type in
|
||||
|
|
@ -2327,7 +2326,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
|
||||
var items: [ActionSheetItem] = []
|
||||
|
||||
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: mainPeer, chatPeer: chatPeer, action: .clearHistory(canClearCache: false), strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: EnginePeer(mainPeer), chatPeer: EnginePeer(chatPeer), action: .clearHistory(canClearCache: false), strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
|
||||
if joined || mainPeer.isDeleted {
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Delete, color: .destructive, action: { [weak actionSheet] in
|
||||
|
|
@ -2387,7 +2386,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
|
||||
var items: [ActionSheetItem] = []
|
||||
|
||||
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: mainPeer, chatPeer: chatPeer, action: .deleteAndLeave, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: EnginePeer(mainPeer), chatPeer: EnginePeer(chatPeer), action: .deleteAndLeave, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
|
@ -2492,7 +2491,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
let actionSheet = ActionSheetController(presentationData: self.presentationData)
|
||||
var items: [ActionSheetItem] = []
|
||||
|
||||
items.append(DeleteChatPeerActionSheetItem(context: self.context, peer: mainPeer, chatPeer: chatPeer, action: .delete, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder))
|
||||
items.append(DeleteChatPeerActionSheetItem(context: self.context, peer: EnginePeer(mainPeer), chatPeer: EnginePeer(chatPeer), action: .delete, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder))
|
||||
|
||||
if joined || mainPeer.isDeleted {
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.Common_Delete, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ private final class ChatListShimmerNode: ASDisplayNode {
|
|||
let peer1 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(0)), accessHash: nil, firstName: "FirstName", lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let timestamp1: Int32 = 100000
|
||||
let peers = SimpleDictionary<PeerId, Peer>()
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
||||
}, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in }, activateChatPreview: { _, _, gesture in
|
||||
gesture?.cancel()
|
||||
}, present: { _ in })
|
||||
|
|
@ -1165,12 +1165,9 @@ final class ChatListControllerNode: ASDisplayNode {
|
|||
return nil
|
||||
}
|
||||
|
||||
var filter: ChatListNodePeersFilter = []
|
||||
if false, case .group = self.groupId {
|
||||
filter.insert(.excludeRecent)
|
||||
}
|
||||
let filter: ChatListNodePeersFilter = []
|
||||
|
||||
let contentNode = ChatListSearchContainerNode(context: self.context, filter: filter, groupId: self.groupId, displaySearchFilters: displaySearchFilters, initialFilter: initialFilter, openPeer: { [weak self] peer, dismissSearch in
|
||||
let contentNode = ChatListSearchContainerNode(context: self.context, filter: filter, groupId: self.groupId, displaySearchFilters: displaySearchFilters, initialFilter: initialFilter, openPeer: { [weak self] peer, _, dismissSearch in
|
||||
self?.requestOpenPeerFromSearch?(peer, dismissSearch)
|
||||
}, openDisabledPeer: { _ in
|
||||
}, openRecentPeerOptions: { [weak self] peer in
|
||||
|
|
|
|||
|
|
@ -157,7 +157,6 @@ class ChatListFilterPresetCategoryItemNode: ItemListRevealOptionsItemNode, ItemL
|
|||
|
||||
func asyncLayout() -> (_ item: ChatListFilterPresetCategoryItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors, _ headerAtTop: Bool) -> (ListViewItemNodeLayout, (Bool, Bool) -> Void) {
|
||||
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||
let editableControlLayout = ItemListEditableControlNode.asyncLayout(self.editableControlNode)
|
||||
|
||||
let currentItem = self.item
|
||||
|
||||
|
|
@ -193,16 +192,10 @@ class ChatListFilterPresetCategoryItemNode: ItemListRevealOptionsItemNode, ItemL
|
|||
avatarSize = 40.0
|
||||
leftInset = 65.0 + params.leftInset
|
||||
|
||||
var editableControlSizeAndApply: (CGFloat, (CGFloat) -> ItemListEditableControlNode)?
|
||||
let editableControlSizeAndApply: (CGFloat, (CGFloat) -> ItemListEditableControlNode)? = nil
|
||||
|
||||
let editingOffset: CGFloat
|
||||
if false {
|
||||
let sizeAndApply = editableControlLayout(item.presentationData.theme, false)
|
||||
editableControlSizeAndApply = sizeAndApply
|
||||
editingOffset = sizeAndApply.0
|
||||
} else {
|
||||
editingOffset = 0.0
|
||||
}
|
||||
editingOffset = 0.0
|
||||
|
||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 12.0 - editingOffset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
|
|
|
|||
|
|
@ -260,8 +260,8 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
|||
return .index(3)
|
||||
case .addIncludePeer:
|
||||
return .index(4)
|
||||
case let .includeCategory(includeCategory):
|
||||
return .includeCategory(includeCategory.category)
|
||||
case let .includeCategory(_, category, _, _):
|
||||
return .includeCategory(category)
|
||||
case .includeExpand:
|
||||
return .index(5)
|
||||
case .includePeerInfo:
|
||||
|
|
@ -270,16 +270,16 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
|||
return .index(7)
|
||||
case .addExcludePeer:
|
||||
return .index(8)
|
||||
case let .excludeCategory(excludeCategory):
|
||||
return .excludeCategory(excludeCategory.category)
|
||||
case let .excludeCategory(_, category, _, _):
|
||||
return .excludeCategory(category)
|
||||
case .excludeExpand:
|
||||
return .index(9)
|
||||
case .excludePeerInfo:
|
||||
return .index(10)
|
||||
case let .includePeer(peer):
|
||||
return .peer(peer.peer.peerId)
|
||||
case let .excludePeer(peer):
|
||||
return .peer(peer.peer.peerId)
|
||||
case let .includePeer(_, peer, _):
|
||||
return .peer(peer.peerId)
|
||||
case let .excludePeer(_, peer, _):
|
||||
return .peer(peer.peerId)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -295,10 +295,10 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
|||
return .includeIndex(0)
|
||||
case .addIncludePeer:
|
||||
return .includeIndex(1)
|
||||
case let .includeCategory(includeCategory):
|
||||
return .includeIndex(2 + includeCategory.index)
|
||||
case let .includePeer(includePeer):
|
||||
return .includeIndex(200 + includePeer.index)
|
||||
case let .includeCategory(index, _, _, _):
|
||||
return .includeIndex(2 + index)
|
||||
case let .includePeer(index, _, _):
|
||||
return .includeIndex(200 + index)
|
||||
case .includeExpand:
|
||||
return .includeIndex(999)
|
||||
case .includePeerInfo:
|
||||
|
|
@ -307,10 +307,10 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
|||
return .excludeIndex(0)
|
||||
case .addExcludePeer:
|
||||
return .excludeIndex(1)
|
||||
case let .excludeCategory(excludeCategory):
|
||||
return .excludeIndex(2 + excludeCategory.index)
|
||||
case let .excludePeer(excludePeer):
|
||||
return .excludeIndex(200 + excludePeer.index)
|
||||
case let .excludeCategory(index, _, _, _):
|
||||
return .excludeIndex(2 + index)
|
||||
case let .excludePeer(index, _, _):
|
||||
return .excludeIndex(200 + index)
|
||||
case .excludeExpand:
|
||||
return .excludeIndex(999)
|
||||
case .excludePeerInfo:
|
||||
|
|
|
|||
|
|
@ -94,16 +94,16 @@ private enum ChatListFilterPresetListEntry: ItemListNodeEntry {
|
|||
return 0
|
||||
case .listHeader:
|
||||
return 100
|
||||
case let .preset(preset):
|
||||
return 101 + preset.index.value
|
||||
case let .preset(index, _, _, _, _, _, _):
|
||||
return 101 + index.value
|
||||
case .addItem:
|
||||
return 1000
|
||||
case .listFooter:
|
||||
return 1001
|
||||
case .suggestedListHeader:
|
||||
return 1002
|
||||
case let .suggestedPreset(suggestedPreset):
|
||||
return 1003 + suggestedPreset.index.value
|
||||
case let .suggestedPreset(index, _, _, _):
|
||||
return 1003 + index.value
|
||||
case .suggestedAddCustom:
|
||||
return 2000
|
||||
}
|
||||
|
|
@ -115,14 +115,14 @@ private enum ChatListFilterPresetListEntry: ItemListNodeEntry {
|
|||
return .screenHeader
|
||||
case .suggestedListHeader:
|
||||
return .suggestedListHeader
|
||||
case let .suggestedPreset(suggestedPreset):
|
||||
return .suggestedPreset(suggestedPreset.preset)
|
||||
case let .suggestedPreset(_, _, _, preset):
|
||||
return .suggestedPreset(preset)
|
||||
case .suggestedAddCustom:
|
||||
return .suggestedAddCustom
|
||||
case .listHeader:
|
||||
return .listHeader
|
||||
case let .preset(preset):
|
||||
return .preset(preset.preset.id)
|
||||
case let .preset(_, _, _, preset, _, _, _):
|
||||
return .preset(preset.id)
|
||||
case .addItem:
|
||||
return .addItem
|
||||
case .listFooter:
|
||||
|
|
@ -297,8 +297,6 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch
|
|||
presentControllerImpl?(actionSheet)
|
||||
})
|
||||
|
||||
let chatCountCache = Atomic<[ChatListFilterData: Int]>(value: [:])
|
||||
|
||||
let filtersWithCountsSignal = context.engine.peers.updatedChatListFilters()
|
||||
|> distinctUntilChanged
|
||||
|> mapToSignal { filters -> Signal<[(ChatListFilter, Int)], NoError> in
|
||||
|
|
@ -430,7 +428,7 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch
|
|||
}
|
||||
controller.setReorderEntry({ (fromIndex: Int, toIndex: Int, entries: [ChatListFilterPresetListEntry]) -> Signal<Bool, NoError> in
|
||||
let fromEntry = entries[fromIndex]
|
||||
guard case let .preset(fromFilter) = fromEntry else {
|
||||
guard case let .preset(_, _, _, fromPreset, _, _, _) = fromEntry else {
|
||||
return .single(false)
|
||||
}
|
||||
var referenceFilter: ChatListFilter?
|
||||
|
|
@ -438,8 +436,8 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch
|
|||
var afterAll = false
|
||||
if toIndex < entries.count {
|
||||
switch entries[toIndex] {
|
||||
case let .preset(toFilter):
|
||||
referenceFilter = toFilter.preset
|
||||
case let .preset(_, _, _, preset, _, _, _):
|
||||
referenceFilter = preset
|
||||
default:
|
||||
if entries[toIndex] < fromEntry {
|
||||
beforeAll = true
|
||||
|
|
@ -459,7 +457,7 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch
|
|||
var filters = filtersWithAppliedOrder(filters: filtersWithCountsValue, order: updatedFilterOrderValue).map { $0.0 }
|
||||
let initialOrder = filters.map { $0.id }
|
||||
|
||||
if let index = filters.firstIndex(where: { $0.id == fromFilter.preset.id }) {
|
||||
if let index = filters.firstIndex(where: { $0.id == fromPreset.id }) {
|
||||
filters.remove(at: index)
|
||||
}
|
||||
if let referenceFilter = referenceFilter {
|
||||
|
|
@ -467,21 +465,21 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch
|
|||
for i in 0 ..< filters.count {
|
||||
if filters[i].id == referenceFilter.id {
|
||||
if fromIndex < toIndex {
|
||||
filters.insert(fromFilter.preset, at: i + 1)
|
||||
filters.insert(fromPreset, at: i + 1)
|
||||
} else {
|
||||
filters.insert(fromFilter.preset, at: i)
|
||||
filters.insert(fromPreset, at: i)
|
||||
}
|
||||
inserted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !inserted {
|
||||
filters.append(fromFilter.preset)
|
||||
filters.append(fromPreset)
|
||||
}
|
||||
} else if beforeAll {
|
||||
filters.insert(fromFilter.preset, at: 0)
|
||||
filters.insert(fromPreset, at: 0)
|
||||
} else if afterAll {
|
||||
filters.append(fromFilter.preset)
|
||||
filters.append(fromPreset)
|
||||
}
|
||||
|
||||
let updatedOrder = filters.map { $0.id }
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ private final class ItemNode: ASDisplayNode {
|
|||
return
|
||||
}
|
||||
|
||||
if isExtracted, let theme = strongSelf.theme {
|
||||
if isExtracted {
|
||||
strongSelf.extractedBackgroundNode.image = generateStretchableFilledCircleImage(diameter: 32.0, color: strongSelf.isSelected ? UIColor(rgb: 0xbbbbbb) : UIColor(rgb: 0xf1f1f1))
|
||||
}
|
||||
transition.updateAlpha(node: strongSelf.extractedBackgroundNode, alpha: isExtracted ? 1.0 : 0.0, completion: { _ in
|
||||
|
|
@ -652,8 +652,8 @@ final class ChatListFilterTabInlineContainerNode: ASDisplayNode {
|
|||
strongSelf.scrollNode.view.panGestureRecognizer.isEnabled = true
|
||||
strongSelf.scrollNode.view.setContentOffset(strongSelf.scrollNode.view.contentOffset, animated: false)
|
||||
switch filter {
|
||||
case let .filter(filter):
|
||||
strongSelf.contextGesture?(filter.id, sourceNode, gesture)
|
||||
case let .filter(id, _, _):
|
||||
strongSelf.contextGesture?(id, sourceNode, gesture)
|
||||
default:
|
||||
strongSelf.contextGesture?(nil, sourceNode, gesture)
|
||||
}
|
||||
|
|
@ -666,11 +666,11 @@ final class ChatListFilterTabInlineContainerNode: ASDisplayNode {
|
|||
return
|
||||
}
|
||||
switch filter {
|
||||
case let .filter(filter):
|
||||
case let .filter(id, _, _):
|
||||
strongSelf.scrollNode.view.panGestureRecognizer.isEnabled = false
|
||||
strongSelf.scrollNode.view.panGestureRecognizer.isEnabled = true
|
||||
strongSelf.scrollNode.view.setContentOffset(strongSelf.scrollNode.view.contentOffset, animated: false)
|
||||
strongSelf.contextGesture?(filter.id, sourceNode, gesture)
|
||||
strongSelf.contextGesture?(id, sourceNode, gesture)
|
||||
default:
|
||||
strongSelf.contextGesture?(nil, sourceNode, gesture)
|
||||
}
|
||||
|
|
@ -685,9 +685,9 @@ final class ChatListFilterTabInlineContainerNode: ASDisplayNode {
|
|||
unreadCount = count
|
||||
unreadHasUnmuted = true
|
||||
isNoFilter = true
|
||||
case let .filter(filter):
|
||||
unreadCount = filter.unread.value
|
||||
unreadHasUnmuted = filter.unread.hasUnmuted
|
||||
case let .filter(_, _, unread):
|
||||
unreadCount = unread.value
|
||||
unreadHasUnmuted = unread.hasUnmuted
|
||||
}
|
||||
if !wasAdded && (itemNodePair.regular.unreadCount != 0) != (unreadCount != 0) {
|
||||
badgeAnimations[filter.id] = (unreadCount != 0) ? .in : .out
|
||||
|
|
@ -830,9 +830,7 @@ final class ChatListFilterTabInlineContainerNode: ASDisplayNode {
|
|||
transition.updateFrame(node: self.itemsBackgroundTintNode, frame: backgroundFrame)
|
||||
|
||||
self.scrollNode.view.contentSize = CGSize(width: itemsBackgroundRightX + 8.0, height: size.height)
|
||||
|
||||
var previousFrame: CGRect?
|
||||
var nextFrame: CGRect?
|
||||
|
||||
var selectedFrame: CGRect?
|
||||
if let selectedFilter = selectedFilter, let currentIndex = reorderedFilters.firstIndex(where: { $0.id == selectedFilter }) {
|
||||
func interpolateFrame(from fromValue: CGRect, to toValue: CGRect, t: CGFloat) -> CGRect {
|
||||
|
|
|
|||
|
|
@ -122,9 +122,9 @@ class ChatListRecentPeersListItemNode: ListViewItemNode {
|
|||
peersNode.updateThemeAndStrings(theme: item.theme, strings: item.strings)
|
||||
} else {
|
||||
peersNode = ChatListSearchRecentPeersNode(context: item.context, theme: item.theme, mode: .list, strings: item.strings, peerSelected: { peer in
|
||||
self?.item?.peerSelected(peer)
|
||||
self?.item?.peerSelected(peer._asPeer())
|
||||
}, peerContextAction: { peer, node, gesture in
|
||||
self?.item?.peerContextAction(peer, node, gesture)
|
||||
self?.item?.peerContextAction(peer._asPeer(), node, gesture)
|
||||
}, isPeerSelected: { _ in
|
||||
return false
|
||||
})
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ private enum ChatListTokenId: Int32 {
|
|||
}
|
||||
|
||||
final class ChatListSearchInteraction {
|
||||
let openPeer: (Peer, Bool) -> Void
|
||||
let openPeer: (Peer, Peer?, Bool) -> Void
|
||||
let openDisabledPeer: (Peer) -> Void
|
||||
let openMessage: (Peer, MessageId, Bool) -> Void
|
||||
let openUrl: (String) -> Void
|
||||
|
|
@ -52,7 +52,7 @@ final class ChatListSearchInteraction {
|
|||
let dismissInput: () -> Void
|
||||
let getSelectedMessageIds: () -> Set<MessageId>?
|
||||
|
||||
init(openPeer: @escaping (Peer, Bool) -> Void, openDisabledPeer: @escaping (Peer) -> Void, openMessage: @escaping (Peer, MessageId, Bool) -> Void, openUrl: @escaping (String) -> Void, clearRecentSearch: @escaping () -> Void, addContact: @escaping (String) -> Void, toggleMessageSelection: @escaping (MessageId, Bool) -> Void, messageContextAction: @escaping ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), mediaMessageContextAction: @escaping ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, getSelectedMessageIds: @escaping () -> Set<MessageId>?) {
|
||||
init(openPeer: @escaping (Peer, Peer?, Bool) -> Void, openDisabledPeer: @escaping (Peer) -> Void, openMessage: @escaping (Peer, MessageId, Bool) -> Void, openUrl: @escaping (String) -> Void, clearRecentSearch: @escaping () -> Void, addContact: @escaping (String) -> Void, toggleMessageSelection: @escaping (MessageId, Bool) -> Void, messageContextAction: @escaping ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), mediaMessageContextAction: @escaping ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, getSelectedMessageIds: @escaping () -> Set<MessageId>?) {
|
||||
self.openPeer = openPeer
|
||||
self.openDisabledPeer = openDisabledPeer
|
||||
self.openMessage = openMessage
|
||||
|
|
@ -124,7 +124,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
|
||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||
|
||||
public init(context: AccountContext, filter: ChatListNodePeersFilter, groupId: PeerGroupId, displaySearchFilters: Bool, initialFilter: ChatListSearchFilter = .chats, openPeer originalOpenPeer: @escaping (Peer, Bool) -> Void, openDisabledPeer: @escaping (Peer) -> Void, openRecentPeerOptions: @escaping (Peer) -> Void, openMessage originalOpenMessage: @escaping (Peer, MessageId, Bool) -> Void, addContact: ((String) -> Void)?, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void, navigationController: NavigationController?) {
|
||||
public init(context: AccountContext, filter: ChatListNodePeersFilter, groupId: PeerGroupId, displaySearchFilters: Bool, initialFilter: ChatListSearchFilter = .chats, openPeer originalOpenPeer: @escaping (Peer, Peer?, Bool) -> Void, openDisabledPeer: @escaping (Peer) -> Void, openRecentPeerOptions: @escaping (Peer) -> Void, openMessage originalOpenMessage: @escaping (Peer, MessageId, Bool) -> Void, addContact: ((String) -> Void)?, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void, navigationController: NavigationController?) {
|
||||
self.context = context
|
||||
self.peersFilter = filter
|
||||
self.groupId = groupId
|
||||
|
|
@ -149,8 +149,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
|
||||
self.addSubnode(self.paneContainerNode)
|
||||
|
||||
let interaction = ChatListSearchInteraction(openPeer: { peer, value in
|
||||
originalOpenPeer(peer, value)
|
||||
let interaction = ChatListSearchInteraction(openPeer: { peer, chatPeer, value in
|
||||
originalOpenPeer(peer, chatPeer, value)
|
||||
if peer.id.namespace != Namespaces.Peer.SecretChat {
|
||||
addAppLogEvent(postbox: context.account.postbox, type: "search_global_open_peer", peerId: peer.id)
|
||||
}
|
||||
|
|
@ -827,14 +827,11 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
if let strongSelf = self, !actions.options.isEmpty {
|
||||
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
|
||||
var items: [ActionSheetItem] = []
|
||||
var personalPeerName: String?
|
||||
var isChannel = false
|
||||
let personalPeerName: String? = nil
|
||||
|
||||
if actions.options.contains(.deleteGlobally) {
|
||||
let globalTitle: String
|
||||
if isChannel {
|
||||
globalTitle = strongSelf.presentationData.strings.Conversation_DeleteMessagesForMe
|
||||
} else if let personalPeerName = personalPeerName {
|
||||
if let personalPeerName = personalPeerName {
|
||||
globalTitle = strongSelf.presentationData.strings.Conversation_DeleteMessagesFor(personalPeerName).string
|
||||
} else {
|
||||
globalTitle = strongSelf.presentationData.strings.Conversation_DeleteMessagesForEveryone
|
||||
|
|
@ -854,14 +851,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
}))
|
||||
}
|
||||
if actions.options.contains(.deleteLocally) {
|
||||
var localOptionText = strongSelf.presentationData.strings.Conversation_DeleteMessagesForMe
|
||||
// if strongSelf.context.account.peerId == strongSelf.peerId {
|
||||
// if messageIds.count == 1 {
|
||||
// localOptionText = strongSelf.presentationData.strings.Conversation_Moderate_Delete
|
||||
// } else {
|
||||
// localOptionText = strongSelf.presentationData.strings.Conversation_DeleteManyMessages
|
||||
// }
|
||||
// }
|
||||
let localOptionText = strongSelf.presentationData.strings.Conversation_DeleteMessagesForMe
|
||||
items.append(ActionSheetButtonItem(title: localOptionText, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
if let strongSelf = self {
|
||||
|
|
@ -901,7 +891,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
}).start()
|
||||
|
||||
let peerSelectionController = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: [.onlyWriteable, .excludeDisabled], multipleSelection: true))
|
||||
peerSelectionController.multiplePeersSelected = { [weak self, weak peerSelectionController] peers, messageText, mode in
|
||||
peerSelectionController.multiplePeersSelected = { [weak self, weak peerSelectionController] peers, peerMap, messageText, mode in
|
||||
guard let strongSelf = self, let strongController = peerSelectionController else {
|
||||
return
|
||||
}
|
||||
|
|
@ -926,6 +916,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
return .forward(source: messageId, grouping: .auto, attributes: [], correlationId: nil)
|
||||
})
|
||||
|
||||
var displayPeers: [Peer] = []
|
||||
for peer in peers {
|
||||
let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: result)
|
||||
|> deliverOnMainQueue).start(next: { messageIds in
|
||||
|
|
@ -951,31 +942,38 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
|> deliverOnMainQueue).start())
|
||||
}
|
||||
})
|
||||
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
let text: String
|
||||
var savedMessages = false
|
||||
if peers.count == 1, let peerId = peers.first?.id, peerId == strongSelf.context.account.peerId {
|
||||
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One : presentationData.strings.Conversation_ForwardTooltip_SavedMessages_Many
|
||||
savedMessages = true
|
||||
} else {
|
||||
if peers.count == 1, let peer = peers.first {
|
||||
let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string : presentationData.strings.Conversation_ForwardTooltip_Chat_Many(peerName).string
|
||||
} else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last {
|
||||
let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string : presentationData.strings.Conversation_ForwardTooltip_TwoChats_Many(firstPeerName, secondPeerName).string
|
||||
} else if let peer = peers.first {
|
||||
let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string : presentationData.strings.Conversation_ForwardTooltip_ManyChats_Many(peerName, "\(peers.count - 1)").string
|
||||
} else {
|
||||
text = ""
|
||||
if let secretPeer = peer as? TelegramSecretChat {
|
||||
if let peer = peerMap[secretPeer.regularPeerId] {
|
||||
displayPeers.append(peer)
|
||||
}
|
||||
} else {
|
||||
displayPeers.append(peer)
|
||||
}
|
||||
|
||||
(strongSelf.navigationController?.topViewController as? ViewController)?.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
}
|
||||
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
let text: String
|
||||
var savedMessages = false
|
||||
if displayPeers.count == 1, let peerId = displayPeers.first?.id, peerId == strongSelf.context.account.peerId {
|
||||
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One : presentationData.strings.Conversation_ForwardTooltip_SavedMessages_Many
|
||||
savedMessages = true
|
||||
} else {
|
||||
if displayPeers.count == 1, let peer = displayPeers.first {
|
||||
let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string : presentationData.strings.Conversation_ForwardTooltip_Chat_Many(peerName).string
|
||||
} else if displayPeers.count == 2, let firstPeer = displayPeers.first, let secondPeer = displayPeers.last {
|
||||
let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string : presentationData.strings.Conversation_ForwardTooltip_TwoChats_Many(firstPeerName, secondPeerName).string
|
||||
} else if let peer = displayPeers.first {
|
||||
let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(displayPeers.count - 1)").string : presentationData.strings.Conversation_ForwardTooltip_ManyChats_Many(peerName, "\(displayPeers.count - 1)").string
|
||||
} else {
|
||||
text = ""
|
||||
}
|
||||
}
|
||||
|
||||
(strongSelf.navigationController?.topViewController as? ViewController)?.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
}
|
||||
peerSelectionController.peerSelected = { [weak self, weak peerSelectionController] peer in
|
||||
let peerId = peer.id
|
||||
|
|
@ -1023,15 +1021,10 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
}
|
||||
} else {
|
||||
let _ = (strongSelf.context.account.postbox.transaction({ transaction -> Void in
|
||||
transaction.updatePeerChatInterfaceState(peerId, update: { currentState in
|
||||
if let currentState = currentState as? ChatInterfaceState {
|
||||
return currentState.withUpdatedForwardMessageIds(Array(messageIds))
|
||||
} else {
|
||||
return ChatInterfaceState().withUpdatedForwardMessageIds(Array(messageIds))
|
||||
}
|
||||
})
|
||||
}) |> deliverOnMainQueue).start(completed: {
|
||||
let _ = (ChatInterfaceState.update(engine: strongSelf.context.engine, peerId: peerId, threadId: nil, { currentState in
|
||||
return currentState.withUpdatedForwardMessageIds(Array(messageIds))
|
||||
})
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
if let strongSelf = self {
|
||||
let controller = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peerId), subject: nil, botStart: nil, mode: .standard(previewing: false))
|
||||
controller.purposefulAction = { [weak self] in
|
||||
|
|
|
|||
|
|
@ -440,8 +440,12 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
|||
})
|
||||
}
|
||||
|
||||
return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: primaryPeer, chatPeer: chatPeer), status: .none, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in
|
||||
interaction.peerSelected(peer, nil)
|
||||
return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: primaryPeer, chatPeer: chatPeer), status: .none, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { contactPeer in
|
||||
if case let .peer(maybePeer, maybeChatPeer) = contactPeer, let peer = maybePeer, let chatPeer = maybeChatPeer {
|
||||
interaction.peerSelected(chatPeer, peer, nil)
|
||||
} else {
|
||||
interaction.peerSelected(peer, nil, nil)
|
||||
}
|
||||
}, contextAction: peerContextAction.flatMap { peerContextAction in
|
||||
return { node, gesture in
|
||||
if let chatPeer = chatPeer, chatPeer.id.namespace != Namespaces.Peer.SecretChat {
|
||||
|
|
@ -504,7 +508,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
|||
}
|
||||
|
||||
return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: peer.peer, chatPeer: peer.peer), status: .addressName(suffixString), badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in
|
||||
interaction.peerSelected(peer.peer, nil)
|
||||
interaction.peerSelected(peer.peer, nil, nil)
|
||||
}, contextAction: peerContextAction.flatMap { peerContextAction in
|
||||
return { node, gesture in
|
||||
peerContextAction(peer.peer, .search(nil), node, gesture)
|
||||
|
|
@ -1209,9 +1213,9 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
}
|
||||
|
||||
let chatListInteraction = ChatListNodeInteraction(activateSearch: {
|
||||
}, peerSelected: { [weak self] peer, _ in
|
||||
}, peerSelected: { [weak self] peer, chatPeer, _ in
|
||||
interaction.dismissInput()
|
||||
interaction.openPeer(peer, false)
|
||||
interaction.openPeer(peer, chatPeer, false)
|
||||
let _ = context.engine.peers.addRecentlySearchedPeer(peerId: peer.id).start()
|
||||
self?.listNode.clearHighlightAnimated(true)
|
||||
}, disabledPeerSelected: { _ in
|
||||
|
|
@ -1478,7 +1482,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
|
||||
let firstTime = previousEntries == nil
|
||||
let transition = chatListSearchContainerPreparedRecentTransition(from: previousEntries ?? [], to: entries, context: context, presentationData: presentationData, filter: peersFilter, peerSelected: { peer in
|
||||
interaction.openPeer(peer, true)
|
||||
interaction.openPeer(peer, nil, true)
|
||||
let _ = context.engine.peers.addRecentlySearchedPeer(peerId: peer.id).start()
|
||||
self?.recentListNode.clearHighlightAnimated(true)
|
||||
}, disabledPeerSelected: { peer in
|
||||
|
|
@ -1723,32 +1727,28 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
|
||||
let mediaAccessoryPanel = MediaNavigationAccessoryPanel(context: self.context, displayBackground: true)
|
||||
mediaAccessoryPanel.containerNode.headerNode.displayScrubber = item.playbackData?.type != .instantVideo
|
||||
mediaAccessoryPanel.getController = { [weak self] in
|
||||
return self?.navigationController?.topViewController as? ViewController
|
||||
}
|
||||
mediaAccessoryPanel.presentInGlobalOverlay = { [weak self] c in
|
||||
(self?.navigationController?.topViewController as? ViewController)?.presentInGlobalOverlay(c)
|
||||
}
|
||||
mediaAccessoryPanel.close = { [weak self] in
|
||||
if let strongSelf = self, let (_, _, _, _, type, _) = strongSelf.playlistStateAndType {
|
||||
strongSelf.context.sharedContext.mediaManager.setPlaylist(nil, type: type, control: SharedMediaPlayerControlAction.playback(.pause))
|
||||
}
|
||||
}
|
||||
mediaAccessoryPanel.toggleRate = {
|
||||
[weak self] in
|
||||
mediaAccessoryPanel.setRate = { [weak self] rate in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = (strongSelf.context.sharedContext.accountManager.transaction { transaction -> AudioPlaybackRate in
|
||||
let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings) as? MusicPlaybackSettings ?? MusicPlaybackSettings.defaultSettings
|
||||
|
||||
let nextRate: AudioPlaybackRate
|
||||
switch settings.voicePlaybackRate {
|
||||
case .x1:
|
||||
nextRate = .x2
|
||||
case .x2:
|
||||
nextRate = .x1
|
||||
default:
|
||||
nextRate = .x1
|
||||
}
|
||||
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings, { _ in
|
||||
return settings.withUpdatedVoicePlaybackRate(nextRate)
|
||||
return settings.withUpdatedVoicePlaybackRate(rate)
|
||||
})
|
||||
return nextRate
|
||||
return rate
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { baseRate in
|
||||
guard let strongSelf = self, let (_, _, _, _, type, _) = strongSelf.playlistStateAndType else {
|
||||
|
|
@ -1767,22 +1767,31 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
})
|
||||
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
let slowdown = baseRate == .x1
|
||||
controller.present(
|
||||
UndoOverlayController(
|
||||
presentationData: presentationData,
|
||||
content: .audioRate(
|
||||
slowdown: slowdown,
|
||||
text: slowdown ? presentationData.strings.Conversation_AudioRateTooltipNormal : presentationData.strings.Conversation_AudioRateTooltipSpeedUp
|
||||
let slowdown: Bool?
|
||||
if baseRate == .x1 {
|
||||
slowdown = true
|
||||
} else if baseRate == .x2 {
|
||||
slowdown = false
|
||||
} else {
|
||||
slowdown = nil
|
||||
}
|
||||
if let slowdown = slowdown {
|
||||
controller.present(
|
||||
UndoOverlayController(
|
||||
presentationData: presentationData,
|
||||
content: .audioRate(
|
||||
slowdown: slowdown,
|
||||
text: slowdown ? presentationData.strings.Conversation_AudioRateTooltipNormal : presentationData.strings.Conversation_AudioRateTooltipSpeedUp
|
||||
),
|
||||
elevatedLayout: false,
|
||||
animateInAsReplacement: hasTooltip,
|
||||
action: { action in
|
||||
return true
|
||||
}
|
||||
),
|
||||
elevatedLayout: false,
|
||||
animateInAsReplacement: hasTooltip,
|
||||
action: { action in
|
||||
return true
|
||||
}
|
||||
),
|
||||
in: .current
|
||||
)
|
||||
in: .current
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -2324,7 +2333,7 @@ private final class ChatListSearchShimmerNode: ASDisplayNode {
|
|||
let timestamp1: Int32 = 100000
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
peers[peer1.id] = peer1
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
||||
}, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in }, activateChatPreview: { _, _, gesture in
|
||||
gesture?.cancel()
|
||||
}, present: { _ in })
|
||||
|
|
|
|||
|
|
@ -17,9 +17,10 @@ import PeerPresenceStatusManager
|
|||
import PhotoResources
|
||||
import ChatListSearchItemNode
|
||||
import ContextUI
|
||||
import ChatInterfaceState
|
||||
|
||||
public enum ChatListItemContent {
|
||||
case peer(messages: [Message], peer: RenderedPeer, combinedReadState: CombinedPeerReadState?, isRemovedFromTotalUnreadCount: Bool, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, embeddedState: PeerChatListEmbeddedInterfaceState?, inputActivities: [(Peer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, ignoreUnreadBadge: Bool, displayAsMessage: Bool, hasFailedMessages: Bool)
|
||||
case peer(messages: [Message], peer: RenderedPeer, combinedReadState: CombinedPeerReadState?, isRemovedFromTotalUnreadCount: Bool, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, embeddedState: StoredPeerChatInterfaceState?, inputActivities: [(Peer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, ignoreUnreadBadge: Bool, displayAsMessage: Bool, hasFailedMessages: Bool)
|
||||
case groupReference(groupId: PeerGroupId, peers: [ChatListGroupReferencePeer], message: Message?, unreadState: PeerGroupUnreadCountersCombinedSummary, hiddenByDefault: Bool)
|
||||
|
||||
public var chatLocation: ChatLocation? {
|
||||
|
|
@ -127,9 +128,9 @@ public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour {
|
|||
if let message = messages.last, let peer = peer.peer {
|
||||
self.interaction.messageSelected(peer, message, promoInfo)
|
||||
} else if let peer = peer.peer {
|
||||
self.interaction.peerSelected(peer, promoInfo)
|
||||
self.interaction.peerSelected(peer, nil, promoInfo)
|
||||
} else if let peer = peer.peers[peer.peerId] {
|
||||
self.interaction.peerSelected(peer, promoInfo)
|
||||
self.interaction.peerSelected(peer, nil, promoInfo)
|
||||
}
|
||||
case let .groupReference(groupId, _, _, _, _):
|
||||
self.interaction.groupSelected(groupId)
|
||||
|
|
@ -675,12 +676,12 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
if peerValue.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
enablePreview = false
|
||||
}
|
||||
case let .groupReference(groupReference):
|
||||
if let previousItem = previousItem, case let .groupReference(previousGroupReference) = previousItem.content, groupReference.hiddenByDefault != previousGroupReference.hiddenByDefault {
|
||||
case let .groupReference(_, _, _, _, hiddenByDefault):
|
||||
if let previousItem = previousItem, case let .groupReference(_, _, _, _, previousHiddenByDefault) = previousItem.content, hiddenByDefault != previousHiddenByDefault {
|
||||
UIView.transition(with: self.avatarNode.view, duration: 0.3, options: [.transitionCrossDissolve], animations: {
|
||||
}, completion: nil)
|
||||
}
|
||||
self.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: .archivedChatsIcon(hiddenByDefault: groupReference.hiddenByDefault), emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoads)
|
||||
self.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer.flatMap(EnginePeer.init), overrideImage: .archivedChatsIcon(hiddenByDefault: hiddenByDefault), emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoads)
|
||||
}
|
||||
|
||||
if let peer = peer {
|
||||
|
|
@ -692,7 +693,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
} else if peer.isDeleted {
|
||||
overrideImage = .deletedIcon
|
||||
}
|
||||
self.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoads, displayDimensions: CGSize(width: 60.0, height: 60.0))
|
||||
self.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: EnginePeer(peer), overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoads, displayDimensions: CGSize(width: 60.0, height: 60.0))
|
||||
}
|
||||
|
||||
self.contextContainer.isGestureEnabled = enablePreview && !item.editing
|
||||
|
|
@ -813,7 +814,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
let unreadCount: (count: Int32, unread: Bool, muted: Bool, mutedCount: Int32?)
|
||||
let isRemovedFromTotalUnreadCount: Bool
|
||||
let peerPresence: PeerPresence?
|
||||
let embeddedState: PeerChatListEmbeddedInterfaceState?
|
||||
let embeddedState: StoredPeerChatInterfaceState?
|
||||
let summaryInfo: ChatListMessageTagSummaryInfo
|
||||
let inputActivities: [(Peer, PeerInputActivity)]?
|
||||
let isPeerGroup: Bool
|
||||
|
|
@ -824,7 +825,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
var groupHiddenByDefault = false
|
||||
|
||||
switch item.content {
|
||||
case let .peer(messagesValue, peerValue, combinedReadStateValue, isRemovedFromTotalUnreadCountValue, peerPresenceValue, summaryInfoValue, embeddedStateValue, inputActivitiesValue, promoInfoValue, ignoreUnreadBadge, displayAsMessageValue, hasFailedMessagesValue):
|
||||
case let .peer(messagesValue, peerValue, combinedReadStateValue, isRemovedFromTotalUnreadCountValue, peerPresenceValue, summaryInfoValue, embeddedStateValue, inputActivitiesValue, promoInfoValue, ignoreUnreadBadge, displayAsMessageValue, _):
|
||||
messages = messagesValue
|
||||
contentPeer = .chat(peerValue)
|
||||
combinedReadState = combinedReadStateValue
|
||||
|
|
@ -1021,11 +1022,15 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
chatListText = (text, messageText)
|
||||
}
|
||||
|
||||
if inlineAuthorPrefix == nil, let embeddedState = embeddedState as? ChatEmbeddedInterfaceState {
|
||||
if inlineAuthorPrefix == nil, let embeddedState = embeddedState, embeddedState.overrideChatTimestamp != nil, let opaqueState = _internal_decodeStoredChatInterfaceState(state: embeddedState) {
|
||||
let interfaceState = ChatInterfaceState.parse(opaqueState)
|
||||
|
||||
hasDraft = true
|
||||
authorAttributedString = NSAttributedString(string: item.presentationData.strings.DialogList_Draft, font: textFont, textColor: theme.messageDraftTextColor)
|
||||
|
||||
let draftText: String = interfaceState.composeInputState.inputText.string
|
||||
|
||||
attributedText = NSAttributedString(string: foldLineBreaks(embeddedState.text.string.replacingOccurrences(of: "\n\n", with: " ")), font: textFont, textColor: theme.messageTextColor)
|
||||
attributedText = NSAttributedString(string: foldLineBreaks(draftText.replacingOccurrences(of: "\n\n", with: " ")), font: textFont, textColor: theme.messageTextColor)
|
||||
} else if let message = messages.last {
|
||||
var composedString: NSMutableAttributedString
|
||||
if let inlineAuthorPrefix = inlineAuthorPrefix {
|
||||
|
|
@ -1275,7 +1280,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
}
|
||||
}
|
||||
|
||||
var isMuted = isRemovedFromTotalUnreadCount
|
||||
let isMuted = isRemovedFromTotalUnreadCount
|
||||
if isMuted {
|
||||
currentMutedIconImage = PresentationResourcesChatList.mutedIcon(item.presentationData.theme)
|
||||
}
|
||||
|
|
@ -1346,7 +1351,6 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
|
||||
let layoutOffset: CGFloat = 0.0
|
||||
|
||||
let rawContentOriginX = 2.0
|
||||
let rawContentWidth = params.width - leftInset - params.rightInset - 10.0 - editingOffset
|
||||
|
||||
let (dateLayout, dateApply) = dateLayout(TextNodeLayoutArguments(attributedString: dateAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: rawContentWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
|
@ -1412,7 +1416,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
if !displayAsMessage {
|
||||
if let peer = renderedPeer.chatMainPeer as? TelegramUser, let presence = presence as? TelegramUserPresence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != item.context.account.peerId {
|
||||
let updatedPresence = TelegramUserPresence(status: presence.status, lastActivity: 0)
|
||||
let relativeStatus = relativeUserPresenceStatus(updatedPresence, relativeTo: timestamp)
|
||||
let relativeStatus = relativeUserPresenceStatus(EnginePeer.Presence(updatedPresence), relativeTo: timestamp)
|
||||
if case .online = relativeStatus {
|
||||
online = true
|
||||
}
|
||||
|
|
@ -1820,7 +1824,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
}
|
||||
|
||||
let separatorInset: CGFloat
|
||||
if case let .groupReference(groupReference) = item.content, groupReference.hiddenByDefault {
|
||||
if case let .groupReference(_, _, _, _, hiddenByDefault) = item.content, hiddenByDefault {
|
||||
separatorInset = 0.0
|
||||
} else if (!nextIsPinned && item.index.pinningIndex != nil) || last {
|
||||
separatorInset = 0.0
|
||||
|
|
@ -1835,7 +1839,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
if item.selected {
|
||||
backgroundColor = theme.itemSelectedBackgroundColor
|
||||
} else if item.index.pinningIndex != nil {
|
||||
if case let .groupReference(groupReference) = item.content, groupReference.hiddenByDefault {
|
||||
if case let .groupReference(_, _, _, _, hiddenByDefault) = item.content, hiddenByDefault {
|
||||
backgroundColor = theme.itemBackgroundColor
|
||||
} else {
|
||||
backgroundColor = theme.pinnedItemBackgroundColor
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public final class ChatListNodeInteraction {
|
|||
}
|
||||
|
||||
let activateSearch: () -> Void
|
||||
let peerSelected: (Peer, ChatListNodeEntryPromoInfo?) -> Void
|
||||
let peerSelected: (Peer, Peer?, ChatListNodeEntryPromoInfo?) -> Void
|
||||
let disabledPeerSelected: (Peer) -> Void
|
||||
let togglePeerSelected: (Peer) -> Void
|
||||
let togglePeersSelection: ([PeerEntry], Bool) -> Void
|
||||
|
|
@ -75,7 +75,7 @@ public final class ChatListNodeInteraction {
|
|||
public var searchTextHighightState: String?
|
||||
var highlightedChatLocation: ChatListHighlightedLocation?
|
||||
|
||||
public init(activateSearch: @escaping () -> Void, peerSelected: @escaping (Peer, ChatListNodeEntryPromoInfo?) -> Void, disabledPeerSelected: @escaping (Peer) -> Void, togglePeerSelected: @escaping (Peer) -> Void, togglePeersSelection: @escaping ([PeerEntry], Bool) -> Void, additionalCategorySelected: @escaping (Int) -> Void, messageSelected: @escaping (Peer, Message, ChatListNodeEntryPromoInfo?) -> Void, groupSelected: @escaping (PeerGroupId) -> Void, addContact: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, setItemPinned: @escaping (PinnedItemId, Bool) -> Void, setPeerMuted: @escaping (PeerId, Bool) -> Void, deletePeer: @escaping (PeerId, Bool) -> Void, updatePeerGrouping: @escaping (PeerId, Bool) -> Void, togglePeerMarkedUnread: @escaping (PeerId, Bool) -> Void, toggleArchivedFolderHiddenByDefault: @escaping () -> Void, hidePsa: @escaping (PeerId) -> Void, activateChatPreview: @escaping (ChatListItem, ASDisplayNode, ContextGesture?) -> Void, present: @escaping (ViewController) -> Void) {
|
||||
public init(activateSearch: @escaping () -> Void, peerSelected: @escaping (Peer, Peer?, ChatListNodeEntryPromoInfo?) -> Void, disabledPeerSelected: @escaping (Peer) -> Void, togglePeerSelected: @escaping (Peer) -> Void, togglePeersSelection: @escaping ([PeerEntry], Bool) -> Void, additionalCategorySelected: @escaping (Int) -> Void, messageSelected: @escaping (Peer, Message, ChatListNodeEntryPromoInfo?) -> Void, groupSelected: @escaping (PeerGroupId) -> Void, addContact: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, setItemPinned: @escaping (PinnedItemId, Bool) -> Void, setPeerMuted: @escaping (PeerId, Bool) -> Void, deletePeer: @escaping (PeerId, Bool) -> Void, updatePeerGrouping: @escaping (PeerId, Bool) -> Void, togglePeerMarkedUnread: @escaping (PeerId, Bool) -> Void, toggleArchivedFolderHiddenByDefault: @escaping () -> Void, hidePsa: @escaping (PeerId) -> Void, activateChatPreview: @escaping (ChatListItem, ASDisplayNode, ContextGesture?) -> Void, present: @escaping (ViewController) -> Void) {
|
||||
self.activateSearch = activateSearch
|
||||
self.peerSelected = peerSelected
|
||||
self.disabledPeerSelected = disabledPeerSelected
|
||||
|
|
@ -106,6 +106,18 @@ public final class ChatListNodePeerInputActivities {
|
|||
}
|
||||
}
|
||||
|
||||
private func areFoundPeerArraysEqual(_ lhs: [(Peer, Peer?)], _ rhs: [(Peer, Peer?)]) -> Bool {
|
||||
if lhs.count != rhs.count {
|
||||
return false
|
||||
}
|
||||
for i in 0 ..< lhs.count {
|
||||
if !arePeersEqual(lhs[i].0, rhs[i].0) || !arePeersEqual(lhs[i].1, rhs[i].1) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public struct ChatListNodeState: Equatable {
|
||||
public var presentationData: ChatListPresentationData
|
||||
public var editing: Bool
|
||||
|
|
@ -117,10 +129,10 @@ public struct ChatListNodeState: Equatable {
|
|||
public var archiveShouldBeTemporaryRevealed: Bool
|
||||
public var selectedAdditionalCategoryIds: Set<Int>
|
||||
public var hiddenPsaPeerId: PeerId?
|
||||
public var foundPeers: [Peer]
|
||||
public var foundPeers: [(Peer, Peer?)]
|
||||
public var selectedPeerMap: [PeerId: Peer]
|
||||
|
||||
public init(presentationData: ChatListPresentationData, editing: Bool, peerIdWithRevealedOptions: PeerId?, selectedPeerIds: Set<PeerId>, foundPeers: [Peer], selectedPeerMap: [PeerId: Peer], selectedAdditionalCategoryIds: Set<Int>, peerInputActivities: ChatListNodePeerInputActivities?, pendingRemovalPeerIds: Set<PeerId>, pendingClearHistoryPeerIds: Set<PeerId>, archiveShouldBeTemporaryRevealed: Bool, hiddenPsaPeerId: PeerId?) {
|
||||
public init(presentationData: ChatListPresentationData, editing: Bool, peerIdWithRevealedOptions: PeerId?, selectedPeerIds: Set<PeerId>, foundPeers: [(Peer, Peer?)], selectedPeerMap: [PeerId: Peer], selectedAdditionalCategoryIds: Set<Int>, peerInputActivities: ChatListNodePeerInputActivities?, pendingRemovalPeerIds: Set<PeerId>, pendingClearHistoryPeerIds: Set<PeerId>, archiveShouldBeTemporaryRevealed: Bool, hiddenPsaPeerId: PeerId?) {
|
||||
self.presentationData = presentationData
|
||||
self.editing = editing
|
||||
self.peerIdWithRevealedOptions = peerIdWithRevealedOptions
|
||||
|
|
@ -148,7 +160,7 @@ public struct ChatListNodeState: Equatable {
|
|||
if lhs.selectedPeerIds != rhs.selectedPeerIds {
|
||||
return false
|
||||
}
|
||||
if arePeerArraysEqual(lhs.foundPeers, rhs.foundPeers) {
|
||||
if areFoundPeerArraysEqual(lhs.foundPeers, rhs.foundPeers) {
|
||||
return false
|
||||
}
|
||||
if arePeerDictionariesEqual(lhs.selectedPeerMap, rhs.selectedPeerMap) {
|
||||
|
|
@ -302,7 +314,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||
if editing {
|
||||
nodeInteraction.togglePeerSelected(chatPeer)
|
||||
} else {
|
||||
nodeInteraction.peerSelected(chatPeer, nil)
|
||||
nodeInteraction.peerSelected(chatPeer, nil, nil)
|
||||
}
|
||||
}
|
||||
}, disabledAction: { _ in
|
||||
|
|
@ -383,7 +395,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||
if editing {
|
||||
nodeInteraction.togglePeerSelected(chatPeer)
|
||||
} else {
|
||||
nodeInteraction.peerSelected(chatPeer, nil)
|
||||
nodeInteraction.peerSelected(chatPeer, nil, nil)
|
||||
}
|
||||
}
|
||||
}, disabledAction: { _ in
|
||||
|
|
@ -602,7 +614,7 @@ public final class ChatListNode: ListView {
|
|||
if let strongSelf = self, let activateSearch = strongSelf.activateSearch {
|
||||
activateSearch()
|
||||
}
|
||||
}, peerSelected: { [weak self] peer, promoInfo in
|
||||
}, peerSelected: { [weak self] peer, _, promoInfo in
|
||||
if let strongSelf = self, let peerSelected = strongSelf.peerSelected {
|
||||
peerSelected(peer, true, true, promoInfo)
|
||||
}
|
||||
|
|
@ -952,8 +964,8 @@ public final class ChatListNode: ListView {
|
|||
if index.messageIndex.id.peerId == removingPeerId {
|
||||
didIncludeRemovingPeerId = true
|
||||
}
|
||||
} else if case let .GroupReferenceEntry(entry) = entry {
|
||||
didIncludeHiddenByDefaultArchive = entry.hiddenByDefault
|
||||
} else if case let .GroupReferenceEntry(_, _, _, _, _, _, _, _, hiddenByDefault) = entry {
|
||||
didIncludeHiddenByDefaultArchive = hiddenByDefault
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -961,16 +973,16 @@ public final class ChatListNode: ListView {
|
|||
var doesIncludeArchive = false
|
||||
var doesIncludeHiddenByDefaultArchive = false
|
||||
for entry in processedView.filteredEntries {
|
||||
if case let .PeerEntry(peerEntry) = entry {
|
||||
if peerEntry.index.pinningIndex != nil {
|
||||
updatedPinnedChats.append(peerEntry.index.messageIndex.id.peerId)
|
||||
if case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = entry {
|
||||
if index.pinningIndex != nil {
|
||||
updatedPinnedChats.append(index.messageIndex.id.peerId)
|
||||
}
|
||||
if peerEntry.index.messageIndex.id.peerId == removingPeerId {
|
||||
if index.messageIndex.id.peerId == removingPeerId {
|
||||
doesIncludeRemovingPeerId = true
|
||||
}
|
||||
} else if case let .GroupReferenceEntry(entry) = entry {
|
||||
} else if case let .GroupReferenceEntry(_, _, _, _, _, _, _, _, hiddenByDefault) = entry {
|
||||
doesIncludeArchive = true
|
||||
doesIncludeHiddenByDefaultArchive = entry.hiddenByDefault
|
||||
doesIncludeHiddenByDefaultArchive = hiddenByDefault
|
||||
}
|
||||
}
|
||||
if previousPinnedChats != updatedPinnedChats {
|
||||
|
|
@ -1331,8 +1343,8 @@ public final class ChatListNode: ListView {
|
|||
var isHiddenArchiveVisible = false
|
||||
strongSelf.forEachItemNode({ itemNode in
|
||||
if let itemNode = itemNode as? ChatListItemNode, let item = itemNode.item {
|
||||
if case let .groupReference(groupReference) = item.content {
|
||||
if groupReference.hiddenByDefault {
|
||||
if case let .groupReference(_, _, _, _, hiddenByDefault) = item.content {
|
||||
if hiddenByDefault {
|
||||
isHiddenArchiveVisible = true
|
||||
}
|
||||
}
|
||||
|
|
@ -1587,8 +1599,8 @@ public final class ChatListNode: ListView {
|
|||
for item in transition.insertItems {
|
||||
if let item = item.item as? ChatListItem {
|
||||
switch item.content {
|
||||
case let .peer(peer):
|
||||
insertedPeerIds.append(peer.peer.peerId)
|
||||
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _):
|
||||
insertedPeerIds.append(peer.peerId)
|
||||
case .groupReference:
|
||||
break
|
||||
}
|
||||
|
|
@ -1997,6 +2009,13 @@ public final class ChatListNode: ListView {
|
|||
}
|
||||
|
||||
private func handlePanSelection(location: CGPoint) {
|
||||
var location = location
|
||||
if location.y < self.insets.top {
|
||||
location.y = self.insets.top + 5.0
|
||||
} else if location.y > self.frame.height - self.insets.bottom {
|
||||
location.y = self.frame.height - self.insets.bottom - 5.0
|
||||
}
|
||||
|
||||
if let state = self.selectionPanState {
|
||||
if let peer = self.peerAtPoint(location) {
|
||||
if peer.id == state.initialPeerId {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ public enum ChatListNodeEntryPromoInfo: Equatable {
|
|||
|
||||
enum ChatListNodeEntry: Comparable, Identifiable {
|
||||
case HeaderEntry
|
||||
case PeerEntry(index: ChatListIndex, presentationData: ChatListPresentationData, messages: [Message], readState: CombinedPeerReadState?, isRemovedFromTotalUnreadCount: Bool, embeddedInterfaceState: PeerChatListEmbeddedInterfaceState?, peer: RenderedPeer, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, inputActivities: [(Peer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, hasFailedMessages: Bool, isContact: Bool)
|
||||
case PeerEntry(index: ChatListIndex, presentationData: ChatListPresentationData, messages: [Message], readState: CombinedPeerReadState?, isRemovedFromTotalUnreadCount: Bool, embeddedInterfaceState: StoredPeerChatInterfaceState?, peer: RenderedPeer, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, inputActivities: [(Peer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, hasFailedMessages: Bool, isContact: Bool)
|
||||
case HoleEntry(ChatListHole, theme: PresentationTheme)
|
||||
case GroupReferenceEntry(index: ChatListIndex, presentationData: ChatListPresentationData, groupId: PeerGroupId, peers: [ChatListGroupReferencePeer], message: Message?, editing: Bool, unreadState: PeerGroupUnreadCountersCombinedSummary, revealed: Bool, hiddenByDefault: Bool)
|
||||
case ArchiveIntro(presentationData: ChatListPresentationData)
|
||||
|
|
@ -64,8 +64,8 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
|||
return .index(index)
|
||||
case .ArchiveIntro:
|
||||
return .index(ChatListIndex.absoluteUpperBound.successor)
|
||||
case let .AdditionalCategory(additionalCategory):
|
||||
return .additionalCategory(additionalCategory.index)
|
||||
case let .AdditionalCategory(index, _, _, _, _, _, _):
|
||||
return .additionalCategory(index)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -81,8 +81,8 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
|||
return .GroupId(groupId)
|
||||
case .ArchiveIntro:
|
||||
return .ArchiveIntro
|
||||
case let .AdditionalCategory(additionalCategory):
|
||||
return .additionalCategory(additionalCategory.id)
|
||||
case let .AdditionalCategory(_, id, _, _, _, _, _):
|
||||
return .additionalCategory(id)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +144,7 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
|||
return false
|
||||
}
|
||||
if let lhsEmbeddedState = lhsEmbeddedState, let rhsEmbeddedState = rhsEmbeddedState {
|
||||
if !lhsEmbeddedState.isEqual(to: rhsEmbeddedState) {
|
||||
if lhsEmbeddedState != rhsEmbeddedState {
|
||||
return false
|
||||
}
|
||||
} else if (lhsEmbeddedState != nil) != (rhsEmbeddedState != nil) {
|
||||
|
|
@ -281,7 +281,7 @@ private func offsetPinnedIndex(_ index: ChatListIndex, offset: UInt16) -> ChatLi
|
|||
}
|
||||
}
|
||||
|
||||
func chatListNodeEntriesForView(_ view: ChatListView, state: ChatListNodeState, savedMessagesPeer: Peer?, foundPeers: [Peer], hideArchivedFolderByDefault: Bool, displayArchiveIntro: Bool, mode: ChatListNodeMode) -> (entries: [ChatListNodeEntry], loading: Bool) {
|
||||
func chatListNodeEntriesForView(_ view: ChatListView, state: ChatListNodeState, savedMessagesPeer: Peer?, foundPeers: [(Peer, Peer?)], hideArchivedFolderByDefault: Bool, displayArchiveIntro: Bool, mode: ChatListNodeMode) -> (entries: [ChatListNodeEntry], loading: Bool) {
|
||||
var result: [ChatListNodeEntry] = []
|
||||
|
||||
var pinnedIndexOffset: UInt16 = 0
|
||||
|
|
@ -300,7 +300,7 @@ func chatListNodeEntriesForView(_ view: ChatListView, state: ChatListNodeState,
|
|||
|
||||
var foundPeerIds = Set<PeerId>()
|
||||
for peer in foundPeers {
|
||||
foundPeerIds.insert(peer.id)
|
||||
foundPeerIds.insert(peer.0.id)
|
||||
}
|
||||
|
||||
if view.laterIndex == nil && savedMessagesPeer == nil {
|
||||
|
|
@ -338,8 +338,13 @@ func chatListNodeEntriesForView(_ view: ChatListView, state: ChatListNodeState,
|
|||
if !foundPeers.isEmpty {
|
||||
var foundPinningIndex: UInt16 = UInt16(foundPeers.count)
|
||||
for peer in foundPeers.reversed() {
|
||||
let messageIndex = MessageIndex(id: MessageId(peerId: peer.id, namespace: 0, id: 0), timestamp: 1)
|
||||
result.append(.PeerEntry(index: ChatListIndex(pinningIndex: foundPinningIndex, messageIndex: messageIndex), presentationData: state.presentationData, messages: [], readState: nil, isRemovedFromTotalUnreadCount: false, embeddedInterfaceState: nil, peer: RenderedPeer(peerId: peer.id, peers: SimpleDictionary([peer.id: peer])), presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), editing: state.editing, hasActiveRevealControls: false, selected: state.selectedPeerIds.contains(peer.id), inputActivities: nil, promoInfo: nil, hasFailedMessages: false, isContact: false))
|
||||
var peers: [PeerId: Peer] = [peer.0.id: peer.0]
|
||||
if let chatPeer = peer.1 {
|
||||
peers[chatPeer.id] = chatPeer
|
||||
}
|
||||
|
||||
let messageIndex = MessageIndex(id: MessageId(peerId: peer.0.id, namespace: 0, id: 0), timestamp: 1)
|
||||
result.append(.PeerEntry(index: ChatListIndex(pinningIndex: foundPinningIndex, messageIndex: messageIndex), presentationData: state.presentationData, messages: [], readState: nil, isRemovedFromTotalUnreadCount: false, embeddedInterfaceState: nil, peer: RenderedPeer(peerId: peer.0.id, peers: SimpleDictionary(peers)), presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), editing: state.editing, hasActiveRevealControls: false, selected: state.selectedPeerIds.contains(peer.0.id), inputActivities: nil, promoInfo: nil, hasFailedMessages: false, isContact: false))
|
||||
if foundPinningIndex != 0 {
|
||||
foundPinningIndex -= 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@ enum ChatListNodeLocation: Equatable {
|
|||
|
||||
var filter: ChatListFilter? {
|
||||
switch self {
|
||||
case let .initial(initial):
|
||||
return initial.filter
|
||||
case let .navigation(navigation):
|
||||
return navigation.filter
|
||||
case let .scroll(scroll):
|
||||
return scroll.filter
|
||||
case let .initial(_, filter):
|
||||
return filter
|
||||
case let .navigation(_, filter):
|
||||
return filter
|
||||
case let .scroll(_, _, _, _, filter):
|
||||
return filter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@ struct ChatListNodeViewUpdate {
|
|||
let scrollPosition: ChatListNodeViewScrollPosition?
|
||||
}
|
||||
|
||||
func chatListFilterPredicate(filter: ChatListFilterData) -> ChatListFilterPredicate {
|
||||
public func chatListFilterPredicate(filter: ChatListFilterData) -> ChatListFilterPredicate {
|
||||
var includePeers = Set(filter.includePeers.peers)
|
||||
var excludePeers = Set(filter.excludePeers)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ swift_library(
|
|||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue