mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
[WIP] Topic APIs
This commit is contained in:
parent
d7d3b1b9cb
commit
d01a7853fa
@ -980,6 +980,9 @@ ios_framework(
|
|||||||
deps = [
|
deps = [
|
||||||
"//submodules/TelegramCore:TelegramCore",
|
"//submodules/TelegramCore:TelegramCore",
|
||||||
],
|
],
|
||||||
|
visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
plist_fragment(
|
plist_fragment(
|
||||||
@ -1466,6 +1469,9 @@ ios_extension(
|
|||||||
":PostboxFramework",
|
":PostboxFramework",
|
||||||
":TelegramCoreFramework",
|
":TelegramCoreFramework",
|
||||||
],
|
],
|
||||||
|
visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
plist_fragment(
|
plist_fragment(
|
||||||
@ -2059,3 +2065,53 @@ ios_application(
|
|||||||
"//third-party/libvpx:vpx",
|
"//third-party/libvpx:vpx",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
swift_library(
|
||||||
|
name = "TelegramCoreBuildTestLib",
|
||||||
|
module_name = "TelegramCoreBuildTestLib",
|
||||||
|
srcs = glob([
|
||||||
|
"Tests/TelegramCoreBuildTest/**/*.swift",
|
||||||
|
]),
|
||||||
|
copts = [
|
||||||
|
"-warnings-as-errors",
|
||||||
|
],
|
||||||
|
data = [
|
||||||
|
":WidgetAssets",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//submodules/BuildConfig:BuildConfig",
|
||||||
|
"//submodules/WidgetItems:WidgetItems_iOS14",
|
||||||
|
"//submodules/WidgetItemsUtils:WidgetItemsUtils",
|
||||||
|
"//submodules/AppLockState:AppLockState",
|
||||||
|
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||||
|
"//submodules/Postbox:Postbox",
|
||||||
|
"//submodules/TelegramCore:TelegramCore",
|
||||||
|
"//submodules/OpenSSLEncryptionProvider:OpenSSLEncryptionProvider",
|
||||||
|
"//Telegram:GeneratedSources",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
ios_application(
|
||||||
|
name = "TelegramCoreBuildTest",
|
||||||
|
bundle_id = "{telegram_bundle_id}".format(
|
||||||
|
telegram_bundle_id = telegram_bundle_id,
|
||||||
|
),
|
||||||
|
families = ["iphone", "ipad"],
|
||||||
|
minimum_os_version = minimum_os_version,
|
||||||
|
provisioning_profile = select({
|
||||||
|
":disableProvisioningProfilesSetting": None,
|
||||||
|
"//conditions:default": "@build_configuration//provisioning:Telegram.mobileprovision",
|
||||||
|
}),
|
||||||
|
entitlements = ":TelegramEntitlements.entitlements",
|
||||||
|
infoplists = [
|
||||||
|
":TelegramInfoPlist",
|
||||||
|
":BuildNumberInfoPlist",
|
||||||
|
":VersionInfoPlist",
|
||||||
|
":RequiredDeviceCapabilitiesPlist",
|
||||||
|
":UrlTypesInfoPlist",
|
||||||
|
],
|
||||||
|
frameworks = [
|
||||||
|
":TelegramCoreFramework",
|
||||||
|
],
|
||||||
|
deps = [":TelegramCoreBuildTestLib"],
|
||||||
|
)
|
||||||
|
@ -613,6 +613,7 @@ private final class NotificationServiceHandler {
|
|||||||
private let pollDisposable = MetaDisposable()
|
private let pollDisposable = MetaDisposable()
|
||||||
|
|
||||||
init?(queue: Queue, updateCurrentContent: @escaping (NotificationContent) -> Void, completed: @escaping () -> Void, payload: [AnyHashable: Any]) {
|
init?(queue: Queue, updateCurrentContent: @escaping (NotificationContent) -> Void, completed: @escaping () -> Void, payload: [AnyHashable: Any]) {
|
||||||
|
//debug_linker_fail_test()
|
||||||
self.queue = queue
|
self.queue = queue
|
||||||
|
|
||||||
let episode = String(UInt32.random(in: 0 ..< UInt32.max), radix: 16)
|
let episode = String(UInt32.random(in: 0 ..< UInt32.max), radix: 16)
|
||||||
|
155
Tests/TelegramCoreBuildTest/BUILD
Normal file
155
Tests/TelegramCoreBuildTest/BUILD
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
load("@build_bazel_rules_apple//apple:ios.bzl",
|
||||||
|
"ios_application",
|
||||||
|
)
|
||||||
|
|
||||||
|
load("@build_bazel_rules_swift//swift:swift.bzl",
|
||||||
|
"swift_library",
|
||||||
|
)
|
||||||
|
|
||||||
|
load("//build-system/bazel-utils:plist_fragment.bzl",
|
||||||
|
"plist_fragment",
|
||||||
|
)
|
||||||
|
|
||||||
|
load(
|
||||||
|
"@build_configuration//:variables.bzl",
|
||||||
|
"telegram_bundle_id",
|
||||||
|
"telegram_aps_environment",
|
||||||
|
"telegram_team_id",
|
||||||
|
"telegram_enable_icloud",
|
||||||
|
"telegram_enable_siri",
|
||||||
|
"telegram_enable_watch",
|
||||||
|
)
|
||||||
|
|
||||||
|
module_name = "TelegramCoreBuildTest"
|
||||||
|
|
||||||
|
swift_library(
|
||||||
|
name = "Lib",
|
||||||
|
srcs = glob([
|
||||||
|
"Sources/**/*.swift",
|
||||||
|
]),
|
||||||
|
data = [
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
plist_fragment(
|
||||||
|
name = "BuildNumberInfoPlist",
|
||||||
|
extension = "plist",
|
||||||
|
template =
|
||||||
|
"""
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
plist_fragment(
|
||||||
|
name = "VersionInfoPlist",
|
||||||
|
extension = "plist",
|
||||||
|
template =
|
||||||
|
"""
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>{telegramVersion}</string>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
plist_fragment(
|
||||||
|
name = "AppNameInfoPlist",
|
||||||
|
extension = "plist",
|
||||||
|
template =
|
||||||
|
"""
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>Test</string>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
plist_fragment(
|
||||||
|
name = "AppInfoPlist",
|
||||||
|
extension = "plist",
|
||||||
|
template =
|
||||||
|
"""
|
||||||
|
<key>CFBundleAllowMixedLocalizations</key>
|
||||||
|
<true/>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>Test</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>ph.telegra.Telegraph</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>Telegram</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
|
<false/>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSAppTransportSecurity</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSAllowsArbitraryLoads</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<key>UIDeviceFamily</key>
|
||||||
|
<array>
|
||||||
|
<integer>1</integer>
|
||||||
|
<integer>2</integer>
|
||||||
|
</array>
|
||||||
|
<key>UIFileSharingEnabled</key>
|
||||||
|
<false/>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>LaunchScreen</string>
|
||||||
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
</array>
|
||||||
|
<key>UIStatusBarStyle</key>
|
||||||
|
<string>UIStatusBarStyleDefault</string>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
|
<false/>
|
||||||
|
<key>UIViewEdgeAntialiasing</key>
|
||||||
|
<false/>
|
||||||
|
<key>UIViewGroupOpacity</key>
|
||||||
|
<false/>
|
||||||
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
|
<true/>
|
||||||
|
""".format(module_name=module_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
ios_application(
|
||||||
|
name = module_name,
|
||||||
|
bundle_id = "ph.telegra.Telegraph",
|
||||||
|
families = ["iphone", "ipad"],
|
||||||
|
minimum_os_version = "11.0",
|
||||||
|
provisioning_profile = None,
|
||||||
|
infoplists = [
|
||||||
|
":AppInfoPlist",
|
||||||
|
":BuildNumberInfoPlist",
|
||||||
|
":VersionInfoPlist",
|
||||||
|
],
|
||||||
|
resources = [
|
||||||
|
"//Tests/Common:LaunchScreen",
|
||||||
|
],
|
||||||
|
extensions = [
|
||||||
|
"//Telegram:WidgetExtension",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//Tests/Common:Main",
|
||||||
|
":Lib",
|
||||||
|
],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
15
Tests/TelegramCoreBuildTest/Sources/main.swift
Normal file
15
Tests/TelegramCoreBuildTest/Sources/main.swift
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
@objc(Application)
|
||||||
|
public final class Application: UIApplication {
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(AppDelegate)
|
||||||
|
public final class AppDelegate: NSObject, UIApplicationDelegate {
|
||||||
|
public var window: UIWindow?
|
||||||
|
|
||||||
|
public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
@ -732,6 +732,8 @@ public protocol SharedAccountContext: AnyObject {
|
|||||||
func makeChatRecentActionsController(context: AccountContext, peer: Peer, adminPeerId: PeerId?) -> ViewController
|
func makeChatRecentActionsController(context: AccountContext, peer: Peer, adminPeerId: PeerId?) -> ViewController
|
||||||
func makePrivacyAndSecurityController(context: AccountContext) -> ViewController
|
func makePrivacyAndSecurityController(context: AccountContext) -> ViewController
|
||||||
func navigateToChatController(_ params: NavigateToChatControllerParams)
|
func navigateToChatController(_ params: NavigateToChatControllerParams)
|
||||||
|
func navigateToForumChannel(context: AccountContext, peerId: EnginePeer.Id, navigationController: NavigationController)
|
||||||
|
func navigateToForumThread(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64, navigationController: NavigationController) -> Signal<Never, NoError>
|
||||||
func openStorageUsage(context: AccountContext)
|
func openStorageUsage(context: AccountContext)
|
||||||
func openLocationScreen(context: AccountContext, messageId: MessageId, navigationController: NavigationController)
|
func openLocationScreen(context: AccountContext, messageId: MessageId, navigationController: NavigationController)
|
||||||
func openExternalUrl(context: AccountContext, urlContext: OpenURLContext, url: String, forceExternal: Bool, presentationData: PresentationData, navigationController: NavigationController?, dismissInput: @escaping () -> Void)
|
func openExternalUrl(context: AccountContext, urlContext: OpenURLContext, url: String, forceExternal: Bool, presentationData: PresentationData, navigationController: NavigationController?, dismissInput: @escaping () -> Void)
|
||||||
|
@ -4,6 +4,11 @@ import Postbox
|
|||||||
import Display
|
import Display
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
|
|
||||||
|
public enum ChatListControllerLocation {
|
||||||
|
case chatList(groupId: EngineChatList.Group)
|
||||||
|
case forum(peerId: PeerId)
|
||||||
|
}
|
||||||
|
|
||||||
public protocol ChatListController: ViewController {
|
public protocol ChatListController: ViewController {
|
||||||
var context: AccountContext { get }
|
var context: AccountContext { get }
|
||||||
var lockViewFrame: CGRect? { get }
|
var lockViewFrame: CGRect? { get }
|
||||||
|
@ -118,8 +118,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
private let animationCache: AnimationCache
|
private let animationCache: AnimationCache
|
||||||
private let animationRenderer: MultiAnimationRenderer
|
private let animationRenderer: MultiAnimationRenderer
|
||||||
|
|
||||||
public let groupId: PeerGroupId
|
public let location: ChatListControllerLocation
|
||||||
public let filter: ChatListFilter?
|
|
||||||
public let previewing: Bool
|
public let previewing: Bool
|
||||||
|
|
||||||
let openMessageFromSearchDisposable: MetaDisposable = MetaDisposable()
|
let openMessageFromSearchDisposable: MetaDisposable = MetaDisposable()
|
||||||
@ -175,19 +174,20 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
|
|
||||||
private weak var emojiStatusSelectionController: ViewController?
|
private weak var emojiStatusSelectionController: ViewController?
|
||||||
|
|
||||||
|
private var forumChannelTracker: ForumChannelTopics?
|
||||||
|
|
||||||
public override func updateNavigationCustomData(_ data: Any?, progress: CGFloat, transition: ContainedViewLayoutTransition) {
|
public override func updateNavigationCustomData(_ data: Any?, progress: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
if self.isNodeLoaded {
|
if self.isNodeLoaded {
|
||||||
self.chatListDisplayNode.containerNode.updateSelectedChatLocation(data: data as? ChatLocation, progress: progress, transition: transition)
|
self.chatListDisplayNode.containerNode.updateSelectedChatLocation(data: data as? ChatLocation, progress: progress, transition: transition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(context: AccountContext, groupId: PeerGroupId, filter: ChatListFilter? = nil, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool = false, previewing: Bool = false, enableDebugActions: Bool) {
|
public init(context: AccountContext, location: ChatListControllerLocation, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool = false, previewing: Bool = false, enableDebugActions: Bool) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.controlsHistoryPreload = controlsHistoryPreload
|
self.controlsHistoryPreload = controlsHistoryPreload
|
||||||
self.hideNetworkActivityStatus = hideNetworkActivityStatus
|
self.hideNetworkActivityStatus = hideNetworkActivityStatus
|
||||||
|
|
||||||
self.groupId = groupId
|
self.location = location
|
||||||
self.filter = filter
|
|
||||||
self.previewing = previewing
|
self.previewing = previewing
|
||||||
|
|
||||||
self.presentationData = (context.sharedContext.currentPresentationData.with { $0 })
|
self.presentationData = (context.sharedContext.currentPresentationData.with { $0 })
|
||||||
@ -213,12 +213,18 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||||
|
|
||||||
let title: String
|
let title: String
|
||||||
if let filter = self.filter, case let .filter(_, filterTitle, _, _) = filter {
|
switch self.location {
|
||||||
title = filterTitle
|
case let .chatList(groupId):
|
||||||
} else if self.groupId == .root {
|
if groupId == .root {
|
||||||
title = self.presentationData.strings.DialogList_Title
|
title = self.presentationData.strings.DialogList_Title
|
||||||
} else {
|
} else {
|
||||||
title = self.presentationData.strings.ChatList_ArchivedChatsTitle
|
title = self.presentationData.strings.ChatList_ArchivedChatsTitle
|
||||||
|
}
|
||||||
|
case let .forum(peerId):
|
||||||
|
//TODO:localize
|
||||||
|
title = "Forum"
|
||||||
|
|
||||||
|
self.forumChannelTracker = ForumChannelTopics(account: self.context.account, peerId: peerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.titleView.title = NetworkStatusTitle(text: title, activity: false, hasProxy: false, connectsViaProxy: false, isPasscodeSet: false, isManuallyLocked: false, peerStatus: nil)
|
self.titleView.title = NetworkStatusTitle(text: title, activity: false, hasProxy: false, connectsViaProxy: false, isPasscodeSet: false, isManuallyLocked: false, peerStatus: nil)
|
||||||
@ -229,40 +235,45 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !previewing {
|
if !previewing {
|
||||||
if self.groupId == .root && self.filter == nil {
|
switch self.location {
|
||||||
self.tabBarItem.title = self.presentationData.strings.DialogList_Title
|
case let .chatList(groupId):
|
||||||
|
if groupId == .root {
|
||||||
let icon: UIImage?
|
self.tabBarItem.title = self.presentationData.strings.DialogList_Title
|
||||||
if useSpecialTabBarIcons() {
|
|
||||||
icon = UIImage(bundleImageName: "Chat List/Tabs/Holiday/IconChats")
|
let icon: UIImage?
|
||||||
|
if useSpecialTabBarIcons() {
|
||||||
|
icon = UIImage(bundleImageName: "Chat List/Tabs/Holiday/IconChats")
|
||||||
|
} else {
|
||||||
|
icon = UIImage(bundleImageName: "Chat List/Tabs/IconChats")
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tabBarItem.image = icon
|
||||||
|
self.tabBarItem.selectedImage = icon
|
||||||
|
if !self.presentationData.reduceMotion {
|
||||||
|
self.tabBarItem.animationName = "TabChats"
|
||||||
|
self.tabBarItem.animationOffset = CGPoint(x: 0.0, y: UIScreenPixel)
|
||||||
|
}
|
||||||
|
|
||||||
|
let leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(self.editPressed))
|
||||||
|
leftBarButtonItem.accessibilityLabel = self.presentationData.strings.Common_Edit
|
||||||
|
self.navigationItem.leftBarButtonItem = leftBarButtonItem
|
||||||
|
|
||||||
|
let rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationComposeIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.composePressed))
|
||||||
|
rightBarButtonItem.accessibilityLabel = self.presentationData.strings.VoiceOver_Navigation_Compose
|
||||||
|
self.navigationItem.rightBarButtonItem = rightBarButtonItem
|
||||||
|
let backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.DialogList_Title, style: .plain, target: nil, action: nil)
|
||||||
|
backBarButtonItem.accessibilityLabel = self.presentationData.strings.Common_Back
|
||||||
|
self.navigationItem.backBarButtonItem = backBarButtonItem
|
||||||
} else {
|
} else {
|
||||||
icon = UIImage(bundleImageName: "Chat List/Tabs/IconChats")
|
let rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(self.editPressed))
|
||||||
|
rightBarButtonItem.accessibilityLabel = self.presentationData.strings.Common_Edit
|
||||||
|
self.navigationItem.rightBarButtonItem = rightBarButtonItem
|
||||||
|
let backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||||
|
backBarButtonItem.accessibilityLabel = self.presentationData.strings.Common_Back
|
||||||
|
self.navigationItem.backBarButtonItem = backBarButtonItem
|
||||||
}
|
}
|
||||||
|
case .forum:
|
||||||
self.tabBarItem.image = icon
|
break
|
||||||
self.tabBarItem.selectedImage = icon
|
|
||||||
if !self.presentationData.reduceMotion {
|
|
||||||
self.tabBarItem.animationName = "TabChats"
|
|
||||||
self.tabBarItem.animationOffset = CGPoint(x: 0.0, y: UIScreenPixel)
|
|
||||||
}
|
|
||||||
|
|
||||||
let leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(self.editPressed))
|
|
||||||
leftBarButtonItem.accessibilityLabel = self.presentationData.strings.Common_Edit
|
|
||||||
self.navigationItem.leftBarButtonItem = leftBarButtonItem
|
|
||||||
|
|
||||||
let rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationComposeIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.composePressed))
|
|
||||||
rightBarButtonItem.accessibilityLabel = self.presentationData.strings.VoiceOver_Navigation_Compose
|
|
||||||
self.navigationItem.rightBarButtonItem = rightBarButtonItem
|
|
||||||
let backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.DialogList_Title, style: .plain, target: nil, action: nil)
|
|
||||||
backBarButtonItem.accessibilityLabel = self.presentationData.strings.Common_Back
|
|
||||||
self.navigationItem.backBarButtonItem = backBarButtonItem
|
|
||||||
} else {
|
|
||||||
let rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(self.editPressed))
|
|
||||||
rightBarButtonItem.accessibilityLabel = self.presentationData.strings.Common_Edit
|
|
||||||
self.navigationItem.rightBarButtonItem = rightBarButtonItem
|
|
||||||
let backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
|
||||||
backBarButtonItem.accessibilityLabel = self.presentationData.strings.Common_Back
|
|
||||||
self.navigationItem.backBarButtonItem = backBarButtonItem
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,9 +340,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
|
|
||||||
let peerStatus: Signal<NetworkStatusTitle.Status?, NoError>
|
let peerStatus: Signal<NetworkStatusTitle.Status?, NoError>
|
||||||
if filter != nil || groupId != .root {
|
switch self.location {
|
||||||
peerStatus = .single(nil)
|
case .chatList(.root):
|
||||||
} else {
|
|
||||||
peerStatus = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
peerStatus = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||||
|> map { peer -> NetworkStatusTitle.Status? in
|
|> map { peer -> NetworkStatusTitle.Status? in
|
||||||
guard case let .user(user) = peer else {
|
guard case let .user(user) = peer else {
|
||||||
@ -346,6 +356,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> distinctUntilChanged
|
|> distinctUntilChanged
|
||||||
|
default:
|
||||||
|
peerStatus = .single(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
let previousEditingAndNetworkStateValue = Atomic<(Bool, AccountNetworkState)?>(value: nil)
|
let previousEditingAndNetworkStateValue = Atomic<(Bool, AccountNetworkState)?>(value: nil)
|
||||||
@ -360,14 +372,20 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
).start(next: { [weak self] networkState, proxy, passcode, stateAndFilterId, isReorderingTabs, peerStatus in
|
).start(next: { [weak self] networkState, proxy, passcode, stateAndFilterId, isReorderingTabs, peerStatus in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let defaultTitle: String
|
let defaultTitle: String
|
||||||
if strongSelf.groupId == .root {
|
switch strongSelf.location {
|
||||||
defaultTitle = strongSelf.presentationData.strings.DialogList_Title
|
case let .chatList(groupId):
|
||||||
} else {
|
if groupId == .root {
|
||||||
defaultTitle = strongSelf.presentationData.strings.ChatList_ArchivedChatsTitle
|
defaultTitle = strongSelf.presentationData.strings.DialogList_Title
|
||||||
|
} else {
|
||||||
|
defaultTitle = strongSelf.presentationData.strings.ChatList_ArchivedChatsTitle
|
||||||
|
}
|
||||||
|
case .forum:
|
||||||
|
//TODO:localize
|
||||||
|
defaultTitle = "Forum"
|
||||||
}
|
}
|
||||||
let previousEditingAndNetworkState = previousEditingAndNetworkStateValue.swap((stateAndFilterId.state.editing, networkState))
|
let previousEditingAndNetworkState = previousEditingAndNetworkStateValue.swap((stateAndFilterId.state.editing, networkState))
|
||||||
if stateAndFilterId.state.editing {
|
if stateAndFilterId.state.editing {
|
||||||
if strongSelf.groupId == .root {
|
if case .chatList(.root) = strongSelf.location {
|
||||||
strongSelf.navigationItem.setRightBarButton(nil, animated: true)
|
strongSelf.navigationItem.setRightBarButton(nil, animated: true)
|
||||||
}
|
}
|
||||||
let title = !stateAndFilterId.state.selectedPeerIds.isEmpty ? strongSelf.presentationData.strings.ChatList_SelectedChats(Int32(stateAndFilterId.state.selectedPeerIds.count)) : defaultTitle
|
let title = !stateAndFilterId.state.selectedPeerIds.isEmpty ? strongSelf.presentationData.strings.ChatList_SelectedChats(Int32(stateAndFilterId.state.selectedPeerIds.count)) : defaultTitle
|
||||||
@ -380,7 +398,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
strongSelf.titleView.setTitle(NetworkStatusTitle(text: title, activity: false, hasProxy: false, connectsViaProxy: false, isPasscodeSet: false, isManuallyLocked: false, peerStatus: peerStatus), animated: animated)
|
strongSelf.titleView.setTitle(NetworkStatusTitle(text: title, activity: false, hasProxy: false, connectsViaProxy: false, isPasscodeSet: false, isManuallyLocked: false, peerStatus: peerStatus), animated: animated)
|
||||||
} else if isReorderingTabs {
|
} else if isReorderingTabs {
|
||||||
if strongSelf.groupId == .root {
|
if case .chatList(.root) = strongSelf.location {
|
||||||
strongSelf.navigationItem.setRightBarButton(nil, animated: true)
|
strongSelf.navigationItem.setRightBarButton(nil, animated: true)
|
||||||
}
|
}
|
||||||
let leftBarButtonItem = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Done, style: .done, target: strongSelf, action: #selector(strongSelf.reorderingDonePressed))
|
let leftBarButtonItem = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Done, style: .done, target: strongSelf, action: #selector(strongSelf.reorderingDonePressed))
|
||||||
@ -403,7 +421,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var isRoot = false
|
var isRoot = false
|
||||||
if case .root = strongSelf.groupId {
|
if case .chatList(.root) = strongSelf.location {
|
||||||
isRoot = true
|
isRoot = true
|
||||||
|
|
||||||
if isReorderingTabs {
|
if isReorderingTabs {
|
||||||
@ -461,7 +479,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
case .online:
|
case .online:
|
||||||
strongSelf.titleView.setTitle(NetworkStatusTitle(text: defaultTitle, activity: false, hasProxy: isRoot && hasProxy, connectsViaProxy: connectsViaProxy, isPasscodeSet: isRoot && isPasscodeSet, isManuallyLocked: isRoot && isManuallyLocked, peerStatus: peerStatus), animated: (previousEditingAndNetworkState?.0 ?? false) != stateAndFilterId.state.editing)
|
strongSelf.titleView.setTitle(NetworkStatusTitle(text: defaultTitle, activity: false, hasProxy: isRoot && hasProxy, connectsViaProxy: connectsViaProxy, isPasscodeSet: isRoot && isPasscodeSet, isManuallyLocked: isRoot && isManuallyLocked, peerStatus: peerStatus), animated: (previousEditingAndNetworkState?.0 ?? false) != stateAndFilterId.state.editing)
|
||||||
}
|
}
|
||||||
if groupId == .root && filter == nil && checkProxy {
|
if case .chatList(.root) = location, checkProxy {
|
||||||
if strongSelf.proxyUnavailableTooltipController == nil && !strongSelf.didShowProxyUnavailableTooltipController && strongSelf.isNodeLoaded && strongSelf.displayNode.view.window != nil && strongSelf.navigationController?.topViewController === self {
|
if strongSelf.proxyUnavailableTooltipController == nil && !strongSelf.didShowProxyUnavailableTooltipController && strongSelf.isNodeLoaded && strongSelf.displayNode.view.window != nil && strongSelf.navigationController?.topViewController === self {
|
||||||
strongSelf.didShowProxyUnavailableTooltipController = true
|
strongSelf.didShowProxyUnavailableTooltipController = true
|
||||||
let tooltipController = TooltipController(content: .text(strongSelf.presentationData.strings.Proxy_TooltipUnavailable), baseFontSize: strongSelf.presentationData.listsFontSize.baseDisplaySize, timeout: 60.0, dismissByTapOutside: true)
|
let tooltipController = TooltipController(content: .text(strongSelf.presentationData.strings.Proxy_TooltipUnavailable), baseFontSize: strongSelf.presentationData.listsFontSize.baseDisplaySize, timeout: 60.0, dismissByTapOutside: true)
|
||||||
@ -807,7 +825,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.filter == nil, case .root = self.groupId {
|
if case .chatList(.root) = self.location {
|
||||||
self.chatListDisplayNode.containerNode.currentItemFilterUpdated = { [weak self] filter, fraction, transition, force in
|
self.chatListDisplayNode.containerNode.currentItemFilterUpdated = { [weak self] filter, fraction, transition, force in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -890,7 +908,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateThemeAndStrings() {
|
private func updateThemeAndStrings() {
|
||||||
if case .root = self.groupId {
|
if case .chatList(.root) = self.location {
|
||||||
self.tabBarItem.title = self.presentationData.strings.DialogList_Title
|
self.tabBarItem.title = self.presentationData.strings.DialogList_Title
|
||||||
let backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.DialogList_Title, style: .plain, target: nil, action: nil)
|
let backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.DialogList_Title, style: .plain, target: nil, action: nil)
|
||||||
backBarButtonItem.accessibilityLabel = self.presentationData.strings.Common_Back
|
backBarButtonItem.accessibilityLabel = self.presentationData.strings.Common_Back
|
||||||
@ -917,7 +935,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
editItem = UIBarButtonItem(title: self.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(self.editPressed))
|
editItem = UIBarButtonItem(title: self.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(self.editPressed))
|
||||||
editItem.accessibilityLabel = self.presentationData.strings.Common_Edit
|
editItem.accessibilityLabel = self.presentationData.strings.Common_Edit
|
||||||
}
|
}
|
||||||
if self.groupId == .root && self.filter == nil {
|
if case .chatList(.root) = self.location {
|
||||||
self.navigationItem.leftBarButtonItem = editItem
|
self.navigationItem.leftBarButtonItem = editItem
|
||||||
let rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationComposeIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.composePressed))
|
let rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationComposeIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.composePressed))
|
||||||
rightBarButtonItem.accessibilityLabel = self.presentationData.strings.VoiceOver_Navigation_Compose
|
rightBarButtonItem.accessibilityLabel = self.presentationData.strings.VoiceOver_Navigation_Compose
|
||||||
@ -943,7 +961,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
|
|
||||||
override public func loadDisplayNode() {
|
override public func loadDisplayNode() {
|
||||||
self.displayNode = ChatListControllerNode(context: self.context, groupId: EngineChatList.Group(self.groupId), filter: self.filter, previewing: self.previewing, controlsHistoryPreload: self.controlsHistoryPreload, presentationData: self.presentationData, animationCache: self.animationCache, animationRenderer: self.animationRenderer, controller: self)
|
self.displayNode = ChatListControllerNode(context: self.context, location: self.location, previewing: self.previewing, controlsHistoryPreload: self.controlsHistoryPreload, presentationData: self.presentationData, animationCache: self.animationCache, animationRenderer: self.animationRenderer, controller: self)
|
||||||
|
|
||||||
self.chatListDisplayNode.navigationBar = self.navigationBar
|
self.chatListDisplayNode.navigationBar = self.navigationBar
|
||||||
|
|
||||||
@ -994,51 +1012,72 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
strongSelf.deletePeerChat(peerId: peerId, joined: joined)
|
strongSelf.deletePeerChat(peerId: peerId, joined: joined)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.chatListDisplayNode.containerNode.peerSelected = { [weak self] peer, animated, activateInput, promoInfo in
|
self.chatListDisplayNode.containerNode.peerSelected = { [weak self] peer, threadId, animated, activateInput, promoInfo in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let navigationController = strongSelf.navigationController as? NavigationController {
|
if let navigationController = strongSelf.navigationController as? NavigationController {
|
||||||
var scrollToEndIfExists = false
|
var scrollToEndIfExists = false
|
||||||
if let layout = strongSelf.validLayout, case .regular = layout.metrics.widthClass {
|
if let layout = strongSelf.validLayout, case .regular = layout.metrics.widthClass {
|
||||||
scrollToEndIfExists = true
|
scrollToEndIfExists = true
|
||||||
}
|
}
|
||||||
|
|
||||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peer.id), activateInput: (activateInput && !peer.isDeleted) ? .text : nil, scrollToEndIfExists: scrollToEndIfExists, animated: !scrollToEndIfExists, options: strongSelf.groupId == PeerGroupId.root ? [.removeOnMasterDetails] : [], parentGroupId: strongSelf.groupId, chatListFilter: strongSelf.chatListDisplayNode.containerNode.currentItemNode.chatListFilter?.id, completion: { [weak self] controller in
|
if case let .channel(channel) = peer, channel.flags.contains(.isForum), threadId == nil {
|
||||||
self?.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true)
|
strongSelf.context.sharedContext.navigateToForumChannel(context: strongSelf.context, peerId: channel.id, navigationController: navigationController)
|
||||||
if let promoInfo = promoInfo {
|
} else {
|
||||||
switch promoInfo {
|
if let threadId = threadId {
|
||||||
case .proxy:
|
let _ = strongSelf.context.sharedContext.navigateToForumThread(context: strongSelf.context, peerId: peer.id, threadId: threadId, navigationController: navigationController).start()
|
||||||
let _ = (ApplicationSpecificNotice.getProxyAdsAcknowledgment(accountManager: strongSelf.context.sharedContext.accountManager)
|
strongSelf.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true)
|
||||||
|> deliverOnMainQueue).start(next: { value in
|
} else {
|
||||||
guard let strongSelf = self else {
|
var navigationAnimationOptions: NavigationAnimationOptions = []
|
||||||
return
|
var groupId: EngineChatList.Group = .root
|
||||||
}
|
if case let .chatList(groupIdValue) = strongSelf.location {
|
||||||
if !value {
|
groupId = groupIdValue
|
||||||
controller.displayPromoAnnouncement(text: strongSelf.presentationData.strings.DialogList_AdNoticeAlert)
|
if case .root = groupIdValue {
|
||||||
let _ = ApplicationSpecificNotice.setProxyAdsAcknowledgment(accountManager: strongSelf.context.sharedContext.accountManager).start()
|
navigationAnimationOptions = .removeOnMasterDetails
|
||||||
}
|
}
|
||||||
})
|
|
||||||
case let .psa(type, _):
|
|
||||||
let _ = (ApplicationSpecificNotice.getPsaAcknowledgment(accountManager: strongSelf.context.sharedContext.accountManager, peerId: peer.id)
|
|
||||||
|> deliverOnMainQueue).start(next: { value in
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !value {
|
|
||||||
var text = strongSelf.presentationData.strings.ChatList_GenericPsaAlert
|
|
||||||
let key = "ChatList.PsaAlert.\(type)"
|
|
||||||
if let string = strongSelf.presentationData.strings.primaryComponent.dict[key] {
|
|
||||||
text = string
|
|
||||||
} else if let string = strongSelf.presentationData.strings.secondaryComponent?.dict[key] {
|
|
||||||
text = string
|
|
||||||
}
|
|
||||||
|
|
||||||
controller.displayPromoAnnouncement(text: text)
|
|
||||||
let _ = ApplicationSpecificNotice.setPsaAcknowledgment(accountManager: strongSelf.context.sharedContext.accountManager, peerId: peer.id).start()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let chatLocation: ChatLocation
|
||||||
|
chatLocation = .peer(id: peer.id)
|
||||||
|
|
||||||
|
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: chatLocation, activateInput: (activateInput && !peer.isDeleted) ? .text : nil, scrollToEndIfExists: scrollToEndIfExists, animated: !scrollToEndIfExists, options: navigationAnimationOptions, parentGroupId: groupId._asGroup(), chatListFilter: strongSelf.chatListDisplayNode.containerNode.currentItemNode.chatListFilter?.id, completion: { [weak self] controller in
|
||||||
|
self?.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true)
|
||||||
|
if let promoInfo = promoInfo {
|
||||||
|
switch promoInfo {
|
||||||
|
case .proxy:
|
||||||
|
let _ = (ApplicationSpecificNotice.getProxyAdsAcknowledgment(accountManager: strongSelf.context.sharedContext.accountManager)
|
||||||
|
|> deliverOnMainQueue).start(next: { value in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !value {
|
||||||
|
controller.displayPromoAnnouncement(text: strongSelf.presentationData.strings.DialogList_AdNoticeAlert)
|
||||||
|
let _ = ApplicationSpecificNotice.setProxyAdsAcknowledgment(accountManager: strongSelf.context.sharedContext.accountManager).start()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
case let .psa(type, _):
|
||||||
|
let _ = (ApplicationSpecificNotice.getPsaAcknowledgment(accountManager: strongSelf.context.sharedContext.accountManager, peerId: peer.id)
|
||||||
|
|> deliverOnMainQueue).start(next: { value in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !value {
|
||||||
|
var text = strongSelf.presentationData.strings.ChatList_GenericPsaAlert
|
||||||
|
let key = "ChatList.PsaAlert.\(type)"
|
||||||
|
if let string = strongSelf.presentationData.strings.primaryComponent.dict[key] {
|
||||||
|
text = string
|
||||||
|
} else if let string = strongSelf.presentationData.strings.secondaryComponent?.dict[key] {
|
||||||
|
text = string
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.displayPromoAnnouncement(text: text)
|
||||||
|
let _ = ApplicationSpecificNotice.setPsaAcknowledgment(accountManager: strongSelf.context.sharedContext.accountManager, peerId: peer.id).start()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}))
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1046,7 +1085,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
self.chatListDisplayNode.containerNode.groupSelected = { [weak self] groupId in
|
self.chatListDisplayNode.containerNode.groupSelected = { [weak self] groupId in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let navigationController = strongSelf.navigationController as? NavigationController {
|
if let navigationController = strongSelf.navigationController as? NavigationController {
|
||||||
let chatListController = ChatListControllerImpl(context: strongSelf.context, groupId: groupId._asGroup(), controlsHistoryPreload: false, enableDebugActions: false)
|
let chatListController = ChatListControllerImpl(context: strongSelf.context, location: .chatList(groupId: groupId), controlsHistoryPreload: false, enableDebugActions: false)
|
||||||
chatListController.navigationPresentation = .master
|
chatListController.navigationPresentation = .master
|
||||||
navigationController.pushViewController(chatListController)
|
navigationController.pushViewController(chatListController)
|
||||||
strongSelf.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true)
|
strongSelf.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true)
|
||||||
@ -1081,11 +1120,15 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
if let layout = strongSelf.validLayout, case .regular = layout.metrics.widthClass {
|
if let layout = strongSelf.validLayout, case .regular = layout.metrics.widthClass {
|
||||||
scrollToEndIfExists = true
|
scrollToEndIfExists = true
|
||||||
}
|
}
|
||||||
|
var navigationAnimationOptions: NavigationAnimationOptions = []
|
||||||
|
if case .chatList(.root) = strongSelf.location {
|
||||||
|
navigationAnimationOptions = .removeOnMasterDetails
|
||||||
|
}
|
||||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: actualPeerId), subject: .message(id: .id(messageId), highlight: true, timecode: nil), purposefulAction: {
|
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: actualPeerId), subject: .message(id: .id(messageId), highlight: true, timecode: nil), purposefulAction: {
|
||||||
if deactivateOnAction {
|
if deactivateOnAction {
|
||||||
self?.deactivateSearch(animated: false)
|
self?.deactivateSearch(animated: false)
|
||||||
}
|
}
|
||||||
}, scrollToEndIfExists: scrollToEndIfExists, options: strongSelf.groupId == PeerGroupId.root ? [.removeOnMasterDetails] : []))
|
}, scrollToEndIfExists: scrollToEndIfExists, options: navigationAnimationOptions))
|
||||||
strongSelf.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true)
|
strongSelf.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1106,9 +1149,13 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
scrollToEndIfExists = true
|
scrollToEndIfExists = true
|
||||||
}
|
}
|
||||||
if let navigationController = strongSelf.navigationController as? NavigationController {
|
if let navigationController = strongSelf.navigationController as? NavigationController {
|
||||||
|
var navigationAnimationOptions: NavigationAnimationOptions = []
|
||||||
|
if case .chatList(.root) = strongSelf.location {
|
||||||
|
navigationAnimationOptions = .removeOnMasterDetails
|
||||||
|
}
|
||||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peer.id), purposefulAction: { [weak self] in
|
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id: peer.id), purposefulAction: { [weak self] in
|
||||||
self?.deactivateSearch(animated: false)
|
self?.deactivateSearch(animated: false)
|
||||||
}, scrollToEndIfExists: scrollToEndIfExists, options: strongSelf.groupId == PeerGroupId.root ? [.removeOnMasterDetails] : []))
|
}, scrollToEndIfExists: scrollToEndIfExists, options: navigationAnimationOptions))
|
||||||
strongSelf.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true)
|
strongSelf.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1211,7 +1258,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
|
|
||||||
var joined = false
|
var joined = false
|
||||||
if case let .peer(messages, _, _, _, _, _, _, _, _, _, _, _, _) = item.content, let message = messages.first {
|
if case let .peer(messages, _, _, _, _, _, _, _, _, _, _, _, _, _) = item.content, let message = messages.first {
|
||||||
for media in message.media {
|
for media in message.media {
|
||||||
if let action = media as? TelegramMediaAction, action.action == .peerJoined {
|
if let action = media as? TelegramMediaAction, action.action == .peerJoined {
|
||||||
joined = true
|
joined = true
|
||||||
@ -1221,11 +1268,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
|
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .groupReference(groupId, _, _, _, _):
|
case let .groupReference(groupId, _, _, _, _):
|
||||||
let chatListController = ChatListControllerImpl(context: strongSelf.context, groupId: groupId._asGroup(), controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: true, enableDebugActions: false)
|
let chatListController = ChatListControllerImpl(context: strongSelf.context, location: .chatList(groupId: groupId), controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: true, enableDebugActions: false)
|
||||||
chatListController.navigationPresentation = .master
|
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: groupId._asGroup(), chatListController: strongSelf) |> map { ContextController.Items(content: .list($0)) }, 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._asGroup(), chatListController: strongSelf) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
|
||||||
strongSelf.presentInGlobalOverlay(contextController)
|
strongSelf.presentInGlobalOverlay(contextController)
|
||||||
case let .peer(_, peer, _, _, _, _, _, _, _, promoInfo, _, _, _):
|
case let .peer(_, peer, _, _, _, _, _, _, _, _, promoInfo, _, _, _):
|
||||||
let source: ContextContentSource
|
let source: ContextContentSource
|
||||||
if let location = location {
|
if let location = location {
|
||||||
source = .location(ChatListContextLocationContentSource(controller: strongSelf, location: location))
|
source = .location(ChatListContextLocationContentSource(controller: strongSelf, location: location))
|
||||||
@ -1300,7 +1347,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var toolbar: Toolbar?
|
var toolbar: Toolbar?
|
||||||
if case .root = strongSelf.groupId {
|
if case .chatList(.root) = strongSelf.location {
|
||||||
if let (options, peerIds) = peerIdsAndOptions {
|
if let (options, peerIds) = peerIdsAndOptions {
|
||||||
let leftAction: ToolbarAction
|
let leftAction: ToolbarAction
|
||||||
switch options.read {
|
switch options.read {
|
||||||
@ -1567,21 +1614,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if let id = id {
|
|
||||||
items.append(.action(ContextMenuActionItem(text: "View as Feed", icon: { _ in
|
|
||||||
return nil
|
|
||||||
}, action: { c, f in
|
|
||||||
c.dismiss(completion: {
|
|
||||||
guard let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .feed(id: id), subject: nil, purposefulAction: {
|
|
||||||
}, scrollToEndIfExists: false, options: []))
|
|
||||||
})
|
|
||||||
})))
|
|
||||||
}*/
|
|
||||||
|
|
||||||
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatListHeaderBarContextExtractedContentSource(controller: strongSelf, sourceNode: sourceNode, keepInPlace: keepInPlace)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
|
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatListHeaderBarContextExtractedContentSource(controller: strongSelf, sourceNode: sourceNode, keepInPlace: keepInPlace)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
|
||||||
strongSelf.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
|
strongSelf.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
|
||||||
})
|
})
|
||||||
@ -1593,10 +1625,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
tabContextGesture(id, sourceNode, gesture, true, isDisabled)
|
tabContextGesture(id, sourceNode, gesture, true, isDisabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
if case .group = self.groupId {
|
if case .chatList(.root) = self.location {
|
||||||
self.ready.set(self.chatListDisplayNode.containerNode.ready)
|
|
||||||
} else {
|
|
||||||
self.ready.set(.never())
|
self.ready.set(.never())
|
||||||
|
} else {
|
||||||
|
self.ready.set(self.chatListDisplayNode.containerNode.ready)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.displayNodeDidLoad()
|
self.displayNodeDidLoad()
|
||||||
@ -1653,7 +1685,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
strongSelf.push(controller)
|
strongSelf.push(controller)
|
||||||
}
|
}
|
||||||
|
|
||||||
guard case .root = self.groupId else {
|
guard case .chatList(.root) = self.location else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1988,9 +2020,14 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc private func editPressed() {
|
@objc private func editPressed() {
|
||||||
|
if case .forum = self.location {
|
||||||
|
self.forumChannelTracker?.createTopic(title: "Topic#\(Int.random(in: 0 ..< 100000))")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let editItem = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.donePressed))
|
let editItem = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.donePressed))
|
||||||
editItem.accessibilityLabel = self.presentationData.strings.Common_Done
|
editItem.accessibilityLabel = self.presentationData.strings.Common_Done
|
||||||
if case .root = self.groupId, self.filter == nil {
|
if case .chatList(.root) = self.location {
|
||||||
self.navigationItem.setLeftBarButton(editItem, animated: true)
|
self.navigationItem.setLeftBarButton(editItem, animated: true)
|
||||||
(self.navigationController as? NavigationController)?.updateMasterDetailsBlackout(.details, transition: .animated(duration: 0.5, curve: .spring))
|
(self.navigationController as? NavigationController)?.updateMasterDetailsBlackout(.details, transition: .animated(duration: 0.5, curve: .spring))
|
||||||
} else {
|
} else {
|
||||||
@ -2122,7 +2159,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resolvedItems = filterItems
|
var resolvedItems = filterItems
|
||||||
if strongSelf.groupId != .root {
|
if case .chatList(.root) = strongSelf.location {
|
||||||
|
} else {
|
||||||
resolvedItems = []
|
resolvedItems = []
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2578,8 +2616,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
self?.chatListDisplayNode.containerNode.currentItemNode.setCurrentRemovingPeerId(nil)
|
self?.chatListDisplayNode.containerNode.currentItemNode.setCurrentRemovingPeerId(nil)
|
||||||
}
|
}
|
||||||
signal = self.context.engine.messages.togglePeersUnreadMarkInteractively(peerIds: Array(peerIds), setToValue: false)
|
signal = self.context.engine.messages.togglePeersUnreadMarkInteractively(peerIds: Array(peerIds), setToValue: false)
|
||||||
} else {
|
} else if case let .chatList(groupId) = self.location {
|
||||||
let groupId = self.groupId
|
|
||||||
let filterPredicate: ChatListFilterPredicate?
|
let filterPredicate: ChatListFilterPredicate?
|
||||||
if let filter = self.chatListDisplayNode.containerNode.currentItemNode.chatListFilter, case let .filter(_, _, _, data) = filter {
|
if let filter = self.chatListDisplayNode.containerNode.currentItemNode.chatListFilter, case let .filter(_, _, _, data) = filter {
|
||||||
filterPredicate = chatListFilterPredicate(filter: data)
|
filterPredicate = chatListFilterPredicate(filter: data)
|
||||||
@ -2587,13 +2624,15 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
filterPredicate = nil
|
filterPredicate = nil
|
||||||
}
|
}
|
||||||
var markItems: [(groupId: EngineChatList.Group, filterPredicate: ChatListFilterPredicate?)] = []
|
var markItems: [(groupId: EngineChatList.Group, filterPredicate: ChatListFilterPredicate?)] = []
|
||||||
markItems.append((EngineChatList.Group(groupId), filterPredicate))
|
markItems.append((groupId, filterPredicate))
|
||||||
if let filterPredicate = filterPredicate {
|
if let filterPredicate = filterPredicate {
|
||||||
for additionalGroupId in filterPredicate.includeAdditionalPeerGroupIds {
|
for additionalGroupId in filterPredicate.includeAdditionalPeerGroupIds {
|
||||||
markItems.append((EngineChatList.Group(additionalGroupId), filterPredicate))
|
markItems.append((EngineChatList.Group(additionalGroupId), filterPredicate))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
signal = self.context.engine.messages.markAllChatsAsReadInteractively(items: markItems)
|
signal = self.context.engine.messages.markAllChatsAsReadInteractively(items: markItems)
|
||||||
|
} else {
|
||||||
|
signal = .complete()
|
||||||
}
|
}
|
||||||
let _ = (signal
|
let _ = (signal
|
||||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||||
@ -2685,7 +2724,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
])
|
])
|
||||||
self.present(actionSheet, in: .window(.root))
|
self.present(actionSheet, in: .window(.root))
|
||||||
} else if case .middle = action, !peerIds.isEmpty {
|
} else if case .middle = action, !peerIds.isEmpty {
|
||||||
if case .root = self.groupId {
|
if case .chatList(.root) = self.location {
|
||||||
self.donePressed()
|
self.donePressed()
|
||||||
self.archiveChats(peerIds: Array(peerIds))
|
self.archiveChats(peerIds: Array(peerIds))
|
||||||
} else {
|
} else {
|
||||||
@ -3345,7 +3384,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
|
|
||||||
override public func setToolbar(_ toolbar: Toolbar?, transition: ContainedViewLayoutTransition) {
|
override public func setToolbar(_ toolbar: Toolbar?, transition: ContainedViewLayoutTransition) {
|
||||||
if case .root = self.groupId, self.filter == nil {
|
if case .chatList(.root) = self.location {
|
||||||
super.setToolbar(toolbar, transition: transition)
|
super.setToolbar(toolbar, transition: transition)
|
||||||
} else {
|
} else {
|
||||||
self.chatListDisplayNode.toolbar = toolbar
|
self.chatListDisplayNode.toolbar = toolbar
|
||||||
|
@ -182,8 +182,8 @@ private final class ChatListShimmerNode: ASDisplayNode {
|
|||||||
let peer1: EnginePeer = .user(TelegramUser(id: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(0)), accessHash: nil, firstName: "FirstName", lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil))
|
let peer1: EnginePeer = .user(TelegramUser(id: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(0)), accessHash: nil, firstName: "FirstName", lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil))
|
||||||
let timestamp1: Int32 = 100000
|
let timestamp1: Int32 = 100000
|
||||||
let peers: [EnginePeer.Id: EnginePeer] = [:]
|
let peers: [EnginePeer.Id: EnginePeer] = [:]
|
||||||
let interaction = ChatListNodeInteraction(context: context, animationCache: animationCache, animationRenderer: animationRenderer, activateSearch: {}, peerSelected: { _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
let interaction = ChatListNodeInteraction(context: context, animationCache: animationCache, animationRenderer: animationRenderer, 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
|
}, 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()
|
gesture?.cancel()
|
||||||
}, present: { _ in })
|
}, present: { _ in })
|
||||||
|
|
||||||
@ -213,7 +213,7 @@ private final class ChatListShimmerNode: ASDisplayNode {
|
|||||||
)
|
)
|
||||||
let readState = EnginePeerReadCounters()
|
let readState = EnginePeerReadCounters()
|
||||||
|
|
||||||
return ChatListItem(presentationData: chatListPresentationData, context: context, peerGroupId: .root, filterData: nil, index: EngineChatList.Item.Index(pinningIndex: 0, messageIndex: EngineMessage.Index(id: EngineMessage.Id(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(messages: [message], peer: EngineRenderedPeer(peer: peer1), combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, hasUnseenMentions: false, hasUnseenReactions: false, draftState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
return ChatListItem(presentationData: chatListPresentationData, context: context, chatListLocation: .chatList(groupId: .root), filterData: nil, index: .chatList(EngineChatList.Item.Index.ChatList(pinningIndex: 0, messageIndex: EngineMessage.Index(id: EngineMessage.Id(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1))), content: .peer(messages: [message], peer: EngineRenderedPeer(peer: peer1), threadInfo: nil, combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, hasUnseenMentions: false, hasUnseenReactions: false, draftState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemNodes: [ChatListItemNode] = []
|
var itemNodes: [ChatListItemNode] = []
|
||||||
@ -296,7 +296,7 @@ private final class ChatListContainerItemNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var validLayout: (CGSize, UIEdgeInsets, CGFloat)?
|
private var validLayout: (CGSize, UIEdgeInsets, CGFloat)?
|
||||||
|
|
||||||
init(context: AccountContext, groupId: EngineChatList.Group, filter: ChatListFilter?, previewing: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, becameEmpty: @escaping (ChatListFilter?) -> Void, emptyAction: @escaping (ChatListFilter?) -> Void) {
|
init(context: AccountContext, location: ChatListControllerLocation, filter: ChatListFilter?, previewing: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, becameEmpty: @escaping (ChatListFilter?) -> Void, emptyAction: @escaping (ChatListFilter?) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.animationCache = animationCache
|
self.animationCache = animationCache
|
||||||
self.animationRenderer = animationRenderer
|
self.animationRenderer = animationRenderer
|
||||||
@ -304,7 +304,7 @@ private final class ChatListContainerItemNode: ASDisplayNode {
|
|||||||
self.becameEmpty = becameEmpty
|
self.becameEmpty = becameEmpty
|
||||||
self.emptyAction = emptyAction
|
self.emptyAction = emptyAction
|
||||||
|
|
||||||
self.listNode = ChatListNode(context: context, groupId: groupId, chatListFilter: filter, previewing: previewing, fillPreloadItems: controlsHistoryPreload, mode: .chatList, theme: presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, animationCache: animationCache, animationRenderer: animationRenderer, disableAnimations: true)
|
self.listNode = ChatListNode(context: context, location: location, chatListFilter: filter, previewing: previewing, fillPreloadItems: controlsHistoryPreload, mode: .chatList, theme: presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, animationCache: animationCache, animationRenderer: animationRenderer, disableAnimations: true)
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -426,7 +426,7 @@ private final class ChatListContainerItemNode: ASDisplayNode {
|
|||||||
|
|
||||||
final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let groupId: EngineChatList.Group
|
private let location: ChatListControllerLocation
|
||||||
private let previewing: Bool
|
private let previewing: Bool
|
||||||
private let controlsHistoryPreload: Bool
|
private let controlsHistoryPreload: Bool
|
||||||
private let filterBecameEmpty: (ChatListFilter?) -> Void
|
private let filterBecameEmpty: (ChatListFilter?) -> Void
|
||||||
@ -523,8 +523,8 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
itemNode.listNode.deletePeerChat = { [weak self] peerId, joined in
|
itemNode.listNode.deletePeerChat = { [weak self] peerId, joined in
|
||||||
self?.deletePeerChat?(peerId, joined)
|
self?.deletePeerChat?(peerId, joined)
|
||||||
}
|
}
|
||||||
itemNode.listNode.peerSelected = { [weak self] peerId, animated, activateInput, promoInfo in
|
itemNode.listNode.peerSelected = { [weak self] peerId, threadId, animated, activateInput, promoInfo in
|
||||||
self?.peerSelected?(peerId, animated, activateInput, promoInfo)
|
self?.peerSelected?(peerId, threadId, animated, activateInput, promoInfo)
|
||||||
}
|
}
|
||||||
itemNode.listNode.groupSelected = { [weak self] groupId in
|
itemNode.listNode.groupSelected = { [weak self] groupId in
|
||||||
self?.groupSelected?(groupId)
|
self?.groupSelected?(groupId)
|
||||||
@ -581,7 +581,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
var toggleArchivedFolderHiddenByDefault: (() -> Void)?
|
var toggleArchivedFolderHiddenByDefault: (() -> Void)?
|
||||||
var hidePsa: ((EnginePeer.Id) -> Void)?
|
var hidePsa: ((EnginePeer.Id) -> Void)?
|
||||||
var deletePeerChat: ((EnginePeer.Id, Bool) -> Void)?
|
var deletePeerChat: ((EnginePeer.Id, Bool) -> Void)?
|
||||||
var peerSelected: ((EnginePeer, Bool, Bool, ChatListNodeEntryPromoInfo?) -> Void)?
|
var peerSelected: ((EnginePeer, Int64?, Bool, Bool, ChatListNodeEntryPromoInfo?) -> Void)?
|
||||||
var groupSelected: ((EngineChatList.Group) -> Void)?
|
var groupSelected: ((EngineChatList.Group) -> Void)?
|
||||||
var updatePeerGrouping: ((EnginePeer.Id, Bool) -> Void)?
|
var updatePeerGrouping: ((EnginePeer.Id, Bool) -> Void)?
|
||||||
var contentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)?
|
var contentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)?
|
||||||
@ -591,9 +591,9 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
var didBeginSelectingChats: (() -> Void)?
|
var didBeginSelectingChats: (() -> Void)?
|
||||||
var displayFilterLimit: (() -> Void)?
|
var displayFilterLimit: (() -> Void)?
|
||||||
|
|
||||||
init(context: AccountContext, groupId: EngineChatList.Group, previewing: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, filterBecameEmpty: @escaping (ChatListFilter?) -> Void, filterEmptyAction: @escaping (ChatListFilter?) -> Void) {
|
init(context: AccountContext, location: ChatListControllerLocation, previewing: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, filterBecameEmpty: @escaping (ChatListFilter?) -> Void, filterEmptyAction: @escaping (ChatListFilter?) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.groupId = groupId
|
self.location = location
|
||||||
self.previewing = previewing
|
self.previewing = previewing
|
||||||
self.filterBecameEmpty = filterBecameEmpty
|
self.filterBecameEmpty = filterBecameEmpty
|
||||||
self.filterEmptyAction = filterEmptyAction
|
self.filterEmptyAction = filterEmptyAction
|
||||||
@ -607,7 +607,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
let itemNode = ChatListContainerItemNode(context: self.context, groupId: self.groupId, filter: nil, previewing: self.previewing, controlsHistoryPreload: self.controlsHistoryPreload, presentationData: presentationData, animationCache: self.animationCache, animationRenderer: self.animationRenderer, becameEmpty: { [weak self] filter in
|
let itemNode = ChatListContainerItemNode(context: self.context, location: self.location, filter: nil, previewing: self.previewing, controlsHistoryPreload: self.controlsHistoryPreload, presentationData: presentationData, animationCache: self.animationCache, animationRenderer: self.animationRenderer, becameEmpty: { [weak self] filter in
|
||||||
self?.filterBecameEmpty(filter)
|
self?.filterBecameEmpty(filter)
|
||||||
}, emptyAction: { [weak self] filter in
|
}, emptyAction: { [weak self] filter in
|
||||||
self?.filterEmptyAction(filter)
|
self?.filterEmptyAction(filter)
|
||||||
@ -883,7 +883,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
itemNode.emptyNode?.restartAnimation()
|
itemNode.emptyNode?.restartAnimation()
|
||||||
completion?()
|
completion?()
|
||||||
} else if self.pendingItemNode == nil {
|
} else if self.pendingItemNode == nil {
|
||||||
let itemNode = ChatListContainerItemNode(context: self.context, groupId: self.groupId, filter: self.availableFilters[index].filter, previewing: self.previewing, controlsHistoryPreload: self.controlsHistoryPreload, presentationData: self.presentationData, animationCache: self.animationCache, animationRenderer: self.animationRenderer, becameEmpty: { [weak self] filter in
|
let itemNode = ChatListContainerItemNode(context: self.context, location: self.location, filter: self.availableFilters[index].filter, previewing: self.previewing, controlsHistoryPreload: self.controlsHistoryPreload, presentationData: self.presentationData, animationCache: self.animationCache, animationRenderer: self.animationRenderer, becameEmpty: { [weak self] filter in
|
||||||
self?.filterBecameEmpty(filter)
|
self?.filterBecameEmpty(filter)
|
||||||
}, emptyAction: { [weak self] filter in
|
}, emptyAction: { [weak self] filter in
|
||||||
self?.filterEmptyAction(filter)
|
self?.filterEmptyAction(filter)
|
||||||
@ -1011,7 +1011,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
validNodeIds.append(id)
|
validNodeIds.append(id)
|
||||||
|
|
||||||
if self.itemNodes[id] == nil && self.enableAdjacentFilterLoading && !self.disableItemNodeOperationsWhileAnimating {
|
if self.itemNodes[id] == nil && self.enableAdjacentFilterLoading && !self.disableItemNodeOperationsWhileAnimating {
|
||||||
let itemNode = ChatListContainerItemNode(context: self.context, groupId: self.groupId, filter: self.availableFilters[i].filter, previewing: self.previewing, controlsHistoryPreload: self.controlsHistoryPreload, presentationData: self.presentationData, animationCache: self.animationCache, animationRenderer: self.animationRenderer, becameEmpty: { [weak self] filter in
|
let itemNode = ChatListContainerItemNode(context: self.context, location: self.location, filter: self.availableFilters[i].filter, previewing: self.previewing, controlsHistoryPreload: self.controlsHistoryPreload, presentationData: self.presentationData, animationCache: self.animationCache, animationRenderer: self.animationRenderer, becameEmpty: { [weak self] filter in
|
||||||
self?.filterBecameEmpty(filter)
|
self?.filterBecameEmpty(filter)
|
||||||
}, emptyAction: { [weak self] filter in
|
}, emptyAction: { [weak self] filter in
|
||||||
self?.filterEmptyAction(filter)
|
self?.filterEmptyAction(filter)
|
||||||
@ -1073,7 +1073,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
|
|
||||||
final class ChatListControllerNode: ASDisplayNode {
|
final class ChatListControllerNode: ASDisplayNode {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let groupId: EngineChatList.Group
|
private let location: ChatListControllerLocation
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
private let animationCache: AnimationCache
|
private let animationCache: AnimationCache
|
||||||
private let animationRenderer: MultiAnimationRenderer
|
private let animationRenderer: MultiAnimationRenderer
|
||||||
@ -1109,16 +1109,16 @@ final class ChatListControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
let debugListView = ListView()
|
let debugListView = ListView()
|
||||||
|
|
||||||
init(context: AccountContext, groupId: EngineChatList.Group, filter: ChatListFilter?, previewing: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, controller: ChatListControllerImpl) {
|
init(context: AccountContext, location: ChatListControllerLocation, previewing: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, controller: ChatListControllerImpl) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.groupId = groupId
|
self.location = location
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.animationCache = animationCache
|
self.animationCache = animationCache
|
||||||
self.animationRenderer = animationRenderer
|
self.animationRenderer = animationRenderer
|
||||||
|
|
||||||
var filterBecameEmpty: ((ChatListFilter?) -> Void)?
|
var filterBecameEmpty: ((ChatListFilter?) -> Void)?
|
||||||
var filterEmptyAction: ((ChatListFilter?) -> Void)?
|
var filterEmptyAction: ((ChatListFilter?) -> Void)?
|
||||||
self.containerNode = ChatListContainerNode(context: context, groupId: groupId, previewing: previewing, controlsHistoryPreload: controlsHistoryPreload, presentationData: presentationData, animationCache: animationCache, animationRenderer: animationRenderer, filterBecameEmpty: { filter in
|
self.containerNode = ChatListContainerNode(context: context, location: location, previewing: previewing, controlsHistoryPreload: controlsHistoryPreload, presentationData: presentationData, animationCache: animationCache, animationRenderer: animationRenderer, filterBecameEmpty: { filter in
|
||||||
filterBecameEmpty?(filter)
|
filterBecameEmpty?(filter)
|
||||||
}, filterEmptyAction: { filter in
|
}, filterEmptyAction: { filter in
|
||||||
filterEmptyAction?(filter)
|
filterEmptyAction?(filter)
|
||||||
@ -1145,7 +1145,7 @@ final class ChatListControllerNode: ASDisplayNode {
|
|||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if case .archive = strongSelf.groupId {
|
if case .chatList(.archive) = strongSelf.location {
|
||||||
strongSelf.dismissSelfIfCompletedPresentation?()
|
strongSelf.dismissSelfIfCompletedPresentation?()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1258,10 +1258,13 @@ final class ChatListControllerNode: ASDisplayNode {
|
|||||||
guard let (containerLayout, _, _, cleanNavigationBarHeight) = self.containerLayout, let navigationBar = self.navigationBar, self.searchDisplayController == nil else {
|
guard let (containerLayout, _, _, cleanNavigationBarHeight) = self.containerLayout, let navigationBar = self.navigationBar, self.searchDisplayController == nil else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
guard case let .chatList(groupId) = self.location else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
let filter: ChatListNodePeersFilter = []
|
let filter: ChatListNodePeersFilter = []
|
||||||
|
|
||||||
let contentNode = ChatListSearchContainerNode(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, filter: filter, groupId: self.groupId, displaySearchFilters: displaySearchFilters, hasDownloads: hasDownloads, initialFilter: initialFilter, openPeer: { [weak self] peer, _, dismissSearch in
|
let contentNode = ChatListSearchContainerNode(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, filter: filter, groupId: groupId, displaySearchFilters: displaySearchFilters, hasDownloads: hasDownloads, initialFilter: initialFilter, openPeer: { [weak self] peer, _, dismissSearch in
|
||||||
self?.requestOpenPeerFromSearch?(peer, dismissSearch)
|
self?.requestOpenPeerFromSearch?(peer, dismissSearch)
|
||||||
}, openDisabledPeer: { _ in
|
}, openDisabledPeer: { _ in
|
||||||
}, openRecentPeerOptions: { [weak self] peer in
|
}, openRecentPeerOptions: { [weak self] peer in
|
||||||
|
@ -505,9 +505,9 @@ 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: { contactPeer in
|
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 {
|
if case let .peer(maybePeer, maybeChatPeer) = contactPeer, let peer = maybePeer, let chatPeer = maybeChatPeer {
|
||||||
interaction.peerSelected(chatPeer, peer, nil)
|
interaction.peerSelected(chatPeer, nil, peer, nil)
|
||||||
} else {
|
} else {
|
||||||
interaction.peerSelected(peer, nil, nil)
|
interaction.peerSelected(peer, nil, nil, nil)
|
||||||
}
|
}
|
||||||
}, contextAction: peerContextAction.flatMap { peerContextAction in
|
}, contextAction: peerContextAction.flatMap { peerContextAction in
|
||||||
return { node, gesture, location in
|
return { node, gesture, location in
|
||||||
@ -592,9 +592,9 @@ 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: { contactPeer in
|
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 {
|
if case let .peer(maybePeer, maybeChatPeer) = contactPeer, let peer = maybePeer, let chatPeer = maybeChatPeer {
|
||||||
interaction.peerSelected(chatPeer, peer, nil)
|
interaction.peerSelected(chatPeer, nil, peer, nil)
|
||||||
} else {
|
} else {
|
||||||
interaction.peerSelected(peer, nil, nil)
|
interaction.peerSelected(peer, nil, nil, nil)
|
||||||
}
|
}
|
||||||
}, contextAction: peerContextAction.flatMap { peerContextAction in
|
}, contextAction: peerContextAction.flatMap { peerContextAction in
|
||||||
return { node, gesture, location in
|
return { node, gesture, location in
|
||||||
@ -658,7 +658,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: EnginePeer(peer.peer), chatPeer: EnginePeer(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
|
return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: EnginePeer(peer.peer), chatPeer: EnginePeer(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(EnginePeer(peer.peer), nil, nil)
|
interaction.peerSelected(EnginePeer(peer.peer), nil, nil, nil)
|
||||||
}, contextAction: peerContextAction.flatMap { peerContextAction in
|
}, contextAction: peerContextAction.flatMap { peerContextAction in
|
||||||
return { node, gesture, location in
|
return { node, gesture, location in
|
||||||
peerContextAction(EnginePeer(peer.peer), .search(nil), node, gesture, location)
|
peerContextAction(EnginePeer(peer.peer), .search(nil), node, gesture, location)
|
||||||
@ -694,7 +694,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
if isMedia {
|
if isMedia {
|
||||||
return ListMessageItem(presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: .builtin(WallpaperSettings())), fontSize: presentationData.fontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: true, largeEmoji: false, chatBubbleCorners: PresentationChatBubbleCorners(mainRadius: 0.0, auxiliaryRadius: 0.0, mergeBubbleCorners: false)), context: context, chatLocation: .peer(id: peer.peerId), interaction: listInteraction, message: message._asMessage(), selection: selection, displayHeader: enableHeaders && !displayCustomHeader, customHeader: key == .downloads ? header : nil, hintIsLink: tagMask == .webPage, isGlobalSearchResult: key != .downloads, isDownloadList: key == .downloads)
|
return ListMessageItem(presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: .builtin(WallpaperSettings())), fontSize: presentationData.fontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: true, largeEmoji: false, chatBubbleCorners: PresentationChatBubbleCorners(mainRadius: 0.0, auxiliaryRadius: 0.0, mergeBubbleCorners: false)), context: context, chatLocation: .peer(id: peer.peerId), interaction: listInteraction, message: message._asMessage(), selection: selection, displayHeader: enableHeaders && !displayCustomHeader, customHeader: key == .downloads ? header : nil, hintIsLink: tagMask == .webPage, isGlobalSearchResult: key != .downloads, isDownloadList: key == .downloads)
|
||||||
} else {
|
} else {
|
||||||
return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, filterData: nil, index: EngineChatList.Item.Index(pinningIndex: nil, messageIndex: message.index), content: .peer(messages: [message], peer: peer, combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, hasUnseenMentions: false, hasUnseenReactions: false, draftState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: true, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: tagMask == nil ? header : nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
return ChatListItem(presentationData: presentationData, context: context, chatListLocation: .chatList(groupId: .root), filterData: nil, index: .chatList(EngineChatList.Item.Index.ChatList(pinningIndex: nil, messageIndex: message.index)), content: .peer(messages: [message], peer: peer, threadInfo: nil, combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, hasUnseenMentions: false, hasUnseenReactions: false, draftState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: true, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: tagMask == nil ? header : nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
||||||
}
|
}
|
||||||
case let .addContact(phoneNumber, theme, strings):
|
case let .addContact(phoneNumber, theme, strings):
|
||||||
return ContactsAddItem(theme: theme, strings: strings, phoneNumber: phoneNumber, header: ChatListSearchItemHeader(type: .phoneNumber, theme: theme, strings: strings, actionTitle: nil, action: nil), action: {
|
return ContactsAddItem(theme: theme, strings: strings, phoneNumber: phoneNumber, header: ChatListSearchItemHeader(type: .phoneNumber, theme: theme, strings: strings, actionTitle: nil, action: nil), action: {
|
||||||
@ -1718,7 +1718,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let chatListInteraction = ChatListNodeInteraction(context: context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, activateSearch: {
|
let chatListInteraction = ChatListNodeInteraction(context: context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, activateSearch: {
|
||||||
}, peerSelected: { [weak self] peer, chatPeer, _ in
|
}, peerSelected: { [weak self] peer, _, chatPeer, _ in
|
||||||
interaction.dismissInput()
|
interaction.dismissInput()
|
||||||
interaction.openPeer(peer, chatPeer, false)
|
interaction.openPeer(peer, chatPeer, false)
|
||||||
let _ = context.engine.peers.addRecentlySearchedPeer(peerId: peer.id).start()
|
let _ = context.engine.peers.addRecentlySearchedPeer(peerId: peer.id).start()
|
||||||
@ -1727,7 +1727,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
}, togglePeerSelected: { _ in
|
}, togglePeerSelected: { _ in
|
||||||
}, togglePeersSelection: { _, _ in
|
}, togglePeersSelection: { _, _ in
|
||||||
}, additionalCategorySelected: { _ in
|
}, additionalCategorySelected: { _ in
|
||||||
}, messageSelected: { [weak self] peer, message, _ in
|
}, messageSelected: { [weak self] peer, _, message, _ in
|
||||||
interaction.dismissInput()
|
interaction.dismissInput()
|
||||||
if let strongSelf = self, let peer = message.peers[message.id.peerId] {
|
if let strongSelf = self, let peer = message.peers[message.id.peerId] {
|
||||||
interaction.openMessage(EnginePeer(peer), message.id, strongSelf.key == .chats)
|
interaction.openMessage(EnginePeer(peer), message.id, strongSelf.key == .chats)
|
||||||
@ -1752,7 +1752,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(messages, peer, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(messages, peer, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
if let peer = peer.peer, let message = messages.first {
|
if let peer = peer.peer, let message = messages.first {
|
||||||
peerContextAction(peer, .search(message.id), node, gesture, location)
|
peerContextAction(peer, .search(message.id), node, gesture, location)
|
||||||
}
|
}
|
||||||
@ -2794,7 +2794,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
bounds = selectedItemNode.bounds
|
bounds = selectedItemNode.bounds
|
||||||
}
|
}
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(messages, peer, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(messages, peer, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
return (selectedItemNode.view, bounds, messages.last?.id ?? peer.peerId)
|
return (selectedItemNode.view, bounds, messages.last?.id ?? peer.peerId)
|
||||||
case let .groupReference(groupId, _, _, _, _):
|
case let .groupReference(groupId, _, _, _, _):
|
||||||
return (selectedItemNode.view, bounds, groupId)
|
return (selectedItemNode.view, bounds, groupId)
|
||||||
@ -2950,8 +2950,8 @@ private final class ChatListSearchShimmerNode: ASDisplayNode {
|
|||||||
let timestamp1: Int32 = 100000
|
let timestamp1: Int32 = 100000
|
||||||
var peers: [EnginePeer.Id: EnginePeer] = [:]
|
var peers: [EnginePeer.Id: EnginePeer] = [:]
|
||||||
peers[peer1.id] = peer1
|
peers[peer1.id] = peer1
|
||||||
let interaction = ChatListNodeInteraction(context: context, animationCache: animationCache, animationRenderer: animationRenderer, activateSearch: {}, peerSelected: { _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
let interaction = ChatListNodeInteraction(context: context, animationCache: animationCache, animationRenderer: animationRenderer, 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
|
}, 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()
|
gesture?.cancel()
|
||||||
}, present: { _ in })
|
}, present: { _ in })
|
||||||
|
|
||||||
@ -2982,7 +2982,7 @@ private final class ChatListSearchShimmerNode: ASDisplayNode {
|
|||||||
associatedMedia: [:]
|
associatedMedia: [:]
|
||||||
)
|
)
|
||||||
let readState = EnginePeerReadCounters()
|
let readState = EnginePeerReadCounters()
|
||||||
return ChatListItem(presentationData: chatListPresentationData, context: context, peerGroupId: .root, filterData: nil, index: EngineChatList.Item.Index(pinningIndex: 0, messageIndex: EngineMessage.Index(id: EngineMessage.Id(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(messages: [message], peer: EngineRenderedPeer(peer: peer1), combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, hasUnseenMentions: false, hasUnseenReactions: false, draftState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
return ChatListItem(presentationData: chatListPresentationData, context: context, chatListLocation: .chatList(groupId: .root), filterData: nil, index: .chatList(EngineChatList.Item.Index.ChatList(pinningIndex: 0, messageIndex: EngineMessage.Index(id: EngineMessage.Id(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1))), content: .peer(messages: [message], peer: EngineRenderedPeer(peer: peer1), threadInfo: nil, combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, hasUnseenMentions: false, hasUnseenReactions: false, draftState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
||||||
case .media:
|
case .media:
|
||||||
return nil
|
return nil
|
||||||
case .links:
|
case .links:
|
||||||
|
@ -49,12 +49,12 @@ public enum ChatListItemContent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case peer(messages: [EngineMessage], peer: EngineRenderedPeer, combinedReadState: EnginePeerReadCounters?, isRemovedFromTotalUnreadCount: Bool, presence: EnginePeer.Presence?, hasUnseenMentions: Bool, hasUnseenReactions: Bool, draftState: DraftState?, inputActivities: [(EnginePeer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, ignoreUnreadBadge: Bool, displayAsMessage: Bool, hasFailedMessages: Bool)
|
case peer(messages: [EngineMessage], peer: EngineRenderedPeer, threadInfo: EngineMessageHistoryThreads.Info?, combinedReadState: EnginePeerReadCounters?, isRemovedFromTotalUnreadCount: Bool, presence: EnginePeer.Presence?, hasUnseenMentions: Bool, hasUnseenReactions: Bool, draftState: DraftState?, inputActivities: [(EnginePeer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, ignoreUnreadBadge: Bool, displayAsMessage: Bool, hasFailedMessages: Bool)
|
||||||
case groupReference(groupId: EngineChatList.Group, peers: [EngineChatList.GroupItem.Item], message: EngineMessage?, unreadCount: Int, hiddenByDefault: Bool)
|
case groupReference(groupId: EngineChatList.Group, peers: [EngineChatList.GroupItem.Item], message: EngineMessage?, unreadCount: Int, hiddenByDefault: Bool)
|
||||||
|
|
||||||
public var chatLocation: ChatLocation? {
|
public var chatLocation: ChatLocation? {
|
||||||
switch self {
|
switch self {
|
||||||
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
return .peer(id: peer.peerId)
|
return .peer(id: peer.peerId)
|
||||||
case .groupReference:
|
case .groupReference:
|
||||||
return nil
|
return nil
|
||||||
@ -65,7 +65,7 @@ public enum ChatListItemContent {
|
|||||||
public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour {
|
public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour {
|
||||||
let presentationData: ChatListPresentationData
|
let presentationData: ChatListPresentationData
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let peerGroupId: EngineChatList.Group
|
let chatListLocation: ChatListControllerLocation
|
||||||
let filterData: ChatListItemFilterData?
|
let filterData: ChatListItemFilterData?
|
||||||
let index: EngineChatList.Item.Index
|
let index: EngineChatList.Item.Index
|
||||||
public let content: ChatListItemContent
|
public let content: ChatListItemContent
|
||||||
@ -85,12 +85,17 @@ public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour {
|
|||||||
let header: ListViewItemHeader?
|
let header: ListViewItemHeader?
|
||||||
|
|
||||||
public var isPinned: Bool {
|
public var isPinned: Bool {
|
||||||
return self.index.pinningIndex != nil
|
switch self.index {
|
||||||
|
case let .chatList(index):
|
||||||
|
return index.pinningIndex != nil
|
||||||
|
case .forum:
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(presentationData: ChatListPresentationData, context: AccountContext, peerGroupId: EngineChatList.Group, filterData: ChatListItemFilterData?, index: EngineChatList.Item.Index, content: ChatListItemContent, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, header: ListViewItemHeader?, enableContextActions: Bool, hiddenOffset: Bool, interaction: ChatListNodeInteraction) {
|
public init(presentationData: ChatListPresentationData, context: AccountContext, chatListLocation: ChatListControllerLocation, filterData: ChatListItemFilterData?, index: EngineChatList.Item.Index, content: ChatListItemContent, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, header: ListViewItemHeader?, enableContextActions: Bool, hiddenOffset: Bool, interaction: ChatListNodeInteraction) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.peerGroupId = peerGroupId
|
self.chatListLocation = chatListLocation
|
||||||
self.filterData = filterData
|
self.filterData = filterData
|
||||||
self.context = context
|
self.context = context
|
||||||
self.index = index
|
self.index = index
|
||||||
@ -153,13 +158,17 @@ public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour {
|
|||||||
|
|
||||||
public func selected(listView: ListView) {
|
public func selected(listView: ListView) {
|
||||||
switch self.content {
|
switch self.content {
|
||||||
case let .peer(messages, peer, _, _, _, _, _, _, _, promoInfo, _, _, _):
|
case let .peer(messages, peer, _, _, _, _, _, _, _, _, promoInfo, _, _, _):
|
||||||
if let message = messages.last, let peer = peer.peer {
|
if let message = messages.last, let peer = peer.peer {
|
||||||
self.interaction.messageSelected(peer, message, promoInfo)
|
var threadId: Int64?
|
||||||
|
if case let .forum(_, threadIdValue, _, _) = self.index {
|
||||||
|
threadId = threadIdValue
|
||||||
|
}
|
||||||
|
self.interaction.messageSelected(peer, threadId, message, promoInfo)
|
||||||
} else if let peer = peer.peer {
|
} else if let peer = peer.peer {
|
||||||
self.interaction.peerSelected(peer, nil, promoInfo)
|
self.interaction.peerSelected(peer, nil, nil, promoInfo)
|
||||||
} else if let peer = peer.peers[peer.peerId] {
|
} else if let peer = peer.peers[peer.peerId] {
|
||||||
self.interaction.peerSelected(peer, nil, promoInfo)
|
self.interaction.peerSelected(peer, nil, nil, promoInfo)
|
||||||
}
|
}
|
||||||
case let .groupReference(groupId, _, _, _, _):
|
case let .groupReference(groupId, _, _, _, _):
|
||||||
self.interaction.groupSelected(groupId)
|
self.interaction.groupSelected(groupId)
|
||||||
@ -184,7 +193,7 @@ public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour {
|
|||||||
}
|
}
|
||||||
var nextIsPinned = false
|
var nextIsPinned = false
|
||||||
if let nextItem = nextItem as? ChatListItem {
|
if let nextItem = nextItem as? ChatListItem {
|
||||||
if nextItem.index.pinningIndex != nil {
|
if case let .chatList(nextIndex) = nextItem.index, nextIndex.pinningIndex != nil {
|
||||||
nextIsPinned = true
|
nextIsPinned = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -242,10 +251,11 @@ public struct ChatListItemFilterData: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func revealOptions(strings: PresentationStrings, theme: PresentationTheme, isPinned: Bool, isMuted: Bool?, groupId: EngineChatList.Group, peerId: EnginePeer.Id, accountPeerId: EnginePeer.Id, canDelete: Bool, isEditing: Bool, filterData: ChatListItemFilterData?) -> [ItemListRevealOption] {
|
private func revealOptions(strings: PresentationStrings, theme: PresentationTheme, isPinned: Bool, isMuted: Bool?, location: ChatListControllerLocation, peerId: EnginePeer.Id, accountPeerId: EnginePeer.Id, canDelete: Bool, isEditing: Bool, filterData: ChatListItemFilterData?) -> [ItemListRevealOption] {
|
||||||
var options: [ItemListRevealOption] = []
|
var options: [ItemListRevealOption] = []
|
||||||
if !isEditing {
|
if !isEditing {
|
||||||
if case .archive = groupId {
|
if case .forum = location {
|
||||||
|
} else if case .chatList(.archive) = location {
|
||||||
if isPinned {
|
if isPinned {
|
||||||
options.append(ItemListRevealOption(key: RevealOptionKey.unpin.rawValue, title: strings.DialogList_Unpin, icon: unpinIcon, color: theme.list.itemDisclosureActions.constructive.fillColor, textColor: theme.list.itemDisclosureActions.constructive.foregroundColor))
|
options.append(ItemListRevealOption(key: RevealOptionKey.unpin.rawValue, title: strings.DialogList_Unpin, icon: unpinIcon, color: theme.list.itemDisclosureActions.constructive.fillColor, textColor: theme.list.itemDisclosureActions.constructive.foregroundColor))
|
||||||
} else {
|
} else {
|
||||||
@ -272,10 +282,12 @@ private func revealOptions(strings: PresentationStrings, theme: PresentationThem
|
|||||||
canArchive = true
|
canArchive = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if case .root = groupId {
|
if case let .chatList(groupId) = location {
|
||||||
canArchive = true
|
if case .root = groupId {
|
||||||
} else {
|
canArchive = true
|
||||||
canUnarchive = true
|
} else {
|
||||||
|
canUnarchive = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if canArchive {
|
if canArchive {
|
||||||
@ -301,8 +313,8 @@ private func groupReferenceRevealOptions(strings: PresentationStrings, theme: Pr
|
|||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
private func leftRevealOptions(strings: PresentationStrings, theme: PresentationTheme, isUnread: Bool, isEditing: Bool, isPinned: Bool, isSavedMessages: Bool, groupId: EngineChatList.Group, peer: EnginePeer, filterData: ChatListItemFilterData?) -> [ItemListRevealOption] {
|
private func leftRevealOptions(strings: PresentationStrings, theme: PresentationTheme, isUnread: Bool, isEditing: Bool, isPinned: Bool, isSavedMessages: Bool, location: ChatListControllerLocation, peer: EnginePeer, filterData: ChatListItemFilterData?) -> [ItemListRevealOption] {
|
||||||
if case .archive = groupId {
|
guard case .chatList(.root) = location else {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
var options: [ItemListRevealOption] = []
|
var options: [ItemListRevealOption] = []
|
||||||
@ -439,6 +451,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
let contextContainer: ContextControllerSourceNode
|
let contextContainer: ContextControllerSourceNode
|
||||||
|
|
||||||
let avatarNode: AvatarNode
|
let avatarNode: AvatarNode
|
||||||
|
var avatarIconView: ComponentHostView<Empty>?
|
||||||
|
var avatarIconComponent: EmojiStatusComponent?
|
||||||
var videoNode: UniversalVideoNode?
|
var videoNode: UniversalVideoNode?
|
||||||
private var videoContent: NativeVideoContent?
|
private var videoContent: NativeVideoContent?
|
||||||
private let playbackStartDisposable = MetaDisposable()
|
private let playbackStartDisposable = MetaDisposable()
|
||||||
@ -525,7 +539,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
result += "\n\(item.presentationData.strings.VoiceOver_Chat_UnreadMessages(Int32(allCount)))"
|
result += "\n\(item.presentationData.strings.VoiceOver_Chat_UnreadMessages(Int32(allCount)))"
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
case let .peer(_, peer, combinedReadState, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(_, peer, _, combinedReadState, _, _, _, _, _, _, _, _, _, _):
|
||||||
guard let chatMainPeer = peer.chatMainPeer else {
|
guard let chatMainPeer = peer.chatMainPeer else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -585,7 +599,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
} else {
|
} else {
|
||||||
return item.presentationData.strings.VoiceOver_ChatList_MessageEmpty
|
return item.presentationData.strings.VoiceOver_ChatList_MessageEmpty
|
||||||
}
|
}
|
||||||
case let .peer(messages, peer, combinedReadState, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(messages, peer, _, combinedReadState, _, _, _, _, _, _, _, _, _, _):
|
||||||
if let message = messages.last {
|
if let message = messages.last {
|
||||||
var result = ""
|
var result = ""
|
||||||
if message.flags.contains(.Incoming) {
|
if message.flags.contains(.Incoming) {
|
||||||
@ -644,6 +658,14 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
containerSize: credibilityIconView.bounds.size
|
containerSize: credibilityIconView.bounds.size
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if let avatarIconView = self.avatarIconView, let avatarIconComponent = self.avatarIconComponent {
|
||||||
|
let _ = avatarIconView.update(
|
||||||
|
transition: .immediate,
|
||||||
|
component: AnyComponent(avatarIconComponent.withVisibleForAnimations(self.visibilityStatus)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: avatarIconView.bounds.size
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -770,7 +792,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
var displayAsMessage = false
|
var displayAsMessage = false
|
||||||
var enablePreview = true
|
var enablePreview = true
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(messages, peerValue, _, _, _, _, _, _, _, _, _, displayAsMessageValue, _):
|
case let .peer(messages, peerValue, _, _, _, _, _, _, _, _, _, _, displayAsMessageValue, _):
|
||||||
displayAsMessage = displayAsMessageValue
|
displayAsMessage = displayAsMessageValue
|
||||||
if displayAsMessage, case let .user(author) = messages.last?.author {
|
if displayAsMessage, case let .user(author) = messages.last?.author {
|
||||||
peer = .user(author)
|
peer = .user(author)
|
||||||
@ -922,7 +944,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
|
|
||||||
if let item = self.item {
|
if let item = self.item {
|
||||||
let onlineIcon: UIImage?
|
let onlineIcon: UIImage?
|
||||||
if item.index.pinningIndex != nil {
|
if case let .chatList(index) = item.index, index.pinningIndex != nil {
|
||||||
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .pinned, voiceChat: self.onlineIsVoiceChat)
|
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .pinned, voiceChat: self.onlineIsVoiceChat)
|
||||||
} else {
|
} else {
|
||||||
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .regular, voiceChat: self.onlineIsVoiceChat)
|
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .regular, voiceChat: self.onlineIsVoiceChat)
|
||||||
@ -936,7 +958,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
guard let item = self.item, item.editing else {
|
guard let item = self.item, item.editing else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if case let .peer(_, peer, _, _, _, _, _, _, _, promoInfo, _, _, _) = item.content {
|
if case let .peer(_, peer, _, _, _, _, _, _, _, _, promoInfo, _, _, _) = item.content {
|
||||||
if promoInfo == nil, let mainPeer = peer.peer {
|
if promoInfo == nil, let mainPeer = peer.peer {
|
||||||
item.interaction.togglePeerSelected(mainPeer)
|
item.interaction.togglePeerSelected(mainPeer)
|
||||||
}
|
}
|
||||||
@ -985,11 +1007,12 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
let promoInfo: ChatListNodeEntryPromoInfo?
|
let promoInfo: ChatListNodeEntryPromoInfo?
|
||||||
let displayAsMessage: Bool
|
let displayAsMessage: Bool
|
||||||
let hasFailedMessages: Bool
|
let hasFailedMessages: Bool
|
||||||
|
var threadInfo: EngineMessageHistoryThreads.Info?
|
||||||
|
|
||||||
var groupHiddenByDefault = false
|
var groupHiddenByDefault = false
|
||||||
|
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(messagesValue, peerValue, combinedReadStateValue, isRemovedFromTotalUnreadCountValue, peerPresenceValue, hasUnseenMentionsValue, hasUnseenReactionsValue, draftStateValue, inputActivitiesValue, promoInfoValue, ignoreUnreadBadge, displayAsMessageValue, _):
|
case let .peer(messagesValue, peerValue, threadInfoValue, combinedReadStateValue, isRemovedFromTotalUnreadCountValue, peerPresenceValue, hasUnseenMentionsValue, hasUnseenReactionsValue, draftStateValue, inputActivitiesValue, promoInfoValue, ignoreUnreadBadge, displayAsMessageValue, _):
|
||||||
messages = messagesValue
|
messages = messagesValue
|
||||||
contentPeer = .chat(peerValue)
|
contentPeer = .chat(peerValue)
|
||||||
combinedReadState = combinedReadStateValue
|
combinedReadState = combinedReadStateValue
|
||||||
@ -1007,6 +1030,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
return EnginePeer.Presence(status: presence.status, lastActivity: 0)
|
return EnginePeer.Presence(status: presence.status, lastActivity: 0)
|
||||||
}
|
}
|
||||||
draftState = draftStateValue
|
draftState = draftStateValue
|
||||||
|
threadInfo = threadInfoValue
|
||||||
hasUnseenMentions = hasUnseenMentionsValue
|
hasUnseenMentions = hasUnseenMentionsValue
|
||||||
hasUnseenReactions = hasUnseenReactionsValue
|
hasUnseenReactions = hasUnseenReactionsValue
|
||||||
|
|
||||||
@ -1095,7 +1119,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
}
|
}
|
||||||
editingOffset = sizeAndApply.0
|
editingOffset = sizeAndApply.0
|
||||||
|
|
||||||
if item.index.pinningIndex != nil && promoInfo == nil && !isPeerGroup {
|
if case let .chatList(index) = item.index, index.pinningIndex != nil, promoInfo == nil, !isPeerGroup {
|
||||||
let sizeAndApply = reorderControlLayout(item.presentationData.theme)
|
let sizeAndApply = reorderControlLayout(item.presentationData.theme)
|
||||||
reorderControlSizeAndApply = sizeAndApply
|
reorderControlSizeAndApply = sizeAndApply
|
||||||
reorderInset = sizeAndApply.0
|
reorderInset = sizeAndApply.0
|
||||||
@ -1107,14 +1131,20 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
let enableChatListPhotos = true
|
let enableChatListPhotos = true
|
||||||
|
|
||||||
let avatarDiameter = min(60.0, floor(item.presentationData.fontSize.baseDisplaySize * 60.0 / 17.0))
|
let avatarDiameter = min(60.0, floor(item.presentationData.fontSize.baseDisplaySize * 60.0 / 17.0))
|
||||||
let avatarLeftInset = 18.0 + avatarDiameter
|
|
||||||
|
let avatarLeftInset: CGFloat
|
||||||
|
if case .forum = item.index {
|
||||||
|
avatarLeftInset = 56.0
|
||||||
|
} else {
|
||||||
|
avatarLeftInset = 18.0 + avatarDiameter
|
||||||
|
}
|
||||||
|
|
||||||
let badgeDiameter = floor(item.presentationData.fontSize.baseDisplaySize * 20.0 / 17.0)
|
let badgeDiameter = floor(item.presentationData.fontSize.baseDisplaySize * 20.0 / 17.0)
|
||||||
|
|
||||||
let leftInset: CGFloat = params.leftInset + avatarLeftInset
|
let leftInset: CGFloat = params.leftInset + avatarLeftInset
|
||||||
|
|
||||||
enum ContentData {
|
enum ContentData {
|
||||||
case chat(itemPeer: EngineRenderedPeer, peer: EnginePeer?, hideAuthor: Bool, messageText: String, spoilers: [NSRange]?, customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)]?)
|
case chat(itemPeer: EngineRenderedPeer, threadInfo: EngineMessageHistoryThreads.Info?, peer: EnginePeer?, hideAuthor: Bool, messageText: String, spoilers: [NSRange]?, customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)]?)
|
||||||
case group(peers: [EngineChatList.GroupItem.Item])
|
case group(peers: [EngineChatList.GroupItem.Item])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1149,7 +1179,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
contentData = .chat(itemPeer: itemPeer, peer: peer, hideAuthor: hideAuthor, messageText: messageText, spoilers: spoilers, customEmojiRanges: customEmojiRanges)
|
contentData = .chat(itemPeer: itemPeer, threadInfo: threadInfo, peer: peer, hideAuthor: hideAuthor, messageText: messageText, spoilers: spoilers, customEmojiRanges: customEmojiRanges)
|
||||||
hideAuthor = initialHideAuthor
|
hideAuthor = initialHideAuthor
|
||||||
case let .group(groupPeers):
|
case let .group(groupPeers):
|
||||||
contentData = .group(peers: groupPeers)
|
contentData = .group(peers: groupPeers)
|
||||||
@ -1180,7 +1210,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
var contentImageSpecs: [(message: EngineMessage, media: EngineMedia, size: CGSize)] = []
|
var contentImageSpecs: [(message: EngineMessage, media: EngineMedia, size: CGSize)] = []
|
||||||
|
|
||||||
switch contentData {
|
switch contentData {
|
||||||
case let .chat(itemPeer, _, _, text, spoilers, customEmojiRanges):
|
case let .chat(itemPeer, _, _, _, text, spoilers, customEmojiRanges):
|
||||||
var isUser = false
|
var isUser = false
|
||||||
if case .user = itemPeer.chatMainPeer {
|
if case .user = itemPeer.chatMainPeer {
|
||||||
isUser = true
|
isUser = true
|
||||||
@ -1191,7 +1221,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
if let messagePeer = itemPeer.chatMainPeer {
|
if let messagePeer = itemPeer.chatMainPeer {
|
||||||
peerText = messagePeer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
|
peerText = messagePeer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
|
||||||
}
|
}
|
||||||
} else if let message = messages.last, let author = message.author?._asPeer(), let peer = itemPeer.chatMainPeer, !isUser {
|
} else if let message = messages.last, let author = message.author?._asPeer(), let peer = itemPeer.chatMainPeer, !isUser {
|
||||||
if case let .channel(peer) = peer, case .broadcast = peer.info {
|
if case let .channel(peer) = peer, case .broadcast = peer.info {
|
||||||
} else if !displayAsMessage {
|
} else if !displayAsMessage {
|
||||||
if let forwardInfo = message.forwardInfo, forwardInfo.flags.contains(.isImported), let authorSignature = forwardInfo.authorSignature {
|
if let forwardInfo = message.forwardInfo, forwardInfo.flags.contains(.isImported), let authorSignature = forwardInfo.authorSignature {
|
||||||
@ -1390,8 +1420,10 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch contentData {
|
switch contentData {
|
||||||
case let .chat(itemPeer, _, _, _, _, _):
|
case let .chat(itemPeer, threadInfo, _, _, _, _, _):
|
||||||
if let message = messages.last, case let .user(author) = message.author, displayAsMessage {
|
if let threadInfo = threadInfo {
|
||||||
|
titleAttributedString = NSAttributedString(string: threadInfo.title, font: titleFont, textColor: theme.titleColor)
|
||||||
|
} else if let message = messages.last, case let .user(author) = message.author, displayAsMessage {
|
||||||
titleAttributedString = NSAttributedString(string: author.id == account.peerId ? item.presentationData.strings.DialogList_You : EnginePeer.user(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: titleFont, textColor: theme.titleColor)
|
titleAttributedString = NSAttributedString(string: author.id == account.peerId ? item.presentationData.strings.DialogList_You : EnginePeer.user(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: titleFont, textColor: theme.titleColor)
|
||||||
} else if isPeerGroup {
|
} else if isPeerGroup {
|
||||||
titleAttributedString = NSAttributedString(string: item.presentationData.strings.ChatList_ArchivedChatsTitle, font: titleFont, textColor: theme.titleColor)
|
titleAttributedString = NSAttributedString(string: item.presentationData.strings.ChatList_ArchivedChatsTitle, font: titleFont, textColor: theme.titleColor)
|
||||||
@ -1400,7 +1432,13 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
} else if let id = itemPeer.chatMainPeer?.id, id.isReplies {
|
} else if let id = itemPeer.chatMainPeer?.id, id.isReplies {
|
||||||
titleAttributedString = NSAttributedString(string: item.presentationData.strings.DialogList_Replies, font: titleFont, textColor: theme.titleColor)
|
titleAttributedString = NSAttributedString(string: item.presentationData.strings.DialogList_Replies, font: titleFont, textColor: theme.titleColor)
|
||||||
} else if let displayTitle = itemPeer.chatMainPeer?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) {
|
} else if let displayTitle = itemPeer.chatMainPeer?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) {
|
||||||
titleAttributedString = NSAttributedString(string: displayTitle, font: titleFont, textColor: item.index.messageIndex.id.peerId.namespace == Namespaces.Peer.SecretChat ? theme.secretTitleColor : theme.titleColor)
|
let textColor: UIColor
|
||||||
|
if case let .chatList(index) = item.index, index.messageIndex.id.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||||
|
textColor = theme.secretTitleColor
|
||||||
|
} else {
|
||||||
|
textColor = theme.titleColor
|
||||||
|
}
|
||||||
|
titleAttributedString = NSAttributedString(string: displayTitle, font: titleFont, textColor: textColor)
|
||||||
}
|
}
|
||||||
case .group:
|
case .group:
|
||||||
titleAttributedString = NSAttributedString(string: item.presentationData.strings.ChatList_ArchivedChatsTitle, font: titleFont, textColor: theme.titleColor)
|
titleAttributedString = NSAttributedString(string: item.presentationData.strings.ChatList_ArchivedChatsTitle, font: titleFont, textColor: theme.titleColor)
|
||||||
@ -1408,12 +1446,25 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
|
|
||||||
textAttributedString = attributedText
|
textAttributedString = attributedText
|
||||||
|
|
||||||
var t = Int(item.index.messageIndex.timestamp)
|
let dateText: String
|
||||||
var timeinfo = tm()
|
var topIndex: MessageIndex?
|
||||||
localtime_r(&t, &timeinfo)
|
switch item.content {
|
||||||
|
case let .groupReference(_, _, message, _, _):
|
||||||
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
topIndex = message?.index
|
||||||
let dateText = stringForRelativeTimestamp(strings: item.presentationData.strings, relativeTimestamp: item.index.messageIndex.timestamp, relativeTo: timestamp, dateTimeFormat: item.presentationData.dateTimeFormat)
|
case let .peer(messages, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
|
topIndex = messages.first?.index
|
||||||
|
}
|
||||||
|
if let topIndex {
|
||||||
|
var t = Int(topIndex.timestamp)
|
||||||
|
var timeinfo = tm()
|
||||||
|
localtime_r(&t, &timeinfo)
|
||||||
|
|
||||||
|
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
||||||
|
|
||||||
|
dateText = stringForRelativeTimestamp(strings: item.presentationData.strings, relativeTimestamp: topIndex.timestamp, relativeTo: timestamp, dateTimeFormat: item.presentationData.dateTimeFormat)
|
||||||
|
} else {
|
||||||
|
dateText = ""
|
||||||
|
}
|
||||||
|
|
||||||
if isPeerGroup {
|
if isPeerGroup {
|
||||||
dateAttributedString = NSAttributedString(string: "", font: dateFont, textColor: theme.dateTextColor)
|
dateAttributedString = NSAttributedString(string: "", font: dateFont, textColor: theme.dateTextColor)
|
||||||
@ -1481,7 +1532,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
|
|
||||||
if !isPeerGroup {
|
if !isPeerGroup {
|
||||||
if hasUnseenMentions {
|
if hasUnseenMentions {
|
||||||
if case .archive = item.peerGroupId {
|
if case .chatList(.archive) = item.chatListLocation {
|
||||||
currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundInactiveMention(item.presentationData.theme, diameter: badgeDiameter)
|
currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundInactiveMention(item.presentationData.theme, diameter: badgeDiameter)
|
||||||
} else {
|
} else {
|
||||||
currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundMention(item.presentationData.theme, diameter: badgeDiameter)
|
currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundMention(item.presentationData.theme, diameter: badgeDiameter)
|
||||||
@ -1494,7 +1545,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundReactions(item.presentationData.theme, diameter: badgeDiameter)
|
currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundReactions(item.presentationData.theme, diameter: badgeDiameter)
|
||||||
}
|
}
|
||||||
mentionBadgeContent = .mention
|
mentionBadgeContent = .mention
|
||||||
} else if item.index.pinningIndex != nil && promoInfo == nil && currentBadgeBackgroundImage == nil {
|
} else if case let .chatList(chatListIndex) = item.index, chatListIndex.pinningIndex != nil, promoInfo == nil, currentBadgeBackgroundImage == nil {
|
||||||
currentPinnedIconImage = PresentationResourcesChatList.badgeBackgroundPinned(item.presentationData.theme, diameter: badgeDiameter)
|
currentPinnedIconImage = PresentationResourcesChatList.badgeBackgroundPinned(item.presentationData.theme, diameter: badgeDiameter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1519,16 +1570,25 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
titleIconsWidth += currentMutedIconImage.size.width
|
titleIconsWidth += currentMutedIconImage.size.width
|
||||||
}
|
}
|
||||||
|
|
||||||
let isSecret = !isPeerGroup && item.index.messageIndex.id.peerId.namespace == Namespaces.Peer.SecretChat
|
var isSecret = false
|
||||||
|
if !isPeerGroup {
|
||||||
|
if case let .chatList(index) = item.index, index.messageIndex.id.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||||
|
isSecret = true
|
||||||
|
}
|
||||||
|
}
|
||||||
if isSecret {
|
if isSecret {
|
||||||
currentSecretIconImage = PresentationResourcesChatList.secretIcon(item.presentationData.theme)
|
currentSecretIconImage = PresentationResourcesChatList.secretIcon(item.presentationData.theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: item.context.currentAppConfiguration.with { $0 })
|
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: item.context.currentAppConfiguration.with { $0 })
|
||||||
if !isPeerGroup && item.index.messageIndex.id.peerId != item.context.account.peerId {
|
var isAccountPeer = false
|
||||||
|
if case let .chatList(index) = item.index, index.messageIndex.id.peerId == item.context.account.peerId {
|
||||||
|
isAccountPeer = true
|
||||||
|
}
|
||||||
|
if !isPeerGroup && !isAccountPeer {
|
||||||
if displayAsMessage {
|
if displayAsMessage {
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(messages, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(messages, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
if let peer = messages.last?.author {
|
if let peer = messages.last?.author {
|
||||||
if case let .user(user) = peer, let emojiStatus = user.emojiStatus, !premiumConfiguration.isPremiumDisabled {
|
if case let .user(user) = peer, let emojiStatus = user.emojiStatus, !premiumConfiguration.isPremiumDisabled {
|
||||||
currentCredibilityIconContent = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 32.0, height: 32.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .count(2))
|
currentCredibilityIconContent = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 32.0, height: 32.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .count(2))
|
||||||
@ -1623,13 +1683,12 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
|
|
||||||
var inputActivitiesSize: CGSize?
|
var inputActivitiesSize: CGSize?
|
||||||
var inputActivitiesApply: (() -> Void)?
|
var inputActivitiesApply: (() -> Void)?
|
||||||
if let inputActivities = inputActivities, !inputActivities.isEmpty {
|
if let inputActivities = inputActivities, !inputActivities.isEmpty, case let .chatList(index) = item.index {
|
||||||
|
let (size, apply) = inputActivitiesLayout(CGSize(width: rawContentWidth - badgeSize, height: 40.0), item.presentationData, item.presentationData.theme.chatList.messageTextColor, index.messageIndex.id.peerId, inputActivities)
|
||||||
let (size, apply) = inputActivitiesLayout(CGSize(width: rawContentWidth - badgeSize, height: 40.0), item.presentationData, item.presentationData.theme.chatList.messageTextColor, item.index.messageIndex.id.peerId, inputActivities)
|
|
||||||
inputActivitiesSize = size
|
inputActivitiesSize = size
|
||||||
inputActivitiesApply = apply
|
inputActivitiesApply = apply
|
||||||
} else {
|
} else {
|
||||||
let (size, apply) = inputActivitiesLayout(CGSize(width: rawContentWidth - badgeSize, height: 40.0), item.presentationData, item.presentationData.theme.chatList.messageTextColor, item.index.messageIndex.id.peerId, [])
|
let (size, apply) = inputActivitiesLayout(CGSize(width: rawContentWidth - badgeSize, height: 40.0), item.presentationData, item.presentationData.theme.chatList.messageTextColor, nil, [])
|
||||||
inputActivitiesSize = size
|
inputActivitiesSize = size
|
||||||
inputActivitiesApply = apply
|
inputActivitiesApply = apply
|
||||||
}
|
}
|
||||||
@ -1637,14 +1696,20 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
var online = false
|
var online = false
|
||||||
var animateOnline = false
|
var animateOnline = false
|
||||||
var onlineIsVoiceChat = false
|
var onlineIsVoiceChat = false
|
||||||
|
|
||||||
|
var isPinned = false
|
||||||
|
if case let .chatList(index) = item.index {
|
||||||
|
isPinned = index.pinningIndex != nil
|
||||||
|
}
|
||||||
|
|
||||||
let peerRevealOptions: [ItemListRevealOption]
|
let peerRevealOptions: [ItemListRevealOption]
|
||||||
let peerLeftRevealOptions: [ItemListRevealOption]
|
let peerLeftRevealOptions: [ItemListRevealOption]
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(_, renderedPeer, _, _, presence, _, _, _, _, _, _, displayAsMessage, _):
|
case let .peer(_, renderedPeer, _, _, _, presence, _, _, _, _, _, _, displayAsMessage, _):
|
||||||
if !displayAsMessage {
|
if !displayAsMessage {
|
||||||
if case let .user(peer) = renderedPeer.chatMainPeer, let presence = presence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != item.context.account.peerId {
|
if case let .user(peer) = renderedPeer.chatMainPeer, let presence = presence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != item.context.account.peerId {
|
||||||
let updatedPresence = EnginePeer.Presence(status: presence.status, lastActivity: 0)
|
let updatedPresence = EnginePeer.Presence(status: presence.status, lastActivity: 0)
|
||||||
|
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
||||||
let relativeStatus = relativeUserPresenceStatus(updatedPresence, relativeTo: timestamp)
|
let relativeStatus = relativeUserPresenceStatus(updatedPresence, relativeTo: timestamp)
|
||||||
if case .online = relativeStatus {
|
if case .online = relativeStatus {
|
||||||
online = true
|
online = true
|
||||||
@ -1665,8 +1730,6 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let isPinned = item.index.pinningIndex != nil
|
|
||||||
|
|
||||||
if item.enableContextActions {
|
if item.enableContextActions {
|
||||||
if case .psa = promoInfo {
|
if case .psa = promoInfo {
|
||||||
peerRevealOptions = [
|
peerRevealOptions = [
|
||||||
@ -1674,9 +1737,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
]
|
]
|
||||||
peerLeftRevealOptions = []
|
peerLeftRevealOptions = []
|
||||||
} else if promoInfo == nil {
|
} else if promoInfo == nil {
|
||||||
peerRevealOptions = revealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isPinned: isPinned, isMuted: item.context.account.peerId != item.index.messageIndex.id.peerId ? (currentMutedIconImage != nil) : nil, groupId: item.peerGroupId, peerId: renderedPeer.peerId, accountPeerId: item.context.account.peerId, canDelete: true, isEditing: item.editing, filterData: item.filterData)
|
peerRevealOptions = revealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isPinned: isPinned, isMuted: !isAccountPeer ? (currentMutedIconImage != nil) : nil, location: item.chatListLocation, peerId: renderedPeer.peerId, accountPeerId: item.context.account.peerId, canDelete: true, isEditing: item.editing, filterData: item.filterData)
|
||||||
if case let .chat(itemPeer) = contentPeer {
|
if case let .chat(itemPeer) = contentPeer {
|
||||||
peerLeftRevealOptions = leftRevealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isUnread: unreadCount.unread, isEditing: item.editing, isPinned: isPinned, isSavedMessages: itemPeer.peerId == item.context.account.peerId, groupId: item.peerGroupId, peer: itemPeer.peers[itemPeer.peerId]!, filterData: item.filterData)
|
peerLeftRevealOptions = leftRevealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isUnread: unreadCount.unread, isEditing: item.editing, isPinned: isPinned, isSavedMessages: itemPeer.peerId == item.context.account.peerId, location: item.chatListLocation, peer: itemPeer.peers[itemPeer.peerId]!, filterData: item.filterData)
|
||||||
} else {
|
} else {
|
||||||
peerLeftRevealOptions = []
|
peerLeftRevealOptions = []
|
||||||
}
|
}
|
||||||
@ -1813,10 +1876,50 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
transition.updateAlpha(node: strongSelf.statusNode, alpha: 1.0)
|
transition.updateAlpha(node: strongSelf.statusNode, alpha: 1.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let contentRect = rawContentRect.offsetBy(dx: editingOffset + leftInset + revealOffset, dy: 0.0)
|
||||||
|
|
||||||
let avatarFrame = CGRect(origin: CGPoint(x: leftInset - avatarLeftInset + editingOffset + 10.0 + revealOffset, y: floor((itemHeight - avatarDiameter) / 2.0)), size: CGSize(width: avatarDiameter, height: avatarDiameter))
|
let avatarFrame = CGRect(origin: CGPoint(x: leftInset - avatarLeftInset + editingOffset + 10.0 + revealOffset, y: floor((itemHeight - avatarDiameter) / 2.0)), size: CGSize(width: avatarDiameter, height: avatarDiameter))
|
||||||
transition.updateFrame(node: strongSelf.avatarNode, frame: avatarFrame)
|
transition.updateFrame(node: strongSelf.avatarNode, frame: avatarFrame)
|
||||||
strongSelf.updateVideoVisibility()
|
strongSelf.updateVideoVisibility()
|
||||||
|
|
||||||
|
if let iconFileId = threadInfo?.icon {
|
||||||
|
let avatarIconView: ComponentHostView<Empty>
|
||||||
|
if let current = strongSelf.avatarIconView {
|
||||||
|
avatarIconView = current
|
||||||
|
} else {
|
||||||
|
avatarIconView = ComponentHostView<Empty>()
|
||||||
|
strongSelf.avatarIconView = avatarIconView
|
||||||
|
strongSelf.contextContainer.view.addSubview(avatarIconView)
|
||||||
|
}
|
||||||
|
|
||||||
|
let avatarIconComponent = EmojiStatusComponent(
|
||||||
|
context: item.context,
|
||||||
|
animationCache: item.interaction.animationCache,
|
||||||
|
animationRenderer: item.interaction.animationRenderer,
|
||||||
|
content: .animation(content: .customEmoji(fileId: iconFileId), size: CGSize(width: 40.0, height: 40.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: nil, loopMode: .forever),
|
||||||
|
isVisibleForAnimations: strongSelf.visibilityStatus,
|
||||||
|
action: nil
|
||||||
|
)
|
||||||
|
strongSelf.avatarIconComponent = avatarIconComponent
|
||||||
|
|
||||||
|
let iconSize = avatarIconView.update(
|
||||||
|
transition: .immediate,
|
||||||
|
component: AnyComponent(avatarIconComponent),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: 40.0, height: 40.0)
|
||||||
|
)
|
||||||
|
transition.updateFrame(view: avatarIconView, frame: CGRect(origin: CGPoint(x: params.leftInset + floor((leftInset - params.leftInset - iconSize.width) / 2.0), y: contentRect.origin.y + 2.0), size: iconSize))
|
||||||
|
} else if let avatarIconView = strongSelf.avatarIconView {
|
||||||
|
strongSelf.avatarIconView = nil
|
||||||
|
avatarIconView.removeFromSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
if case .forum = item.index {
|
||||||
|
strongSelf.avatarNode.isHidden = true
|
||||||
|
} else {
|
||||||
|
strongSelf.avatarNode.isHidden = false
|
||||||
|
}
|
||||||
|
|
||||||
let onlineFrame: CGRect
|
let onlineFrame: CGRect
|
||||||
if onlineIsVoiceChat {
|
if onlineIsVoiceChat {
|
||||||
onlineFrame = CGRect(origin: CGPoint(x: avatarFrame.maxX - onlineLayout.width + 1.0 - UIScreenPixel, y: avatarFrame.maxY - onlineLayout.height + 1.0 - UIScreenPixel), size: onlineLayout)
|
onlineFrame = CGRect(origin: CGPoint(x: avatarFrame.maxX - onlineLayout.width + 1.0 - UIScreenPixel, y: avatarFrame.maxY - onlineLayout.height + 1.0 - UIScreenPixel), size: onlineLayout)
|
||||||
@ -1828,7 +1931,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
let onlineIcon: UIImage?
|
let onlineIcon: UIImage?
|
||||||
if strongSelf.reallyHighlighted {
|
if strongSelf.reallyHighlighted {
|
||||||
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .highlighted, voiceChat: onlineIsVoiceChat)
|
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .highlighted, voiceChat: onlineIsVoiceChat)
|
||||||
} else if item.index.pinningIndex != nil {
|
} else if case let .chatList(index) = item.index, index.pinningIndex != nil {
|
||||||
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .pinned, voiceChat: onlineIsVoiceChat)
|
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .pinned, voiceChat: onlineIsVoiceChat)
|
||||||
} else {
|
} else {
|
||||||
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .regular, voiceChat: onlineIsVoiceChat)
|
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .regular, voiceChat: onlineIsVoiceChat)
|
||||||
@ -1852,8 +1955,6 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
let _ = mentionBadgeApply(animateBadges, true)
|
let _ = mentionBadgeApply(animateBadges, true)
|
||||||
let _ = onlineApply(animateContent && animateOnline)
|
let _ = onlineApply(animateContent && animateOnline)
|
||||||
|
|
||||||
let contentRect = rawContentRect.offsetBy(dx: editingOffset + leftInset + revealOffset, dy: 0.0)
|
|
||||||
|
|
||||||
transition.updateFrame(node: strongSelf.dateNode, frame: CGRect(origin: CGPoint(x: contentRect.origin.x + contentRect.size.width - dateLayout.size.width, y: contentRect.origin.y + 2.0), size: dateLayout.size))
|
transition.updateFrame(node: strongSelf.dateNode, frame: CGRect(origin: CGPoint(x: contentRect.origin.x + contentRect.size.width - dateLayout.size.width, y: contentRect.origin.y + 2.0), size: dateLayout.size))
|
||||||
|
|
||||||
let statusSize = CGSize(width: 24.0, height: 24.0)
|
let statusSize = CGSize(width: 24.0, height: 24.0)
|
||||||
@ -2104,7 +2205,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
let separatorInset: CGFloat
|
let separatorInset: CGFloat
|
||||||
if case let .groupReference(_, _, _, _, hiddenByDefault) = item.content, hiddenByDefault {
|
if case let .groupReference(_, _, _, _, hiddenByDefault) = item.content, hiddenByDefault {
|
||||||
separatorInset = 0.0
|
separatorInset = 0.0
|
||||||
} else if (!nextIsPinned && item.index.pinningIndex != nil) || last {
|
} else if (!nextIsPinned && isPinned) || last {
|
||||||
separatorInset = 0.0
|
separatorInset = 0.0
|
||||||
} else {
|
} else {
|
||||||
separatorInset = editingOffset + leftInset + rawContentRect.origin.x
|
separatorInset = editingOffset + leftInset + rawContentRect.origin.x
|
||||||
@ -2118,7 +2219,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
if item.selected {
|
if item.selected {
|
||||||
backgroundColor = theme.itemSelectedBackgroundColor
|
backgroundColor = theme.itemSelectedBackgroundColor
|
||||||
highlightedBackgroundColor = theme.itemHighlightedBackgroundColor
|
highlightedBackgroundColor = theme.itemHighlightedBackgroundColor
|
||||||
} else if item.index.pinningIndex != nil {
|
} else if isPinned {
|
||||||
if case let .groupReference(_, _, _, _, hiddenByDefault) = item.content, hiddenByDefault {
|
if case let .groupReference(_, _, _, _, hiddenByDefault) = item.content, hiddenByDefault {
|
||||||
backgroundColor = theme.itemBackgroundColor
|
backgroundColor = theme.itemBackgroundColor
|
||||||
highlightedBackgroundColor = theme.itemHighlightedBackgroundColor
|
highlightedBackgroundColor = theme.itemHighlightedBackgroundColor
|
||||||
@ -2398,90 +2499,100 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
|
|
||||||
override func revealOptionsInteractivelyOpened() {
|
override func revealOptionsInteractivelyOpened() {
|
||||||
if let item = self.item {
|
if let item = self.item {
|
||||||
item.interaction.setPeerIdWithRevealedOptions(item.index.messageIndex.id.peerId, nil)
|
switch item.index {
|
||||||
|
case let .chatList(index):
|
||||||
|
item.interaction.setPeerIdWithRevealedOptions(index.messageIndex.id.peerId, nil)
|
||||||
|
case .forum:
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func revealOptionsInteractivelyClosed() {
|
override func revealOptionsInteractivelyClosed() {
|
||||||
if let item = self.item {
|
if let item = self.item {
|
||||||
item.interaction.setPeerIdWithRevealedOptions(nil, item.index.messageIndex.id.peerId)
|
switch item.index {
|
||||||
|
case let .chatList(index):
|
||||||
|
item.interaction.setPeerIdWithRevealedOptions(nil, index.messageIndex.id.peerId)
|
||||||
|
case .forum:
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func revealOptionSelected(_ option: ItemListRevealOption, animated: Bool) {
|
override func revealOptionSelected(_ option: ItemListRevealOption, animated: Bool) {
|
||||||
var close = true
|
var close = true
|
||||||
if let item = self.item {
|
if let item = self.item, case let .chatList(index) = item.index {
|
||||||
switch option.key {
|
switch option.key {
|
||||||
case RevealOptionKey.pin.rawValue:
|
case RevealOptionKey.pin.rawValue:
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case .peer:
|
case .peer:
|
||||||
let itemId: EngineChatList.PinnedItem.Id = .peer(item.index.messageIndex.id.peerId)
|
let itemId: EngineChatList.PinnedItem.Id = .peer(index.messageIndex.id.peerId)
|
||||||
item.interaction.setItemPinned(itemId, true)
|
item.interaction.setItemPinned(itemId, true)
|
||||||
case .groupReference:
|
case .groupReference:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case RevealOptionKey.unpin.rawValue:
|
case RevealOptionKey.unpin.rawValue:
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case .peer:
|
case .peer:
|
||||||
let itemId: EngineChatList.PinnedItem.Id = .peer(item.index.messageIndex.id.peerId)
|
let itemId: EngineChatList.PinnedItem.Id = .peer(index.messageIndex.id.peerId)
|
||||||
item.interaction.setItemPinned(itemId, false)
|
item.interaction.setItemPinned(itemId, false)
|
||||||
case .groupReference:
|
case .groupReference:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case RevealOptionKey.mute.rawValue:
|
case RevealOptionKey.mute.rawValue:
|
||||||
item.interaction.setPeerMuted(item.index.messageIndex.id.peerId, true)
|
item.interaction.setPeerMuted(index.messageIndex.id.peerId, true)
|
||||||
close = false
|
close = false
|
||||||
case RevealOptionKey.unmute.rawValue:
|
case RevealOptionKey.unmute.rawValue:
|
||||||
item.interaction.setPeerMuted(item.index.messageIndex.id.peerId, false)
|
item.interaction.setPeerMuted(index.messageIndex.id.peerId, false)
|
||||||
close = false
|
close = false
|
||||||
case RevealOptionKey.delete.rawValue:
|
case RevealOptionKey.delete.rawValue:
|
||||||
var joined = false
|
var joined = false
|
||||||
if case let .peer(messages, _, _, _, _, _, _, _, _, _, _, _, _) = item.content, let message = messages.first {
|
if case let .peer(messages, _, _, _, _, _, _, _, _, _, _, _, _, _) = item.content, let message = messages.first {
|
||||||
for media in message.media {
|
for media in message.media {
|
||||||
if let action = media as? TelegramMediaAction, action.action == .peerJoined {
|
if let action = media as? TelegramMediaAction, action.action == .peerJoined {
|
||||||
joined = true
|
joined = true
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item.interaction.deletePeer(item.index.messageIndex.id.peerId, joined)
|
}
|
||||||
case RevealOptionKey.archive.rawValue:
|
item.interaction.deletePeer(index.messageIndex.id.peerId, joined)
|
||||||
item.interaction.updatePeerGrouping(item.index.messageIndex.id.peerId, true)
|
case RevealOptionKey.archive.rawValue:
|
||||||
close = false
|
item.interaction.updatePeerGrouping(index.messageIndex.id.peerId, true)
|
||||||
self.skipFadeout = true
|
close = false
|
||||||
self.animateRevealOptionsFill {
|
self.skipFadeout = true
|
||||||
self.revealOptionsInteractivelyClosed()
|
self.animateRevealOptionsFill {
|
||||||
}
|
self.revealOptionsInteractivelyClosed()
|
||||||
case RevealOptionKey.unarchive.rawValue:
|
}
|
||||||
item.interaction.updatePeerGrouping(item.index.messageIndex.id.peerId, false)
|
case RevealOptionKey.unarchive.rawValue:
|
||||||
close = false
|
item.interaction.updatePeerGrouping(index.messageIndex.id.peerId, false)
|
||||||
self.skipFadeout = true
|
close = false
|
||||||
self.animateRevealOptionsFill {
|
self.skipFadeout = true
|
||||||
self.revealOptionsInteractivelyClosed()
|
self.animateRevealOptionsFill {
|
||||||
}
|
self.revealOptionsInteractivelyClosed()
|
||||||
case RevealOptionKey.toggleMarkedUnread.rawValue:
|
}
|
||||||
item.interaction.togglePeerMarkedUnread(item.index.messageIndex.id.peerId, animated)
|
case RevealOptionKey.toggleMarkedUnread.rawValue:
|
||||||
close = false
|
item.interaction.togglePeerMarkedUnread(index.messageIndex.id.peerId, animated)
|
||||||
case RevealOptionKey.hide.rawValue:
|
close = false
|
||||||
item.interaction.toggleArchivedFolderHiddenByDefault()
|
case RevealOptionKey.hide.rawValue:
|
||||||
close = false
|
item.interaction.toggleArchivedFolderHiddenByDefault()
|
||||||
self.skipFadeout = true
|
close = false
|
||||||
self.animateRevealOptionsFill {
|
self.skipFadeout = true
|
||||||
self.revealOptionsInteractivelyClosed()
|
self.animateRevealOptionsFill {
|
||||||
}
|
self.revealOptionsInteractivelyClosed()
|
||||||
case RevealOptionKey.unhide.rawValue:
|
}
|
||||||
item.interaction.toggleArchivedFolderHiddenByDefault()
|
case RevealOptionKey.unhide.rawValue:
|
||||||
close = false
|
item.interaction.toggleArchivedFolderHiddenByDefault()
|
||||||
case RevealOptionKey.hidePsa.rawValue:
|
close = false
|
||||||
if let item = self.item, case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _) = item.content {
|
case RevealOptionKey.hidePsa.rawValue:
|
||||||
item.interaction.hidePsa(peer.peerId)
|
if let item = self.item, case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _, _) = item.content {
|
||||||
}
|
item.interaction.hidePsa(peer.peerId)
|
||||||
close = false
|
}
|
||||||
self.skipFadeout = true
|
close = false
|
||||||
self.animateRevealOptionsFill {
|
self.skipFadeout = true
|
||||||
self.revealOptionsInteractivelyClosed()
|
self.animateRevealOptionsFill {
|
||||||
}
|
self.revealOptionsInteractivelyClosed()
|
||||||
default:
|
}
|
||||||
break
|
default:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if close {
|
if close {
|
||||||
|
@ -56,12 +56,12 @@ public final class ChatListNodeInteraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let activateSearch: () -> Void
|
let activateSearch: () -> Void
|
||||||
let peerSelected: (EnginePeer, EnginePeer?, ChatListNodeEntryPromoInfo?) -> Void
|
let peerSelected: (EnginePeer, Int64?, EnginePeer?, ChatListNodeEntryPromoInfo?) -> Void
|
||||||
let disabledPeerSelected: (EnginePeer) -> Void
|
let disabledPeerSelected: (EnginePeer) -> Void
|
||||||
let togglePeerSelected: (EnginePeer) -> Void
|
let togglePeerSelected: (EnginePeer) -> Void
|
||||||
let togglePeersSelection: ([PeerEntry], Bool) -> Void
|
let togglePeersSelection: ([PeerEntry], Bool) -> Void
|
||||||
let additionalCategorySelected: (Int) -> Void
|
let additionalCategorySelected: (Int) -> Void
|
||||||
let messageSelected: (EnginePeer, EngineMessage, ChatListNodeEntryPromoInfo?) -> Void
|
let messageSelected: (EnginePeer, Int64?, EngineMessage, ChatListNodeEntryPromoInfo?) -> Void
|
||||||
let groupSelected: (EngineChatList.Group) -> Void
|
let groupSelected: (EngineChatList.Group) -> Void
|
||||||
let addContact: (String) -> Void
|
let addContact: (String) -> Void
|
||||||
let setPeerIdWithRevealedOptions: (EnginePeer.Id?, EnginePeer.Id?) -> Void
|
let setPeerIdWithRevealedOptions: (EnginePeer.Id?, EnginePeer.Id?) -> Void
|
||||||
@ -86,12 +86,12 @@ public final class ChatListNodeInteraction {
|
|||||||
animationCache: AnimationCache,
|
animationCache: AnimationCache,
|
||||||
animationRenderer: MultiAnimationRenderer,
|
animationRenderer: MultiAnimationRenderer,
|
||||||
activateSearch: @escaping () -> Void,
|
activateSearch: @escaping () -> Void,
|
||||||
peerSelected: @escaping (EnginePeer, EnginePeer?, ChatListNodeEntryPromoInfo?) -> Void,
|
peerSelected: @escaping (EnginePeer, Int64?, EnginePeer?, ChatListNodeEntryPromoInfo?) -> Void,
|
||||||
disabledPeerSelected: @escaping (EnginePeer) -> Void,
|
disabledPeerSelected: @escaping (EnginePeer) -> Void,
|
||||||
togglePeerSelected: @escaping (EnginePeer) -> Void,
|
togglePeerSelected: @escaping (EnginePeer) -> Void,
|
||||||
togglePeersSelection: @escaping ([PeerEntry], Bool) -> Void,
|
togglePeersSelection: @escaping ([PeerEntry], Bool) -> Void,
|
||||||
additionalCategorySelected: @escaping (Int) -> Void,
|
additionalCategorySelected: @escaping (Int) -> Void,
|
||||||
messageSelected: @escaping (EnginePeer, EngineMessage, ChatListNodeEntryPromoInfo?) -> Void,
|
messageSelected: @escaping (EnginePeer, Int64?, EngineMessage, ChatListNodeEntryPromoInfo?) -> Void,
|
||||||
groupSelected: @escaping (EngineChatList.Group) -> Void,
|
groupSelected: @escaping (EngineChatList.Group) -> Void,
|
||||||
addContact: @escaping (String) -> Void,
|
addContact: @escaping (String) -> Void,
|
||||||
setPeerIdWithRevealedOptions: @escaping (EnginePeer.Id?, EnginePeer.Id?) -> Void,
|
setPeerIdWithRevealedOptions: @escaping (EnginePeer.Id?, EnginePeer.Id?) -> Void,
|
||||||
@ -219,7 +219,7 @@ public struct ChatListNodeState: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: EngineChatList.Group, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionInsertEntry]) -> [ListViewInsertItem] {
|
private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, location: ChatListControllerLocation, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionInsertEntry]) -> [ListViewInsertItem] {
|
||||||
return entries.map { entry -> ListViewInsertItem in
|
return entries.map { entry -> ListViewInsertItem in
|
||||||
switch entry.entry {
|
switch entry.entry {
|
||||||
case .HeaderEntry:
|
case .HeaderEntry:
|
||||||
@ -242,18 +242,19 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
nodeInteraction.additionalCategorySelected(id)
|
nodeInteraction.additionalCategorySelected(id)
|
||||||
}
|
}
|
||||||
), directionHint: entry.directionHint)
|
), directionHint: entry.directionHint)
|
||||||
case let .PeerEntry(index, presentationData, messages, combinedReadState, isRemovedFromTotalUnreadCount, draftState, peer, presence, hasUnseenMentions, hasUnseenReactions, editing, hasActiveRevealControls, selected, inputActivities, promoInfo, hasFailedMessages, isContact):
|
case let .PeerEntry(index, presentationData, messages, combinedReadState, isRemovedFromTotalUnreadCount, draftState, peer, threadInfo, presence, hasUnseenMentions, hasUnseenReactions, editing, hasActiveRevealControls, selected, inputActivities, promoInfo, hasFailedMessages, isContact):
|
||||||
switch mode {
|
switch mode {
|
||||||
case .chatList:
|
case .chatList:
|
||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(
|
||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
context: context,
|
context: context,
|
||||||
peerGroupId: peerGroupId,
|
chatListLocation: location,
|
||||||
filterData: filterData,
|
filterData: filterData,
|
||||||
index: index,
|
index: index,
|
||||||
content: .peer(
|
content: .peer(
|
||||||
messages: messages,
|
messages: messages,
|
||||||
peer: peer,
|
peer: peer,
|
||||||
|
threadInfo: threadInfo,
|
||||||
combinedReadState: combinedReadState,
|
combinedReadState: combinedReadState,
|
||||||
isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount,
|
isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount,
|
||||||
presence: presence,
|
presence: presence,
|
||||||
@ -386,7 +387,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
if editing {
|
if editing {
|
||||||
nodeInteraction.togglePeerSelected(chatPeer)
|
nodeInteraction.togglePeerSelected(chatPeer)
|
||||||
} else {
|
} else {
|
||||||
nodeInteraction.peerSelected(chatPeer, nil, nil)
|
nodeInteraction.peerSelected(chatPeer, nil, nil, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, disabledAction: { _ in
|
}, disabledAction: { _ in
|
||||||
@ -404,7 +405,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(
|
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(
|
||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
context: context,
|
context: context,
|
||||||
peerGroupId: peerGroupId,
|
chatListLocation: location,
|
||||||
filterData: filterData,
|
filterData: filterData,
|
||||||
index: index,
|
index: index,
|
||||||
content: .groupReference(
|
content: .groupReference(
|
||||||
@ -428,21 +429,22 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: EngineChatList.Group, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionUpdateEntry]) -> [ListViewUpdateItem] {
|
private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, location: ChatListControllerLocation, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, entries: [ChatListNodeViewTransitionUpdateEntry]) -> [ListViewUpdateItem] {
|
||||||
return entries.map { entry -> ListViewUpdateItem in
|
return entries.map { entry -> ListViewUpdateItem in
|
||||||
switch entry.entry {
|
switch entry.entry {
|
||||||
case let .PeerEntry(index, presentationData, messages, combinedReadState, isRemovedFromTotalUnreadCount, draftState, peer, presence, hasUnseenMentions, hasUnseenReactions, editing, hasActiveRevealControls, selected, inputActivities, promoInfo, hasFailedMessages, isContact):
|
case let .PeerEntry(index, presentationData, messages, combinedReadState, isRemovedFromTotalUnreadCount, draftState, peer, threadInfo, presence, hasUnseenMentions, hasUnseenReactions, editing, hasActiveRevealControls, selected, inputActivities, promoInfo, hasFailedMessages, isContact):
|
||||||
switch mode {
|
switch mode {
|
||||||
case .chatList:
|
case .chatList:
|
||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(
|
||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
context: context,
|
context: context,
|
||||||
peerGroupId: peerGroupId,
|
chatListLocation: location,
|
||||||
filterData: filterData,
|
filterData: filterData,
|
||||||
index: index,
|
index: index,
|
||||||
content: .peer(
|
content: .peer(
|
||||||
messages: messages,
|
messages: messages,
|
||||||
peer: peer,
|
peer: peer,
|
||||||
|
threadInfo: threadInfo,
|
||||||
combinedReadState: combinedReadState,
|
combinedReadState: combinedReadState,
|
||||||
isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount,
|
isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount,
|
||||||
presence: presence,
|
presence: presence,
|
||||||
@ -528,7 +530,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
if editing {
|
if editing {
|
||||||
nodeInteraction.togglePeerSelected(chatPeer)
|
nodeInteraction.togglePeerSelected(chatPeer)
|
||||||
} else {
|
} else {
|
||||||
nodeInteraction.peerSelected(chatPeer, nil, nil)
|
nodeInteraction.peerSelected(chatPeer, nil, nil, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, disabledAction: { _ in
|
}, disabledAction: { _ in
|
||||||
@ -546,7 +548,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(
|
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(
|
||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
context: context,
|
context: context,
|
||||||
peerGroupId: peerGroupId,
|
chatListLocation: location,
|
||||||
filterData: filterData,
|
filterData: filterData,
|
||||||
index: index,
|
index: index,
|
||||||
content: .groupReference(
|
content: .groupReference(
|
||||||
@ -590,8 +592,8 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func mappedChatListNodeViewListTransition(context: AccountContext, nodeInteraction: ChatListNodeInteraction, peerGroupId: EngineChatList.Group, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, transition: ChatListNodeViewTransition) -> ChatListNodeListViewTransition {
|
private func mappedChatListNodeViewListTransition(context: AccountContext, nodeInteraction: ChatListNodeInteraction, location: ChatListControllerLocation, filterData: ChatListItemFilterData?, mode: ChatListNodeMode, transition: ChatListNodeViewTransition) -> ChatListNodeListViewTransition {
|
||||||
return ChatListNodeListViewTransition(chatListView: transition.chatListView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(context: context, nodeInteraction: nodeInteraction, peerGroupId: peerGroupId, filterData: filterData, mode: mode, entries: transition.insertEntries), updateItems: mappedUpdateEntries(context: context, nodeInteraction: nodeInteraction, peerGroupId: peerGroupId, filterData: filterData, mode: mode, entries: transition.updateEntries), options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, adjustScrollToFirstItem: transition.adjustScrollToFirstItem, animateCrossfade: transition.animateCrossfade)
|
return ChatListNodeListViewTransition(chatListView: transition.chatListView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(context: context, nodeInteraction: nodeInteraction, location: location, filterData: filterData, mode: mode, entries: transition.insertEntries), updateItems: mappedUpdateEntries(context: context, nodeInteraction: nodeInteraction, location: location, filterData: filterData, mode: mode, entries: transition.updateEntries), options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, adjustScrollToFirstItem: transition.adjustScrollToFirstItem, animateCrossfade: transition.animateCrossfade)
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class ChatListOpaqueTransactionState {
|
private final class ChatListOpaqueTransactionState {
|
||||||
@ -627,7 +629,7 @@ public enum ChatListNodeEmptyState: Equatable {
|
|||||||
public final class ChatListNode: ListView {
|
public final class ChatListNode: ListView {
|
||||||
private let fillPreloadItems: Bool
|
private let fillPreloadItems: Bool
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let groupId: EngineChatList.Group
|
private let location: ChatListControllerLocation
|
||||||
private let mode: ChatListNodeMode
|
private let mode: ChatListNodeMode
|
||||||
private let animationCache: AnimationCache
|
private let animationCache: AnimationCache
|
||||||
private let animationRenderer: MultiAnimationRenderer
|
private let animationRenderer: MultiAnimationRenderer
|
||||||
@ -644,7 +646,7 @@ public final class ChatListNode: ListView {
|
|||||||
return _contentsReady.get()
|
return _contentsReady.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
public var peerSelected: ((EnginePeer, Bool, Bool, ChatListNodeEntryPromoInfo?) -> Void)?
|
public var peerSelected: ((EnginePeer, Int64?, Bool, Bool, ChatListNodeEntryPromoInfo?) -> Void)?
|
||||||
public var disabledPeerSelected: ((EnginePeer) -> Void)?
|
public var disabledPeerSelected: ((EnginePeer) -> Void)?
|
||||||
public var additionalCategorySelected: ((Int) -> Void)?
|
public var additionalCategorySelected: ((Int) -> Void)?
|
||||||
public var groupSelected: ((EngineChatList.Group) -> Void)?
|
public var groupSelected: ((EngineChatList.Group) -> Void)?
|
||||||
@ -745,9 +747,9 @@ public final class ChatListNode: ListView {
|
|||||||
public var selectionLimit: Int32 = 100
|
public var selectionLimit: Int32 = 100
|
||||||
public var reachedSelectionLimit: ((Int32) -> Void)?
|
public var reachedSelectionLimit: ((Int32) -> Void)?
|
||||||
|
|
||||||
public init(context: AccountContext, groupId: EngineChatList.Group, chatListFilter: ChatListFilter? = nil, previewing: Bool, fillPreloadItems: Bool, mode: ChatListNodeMode, theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, disableAnimations: Bool) {
|
public init(context: AccountContext, location: ChatListControllerLocation, chatListFilter: ChatListFilter? = nil, previewing: Bool, fillPreloadItems: Bool, mode: ChatListNodeMode, theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, disableAnimations: Bool) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.groupId = groupId
|
self.location = location
|
||||||
self.chatListFilter = chatListFilter
|
self.chatListFilter = chatListFilter
|
||||||
self.chatListFilterValue.set(.single(chatListFilter))
|
self.chatListFilterValue.set(.single(chatListFilter))
|
||||||
self.fillPreloadItems = fillPreloadItems
|
self.fillPreloadItems = fillPreloadItems
|
||||||
@ -776,9 +778,9 @@ public final class ChatListNode: ListView {
|
|||||||
if let strongSelf = self, let activateSearch = strongSelf.activateSearch {
|
if let strongSelf = self, let activateSearch = strongSelf.activateSearch {
|
||||||
activateSearch()
|
activateSearch()
|
||||||
}
|
}
|
||||||
}, peerSelected: { [weak self] peer, _, promoInfo in
|
}, peerSelected: { [weak self] peer, threadId, _, promoInfo in
|
||||||
if let strongSelf = self, let peerSelected = strongSelf.peerSelected {
|
if let strongSelf = self, let peerSelected = strongSelf.peerSelected {
|
||||||
peerSelected(peer, true, true, promoInfo)
|
peerSelected(peer, threadId, true, true, promoInfo)
|
||||||
}
|
}
|
||||||
}, disabledPeerSelected: { [weak self] peer in
|
}, disabledPeerSelected: { [weak self] peer in
|
||||||
if let strongSelf = self, let disabledPeerSelected = strongSelf.disabledPeerSelected {
|
if let strongSelf = self, let disabledPeerSelected = strongSelf.disabledPeerSelected {
|
||||||
@ -842,7 +844,7 @@ public final class ChatListNode: ListView {
|
|||||||
}
|
}
|
||||||
}, additionalCategorySelected: { [weak self] id in
|
}, additionalCategorySelected: { [weak self] id in
|
||||||
self?.additionalCategorySelected?(id)
|
self?.additionalCategorySelected?(id)
|
||||||
}, messageSelected: { [weak self] peer, message, promoInfo in
|
}, messageSelected: { [weak self] peer, threadId, message, promoInfo in
|
||||||
if let strongSelf = self, let peerSelected = strongSelf.peerSelected {
|
if let strongSelf = self, let peerSelected = strongSelf.peerSelected {
|
||||||
var activateInput = false
|
var activateInput = false
|
||||||
for media in message.media {
|
for media in message.media {
|
||||||
@ -855,7 +857,7 @@ public final class ChatListNode: ListView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
peerSelected(peer, true, activateInput, promoInfo)
|
peerSelected(peer, threadId, true, activateInput, promoInfo)
|
||||||
}
|
}
|
||||||
}, groupSelected: { [weak self] groupId in
|
}, groupSelected: { [weak self] groupId in
|
||||||
if let strongSelf = self, let groupSelected = strongSelf.groupSelected {
|
if let strongSelf = self, let groupSelected = strongSelf.groupSelected {
|
||||||
@ -876,7 +878,14 @@ public final class ChatListNode: ListView {
|
|||||||
}
|
}
|
||||||
}, setItemPinned: { [weak self] itemId, _ in
|
}, setItemPinned: { [weak self] itemId, _ in
|
||||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
|> deliverOnMainQueue).start(next: { peer in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard case let .chatList(groupId) = strongSelf.location else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let isPremium = peer?.isPremium ?? false
|
let isPremium = peer?.isPremium ?? false
|
||||||
let location: TogglePeerChatPinnedLocation
|
let location: TogglePeerChatPinnedLocation
|
||||||
if let chatListFilter = chatListFilter {
|
if let chatListFilter = chatListFilter {
|
||||||
@ -979,10 +988,10 @@ public final class ChatListNode: ListView {
|
|||||||
|
|
||||||
let chatListViewUpdate = self.chatListLocation.get()
|
let chatListViewUpdate = self.chatListLocation.get()
|
||||||
|> distinctUntilChanged
|
|> distinctUntilChanged
|
||||||
|> mapToSignal { location -> Signal<(ChatListNodeViewUpdate, ChatListFilter?), NoError> in
|
|> mapToSignal { listLocation -> Signal<(ChatListNodeViewUpdate, ChatListFilter?), NoError> in
|
||||||
return chatListViewForLocation(groupId: groupId._asGroup(), location: location, account: context.account)
|
return chatListViewForLocation(chatListLocation: location, location: listLocation, account: context.account)
|
||||||
|> map { update in
|
|> map { update in
|
||||||
return (update, location.filter)
|
return (update, listLocation.filter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1010,7 +1019,7 @@ public final class ChatListNode: ListView {
|
|||||||
|> distinctUntilChanged
|
|> distinctUntilChanged
|
||||||
|
|
||||||
let displayArchiveIntro: Signal<Bool, NoError>
|
let displayArchiveIntro: Signal<Bool, NoError>
|
||||||
if case .archive = groupId {
|
if case .chatList(.archive) = location {
|
||||||
displayArchiveIntro = context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.archiveIntroDismissedKey())
|
displayArchiveIntro = context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.archiveIntroDismissedKey())
|
||||||
|> map { entry -> Bool in
|
|> map { entry -> Bool in
|
||||||
if let value = entry.value?.get(ApplicationSpecificVariantNotice.self) {
|
if let value = entry.value?.get(ApplicationSpecificVariantNotice.self) {
|
||||||
@ -1041,123 +1050,123 @@ public final class ChatListNode: ListView {
|
|||||||
|
|
||||||
let previousHideArchivedFolderByDefaultValue = previousHideArchivedFolderByDefault.swap(hideArchivedFolderByDefault)
|
let previousHideArchivedFolderByDefaultValue = previousHideArchivedFolderByDefault.swap(hideArchivedFolderByDefault)
|
||||||
|
|
||||||
let (rawEntries, isLoading) = chatListNodeEntriesForView(EngineChatList(update.view), state: state, savedMessagesPeer: savedMessagesPeer, foundPeers: state.foundPeers, hideArchivedFolderByDefault: hideArchivedFolderByDefault, displayArchiveIntro: displayArchiveIntro, mode: mode)
|
let (rawEntries, isLoading) = chatListNodeEntriesForView(update.list, state: state, savedMessagesPeer: savedMessagesPeer, foundPeers: state.foundPeers, hideArchivedFolderByDefault: hideArchivedFolderByDefault, displayArchiveIntro: displayArchiveIntro, mode: mode)
|
||||||
let entries = rawEntries.filter { entry in
|
let entries = rawEntries.filter { entry in
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .PeerEntry(_, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _):
|
case let .PeerEntry(_, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
switch mode {
|
switch mode {
|
||||||
case .chatList:
|
case .chatList:
|
||||||
return true
|
return true
|
||||||
case let .peers(filter, _, _, _):
|
case let .peers(filter, _, _, _):
|
||||||
guard !filter.contains(.excludeSavedMessages) || peer.peerId != currentPeerId else { return false }
|
guard !filter.contains(.excludeSavedMessages) || peer.peerId != currentPeerId else { return false }
|
||||||
guard !filter.contains(.excludeSavedMessages) || !peer.peerId.isReplies else { return false }
|
guard !filter.contains(.excludeSavedMessages) || !peer.peerId.isReplies else { return false }
|
||||||
guard !filter.contains(.excludeSecretChats) || peer.peerId.namespace != Namespaces.Peer.SecretChat else { return false }
|
guard !filter.contains(.excludeSecretChats) || peer.peerId.namespace != Namespaces.Peer.SecretChat else { return false }
|
||||||
guard !filter.contains(.onlyPrivateChats) || peer.peerId.namespace == Namespaces.Peer.CloudUser else { return false }
|
guard !filter.contains(.onlyPrivateChats) || peer.peerId.namespace == Namespaces.Peer.CloudUser else { return false }
|
||||||
|
|
||||||
if let peer = peer.peer {
|
if let peer = peer.peer {
|
||||||
switch peer {
|
switch peer {
|
||||||
case let .user(user):
|
case let .user(user):
|
||||||
if user.botInfo != nil {
|
if user.botInfo != nil {
|
||||||
if filter.contains(.excludeBots) {
|
if filter.contains(.excludeBots) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if filter.contains(.excludeUsers) {
|
if filter.contains(.excludeUsers) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case .legacyGroup:
|
case .legacyGroup:
|
||||||
if filter.contains(.excludeGroups) {
|
if filter.contains(.excludeGroups) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .channel(channel):
|
case let .channel(channel):
|
||||||
switch channel.info {
|
switch channel.info {
|
||||||
case .broadcast:
|
case .broadcast:
|
||||||
if filter.contains(.excludeChannels) {
|
if filter.contains(.excludeChannels) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case .group:
|
case .group:
|
||||||
if filter.contains(.excludeGroups) {
|
if filter.contains(.excludeGroups) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if filter.contains(.onlyGroupsAndChannels) {
|
||||||
|
if case .channel = peer.chatMainPeer {
|
||||||
|
} else if case .legacyGroup = peer.chatMainPeer {
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if filter.contains(.onlyGroups) {
|
||||||
|
var isGroup: Bool = false
|
||||||
|
if case let .channel(peer) = peer.chatMainPeer, case .group = peer.info {
|
||||||
|
isGroup = true
|
||||||
|
} else if peer.peerId.namespace == Namespaces.Peer.CloudGroup {
|
||||||
|
isGroup = true
|
||||||
|
}
|
||||||
|
if !isGroup {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if filter.contains(.onlyGroupsAndChannels) {
|
if filter.contains(.onlyChannels) {
|
||||||
if case .channel = peer.chatMainPeer {
|
if case let .channel(peer) = peer.chatMainPeer, case .broadcast = peer.info {
|
||||||
} else if case .legacyGroup = peer.chatMainPeer {
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if filter.contains(.excludeChannels) {
|
||||||
|
if case let .channel(peer) = peer.chatMainPeer, case .broadcast = peer.info {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if filter.contains(.onlyWriteable) && filter.contains(.excludeDisabled) {
|
||||||
|
if let peer = peer.peers[peer.peerId] {
|
||||||
|
if !canSendMessagesToPeer(peer._asPeer()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if filter.contains(.onlyManageable) && filter.contains(.excludeDisabled) {
|
||||||
|
if let peer = peer.peers[peer.peerId] {
|
||||||
|
var canManage = false
|
||||||
|
if case let .legacyGroup(peer) = peer {
|
||||||
|
switch peer.role {
|
||||||
|
case .creator, .admin:
|
||||||
|
canManage = true
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if canManage {
|
||||||
|
} else if case let .channel(peer) = peer, case .group = peer.info, peer.hasPermission(.inviteMembers) {
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if filter.contains(.onlyGroups) {
|
return false
|
||||||
var isGroup: Bool = false
|
|
||||||
if case let .channel(peer) = peer.chatMainPeer, case .group = peer.info {
|
|
||||||
isGroup = true
|
|
||||||
} else if peer.peerId.namespace == Namespaces.Peer.CloudGroup {
|
|
||||||
isGroup = true
|
|
||||||
}
|
|
||||||
if !isGroup {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if filter.contains(.onlyChannels) {
|
|
||||||
if case let .channel(peer) = peer.chatMainPeer, case .broadcast = peer.info {
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if filter.contains(.excludeChannels) {
|
|
||||||
if case let .channel(peer) = peer.chatMainPeer, case .broadcast = peer.info {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if filter.contains(.onlyWriteable) && filter.contains(.excludeDisabled) {
|
|
||||||
if let peer = peer.peers[peer.peerId] {
|
|
||||||
if !canSendMessagesToPeer(peer._asPeer()) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if filter.contains(.onlyManageable) && filter.contains(.excludeDisabled) {
|
|
||||||
if let peer = peer.peers[peer.peerId] {
|
|
||||||
var canManage = false
|
|
||||||
if case let .legacyGroup(peer) = peer {
|
|
||||||
switch peer.role {
|
|
||||||
case .creator, .admin:
|
|
||||||
canManage = true
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if canManage {
|
|
||||||
} else if case let .channel(peer) = peer, case .group = peer.info, peer.hasPermission(.inviteMembers) {
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
return true
|
return true
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let processedView = ChatListNodeView(originalView: update.view, filteredEntries: entries, isLoading: isLoading, filter: filter)
|
let processedView = ChatListNodeView(originalList: update.list, filteredEntries: entries, isLoading: isLoading, filter: filter)
|
||||||
let previousView = previousView.swap(processedView)
|
let previousView = previousView.swap(processedView)
|
||||||
let previousState = previousState.swap(state)
|
let previousState = previousState.swap(state)
|
||||||
|
|
||||||
@ -1185,7 +1194,7 @@ public final class ChatListNode: ListView {
|
|||||||
prepareOnMainQueue = true
|
prepareOnMainQueue = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if previousView?.originalView === update.view {
|
if previousView?.originalList === update.list {
|
||||||
reason = .interactiveChanges
|
reason = .interactiveChanges
|
||||||
updatedScrollPosition = nil
|
updatedScrollPosition = nil
|
||||||
} else {
|
} else {
|
||||||
@ -1216,12 +1225,14 @@ public final class ChatListNode: ListView {
|
|||||||
var didIncludeHiddenByDefaultArchive = false
|
var didIncludeHiddenByDefaultArchive = false
|
||||||
if let previous = previousView {
|
if let previous = previousView {
|
||||||
for entry in previous.filteredEntries {
|
for entry in previous.filteredEntries {
|
||||||
if case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = entry {
|
if case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = entry {
|
||||||
if index.pinningIndex != nil {
|
if case let .chatList(chatListIndex) = index {
|
||||||
previousPinnedChats.append(index.messageIndex.id.peerId)
|
if chatListIndex.pinningIndex != nil {
|
||||||
}
|
previousPinnedChats.append(chatListIndex.messageIndex.id.peerId)
|
||||||
if index.messageIndex.id.peerId == removingPeerId {
|
}
|
||||||
didIncludeRemovingPeerId = true
|
if chatListIndex.messageIndex.id.peerId == removingPeerId {
|
||||||
|
didIncludeRemovingPeerId = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if case let .GroupReferenceEntry(_, _, _, _, _, _, _, _, hiddenByDefault) = entry {
|
} else if case let .GroupReferenceEntry(_, _, _, _, _, _, _, _, hiddenByDefault) = entry {
|
||||||
didIncludeHiddenByDefaultArchive = hiddenByDefault
|
didIncludeHiddenByDefaultArchive = hiddenByDefault
|
||||||
@ -1232,11 +1243,11 @@ public final class ChatListNode: ListView {
|
|||||||
var doesIncludeArchive = false
|
var doesIncludeArchive = false
|
||||||
var doesIncludeHiddenByDefaultArchive = false
|
var doesIncludeHiddenByDefaultArchive = false
|
||||||
for entry in processedView.filteredEntries {
|
for entry in processedView.filteredEntries {
|
||||||
if case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = entry {
|
if case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = entry {
|
||||||
if index.pinningIndex != nil {
|
if case let .chatList(index) = index, index.pinningIndex != nil {
|
||||||
updatedPinnedChats.append(index.messageIndex.id.peerId)
|
updatedPinnedChats.append(index.messageIndex.id.peerId)
|
||||||
}
|
}
|
||||||
if index.messageIndex.id.peerId == removingPeerId {
|
if case let .chatList(index) = index, index.messageIndex.id.peerId == removingPeerId {
|
||||||
doesIncludeRemovingPeerId = true
|
doesIncludeRemovingPeerId = true
|
||||||
}
|
}
|
||||||
} else if case let .GroupReferenceEntry(_, _, _, _, _, _, _, _, hiddenByDefault) = entry {
|
} else if case let .GroupReferenceEntry(_, _, _, _, _, _, _, _, hiddenByDefault) = entry {
|
||||||
@ -1287,7 +1298,7 @@ public final class ChatListNode: ListView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return preparedChatListNodeViewTransition(from: previousView, to: processedView, reason: reason, previewing: previewing, disableAnimations: disableAnimations, account: context.account, scrollPosition: updatedScrollPosition, searchMode: searchMode)
|
return preparedChatListNodeViewTransition(from: previousView, to: processedView, reason: reason, previewing: previewing, disableAnimations: disableAnimations, account: context.account, scrollPosition: updatedScrollPosition, searchMode: searchMode)
|
||||||
|> map({ mappedChatListNodeViewListTransition(context: context, nodeInteraction: nodeInteraction, peerGroupId: groupId, filterData: filterData, mode: mode, transition: $0) })
|
|> map({ mappedChatListNodeViewListTransition(context: context, nodeInteraction: nodeInteraction, location: location, filterData: filterData, mode: mode, transition: $0) })
|
||||||
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
|
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1300,13 +1311,13 @@ public final class ChatListNode: ListView {
|
|||||||
|
|
||||||
self.displayedItemRangeChanged = { [weak self] range, transactionOpaqueState in
|
self.displayedItemRangeChanged = { [weak self] range, transactionOpaqueState in
|
||||||
if let strongSelf = self, let chatListView = (transactionOpaqueState as? ChatListOpaqueTransactionState)?.chatListView {
|
if let strongSelf = self, let chatListView = (transactionOpaqueState as? ChatListOpaqueTransactionState)?.chatListView {
|
||||||
let originalView = chatListView.originalView
|
let originalList = chatListView.originalList
|
||||||
if let range = range.loadedRange {
|
if let range = range.loadedRange {
|
||||||
var location: ChatListNodeLocation?
|
var location: ChatListNodeLocation?
|
||||||
if range.firstIndex < 5, let laterIndex = originalView.laterIndex {
|
if range.firstIndex < 5, let lastItem = originalList.items.last, originalList.hasLater {
|
||||||
location = .navigation(index: laterIndex, filter: strongSelf.chatListFilter)
|
location = .navigation(index: lastItem.index, filter: strongSelf.chatListFilter)
|
||||||
} else if range.firstIndex >= 5, range.lastIndex >= originalView.entries.count - 5, let earlierIndex = originalView.earlierIndex {
|
} else if range.firstIndex >= 5, range.lastIndex >= originalList.items.count - 5, originalList.hasEarlier, let firstItem = originalList.items.first {
|
||||||
location = .navigation(index: earlierIndex, filter: strongSelf.chatListFilter)
|
location = .navigation(index: firstItem.index, filter: strongSelf.chatListFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let location = location, location != strongSelf.currentLocation {
|
if let location = location, location != strongSelf.currentLocation {
|
||||||
@ -1485,6 +1496,10 @@ public final class ChatListNode: ListView {
|
|||||||
|
|
||||||
self.reorderItem = { [weak self] fromIndex, toIndex, transactionOpaqueState -> Signal<Bool, NoError> in
|
self.reorderItem = { [weak self] fromIndex, toIndex, transactionOpaqueState -> Signal<Bool, NoError> in
|
||||||
if let strongSelf = self, let filteredEntries = (transactionOpaqueState as? ChatListOpaqueTransactionState)?.chatListView.filteredEntries {
|
if let strongSelf = self, let filteredEntries = (transactionOpaqueState as? ChatListOpaqueTransactionState)?.chatListView.filteredEntries {
|
||||||
|
guard case let .chatList(groupId) = strongSelf.location else {
|
||||||
|
return .single(false)
|
||||||
|
}
|
||||||
|
|
||||||
if fromIndex >= 0 && fromIndex < filteredEntries.count && toIndex >= 0 && toIndex < filteredEntries.count {
|
if fromIndex >= 0 && fromIndex < filteredEntries.count && toIndex >= 0 && toIndex < filteredEntries.count {
|
||||||
let fromEntry = filteredEntries[filteredEntries.count - 1 - fromIndex]
|
let fromEntry = filteredEntries[filteredEntries.count - 1 - fromIndex]
|
||||||
let toEntry = filteredEntries[filteredEntries.count - 1 - toIndex]
|
let toEntry = filteredEntries[filteredEntries.count - 1 - toIndex]
|
||||||
@ -1492,17 +1507,19 @@ public final class ChatListNode: ListView {
|
|||||||
var referenceId: EngineChatList.PinnedItem.Id?
|
var referenceId: EngineChatList.PinnedItem.Id?
|
||||||
var beforeAll = false
|
var beforeAll = false
|
||||||
switch toEntry {
|
switch toEntry {
|
||||||
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, promoInfo, _, _):
|
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, promoInfo, _, _):
|
||||||
if promoInfo != nil {
|
if promoInfo != nil {
|
||||||
beforeAll = true
|
beforeAll = true
|
||||||
} else {
|
} else {
|
||||||
referenceId = .peer(index.messageIndex.id.peerId)
|
if case let .chatList(chatListIndex) = index {
|
||||||
|
referenceId = .peer(chatListIndex.messageIndex.id.peerId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if case let .index(index) = fromEntry.sortIndex, let _ = index.pinningIndex {
|
if case let .index(index) = fromEntry.sortIndex, case let .chatList(chatListIndex) = index, let _ = chatListIndex.pinningIndex {
|
||||||
let location: TogglePeerChatPinnedLocation
|
let location: TogglePeerChatPinnedLocation
|
||||||
if let chatListFilter = chatListFilter {
|
if let chatListFilter = chatListFilter {
|
||||||
location = .filter(chatListFilter.id)
|
location = .filter(chatListFilter.id)
|
||||||
@ -1517,8 +1534,10 @@ public final class ChatListNode: ListView {
|
|||||||
|
|
||||||
var itemId: EngineChatList.PinnedItem.Id?
|
var itemId: EngineChatList.PinnedItem.Id?
|
||||||
switch fromEntry {
|
switch fromEntry {
|
||||||
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
itemId = .peer(index.messageIndex.id.peerId)
|
if case let .chatList(index) = index {
|
||||||
|
itemId = .peer(index.messageIndex.id.peerId)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -1763,16 +1782,18 @@ public final class ChatListNode: ListView {
|
|||||||
if strongSelf.fillPreloadItems {
|
if strongSelf.fillPreloadItems {
|
||||||
let filteredEntries = transition.chatListView.filteredEntries
|
let filteredEntries = transition.chatListView.filteredEntries
|
||||||
var preloadItems: [ChatHistoryPreloadItem] = []
|
var preloadItems: [ChatHistoryPreloadItem] = []
|
||||||
if transition.chatListView.originalView.laterIndex == nil {
|
if !transition.chatListView.originalList.hasLater {
|
||||||
for entry in filteredEntries.reversed() {
|
for entry in filteredEntries.reversed() {
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .PeerEntry(index, _, _, combinedReadState, isMuted, _, _, _, _, _, _, _, _, _, promoInfo, _, _):
|
case let .PeerEntry(index, _, _, combinedReadState, isMuted, _, _, _, _, _, _, _, _, _, _, promoInfo, _, _):
|
||||||
if promoInfo == nil {
|
if promoInfo == nil {
|
||||||
var hasUnread = false
|
var hasUnread = false
|
||||||
if let combinedReadState = combinedReadState {
|
if let combinedReadState = combinedReadState {
|
||||||
hasUnread = combinedReadState.count > 0
|
hasUnread = combinedReadState.count > 0
|
||||||
}
|
}
|
||||||
preloadItems.append(ChatHistoryPreloadItem(index: index, isMuted: isMuted, hasUnread: hasUnread))
|
if case let .chatList(index) = index {
|
||||||
|
preloadItems.append(ChatHistoryPreloadItem(index: index, isMuted: isMuted, hasUnread: hasUnread))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
@ -1789,7 +1810,7 @@ public final class ChatListNode: ListView {
|
|||||||
if case .chatList = strongSelf.mode {
|
if case .chatList = strongSelf.mode {
|
||||||
let entryCount = transition.chatListView.filteredEntries.count
|
let entryCount = transition.chatListView.filteredEntries.count
|
||||||
if entryCount >= 1 {
|
if entryCount >= 1 {
|
||||||
if case let .index(index) = transition.chatListView.filteredEntries[entryCount - 1].sortIndex, index.pinningIndex != nil {
|
if case let .index(index) = transition.chatListView.filteredEntries[entryCount - 1].sortIndex, case let .chatList(chatListIndex) = index, chatListIndex.pinningIndex != nil {
|
||||||
pinnedOverscroll = true
|
pinnedOverscroll = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1887,10 +1908,10 @@ public final class ChatListNode: ListView {
|
|||||||
for item in transition.insertItems {
|
for item in transition.insertItems {
|
||||||
if let item = item.item as? ChatListItem {
|
if let item = item.item as? ChatListItem {
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
insertedPeerIds.append(peer.peerId)
|
insertedPeerIds.append(peer.peerId)
|
||||||
case .groupReference:
|
case .groupReference:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2002,16 +2023,15 @@ public final class ChatListNode: ListView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func scrollToPosition(_ position: ChatListNodeScrollPosition) {
|
public func scrollToPosition(_ position: ChatListNodeScrollPosition) {
|
||||||
if let view = self.chatListView?.originalView {
|
if let list = self.chatListView?.originalList {
|
||||||
if view.laterIndex == nil {
|
if !list.hasLater {
|
||||||
self.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 })
|
self.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 {
|
} else {
|
||||||
let location: ChatListNodeLocation = .scroll(index: .absoluteUpperBound, sourceIndex: .absoluteLowerBound, scrollPosition: .top(0.0), animated: true, filter: self.chatListFilter)
|
let location: ChatListNodeLocation = .scroll(index: .chatList(.absoluteUpperBound), sourceIndex: .chatList(.absoluteLowerBound), scrollPosition: .top(0.0), animated: true, filter: self.chatListFilter)
|
||||||
self.setChatListLocation(location)
|
self.setChatListLocation(location)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let location: ChatListNodeLocation = .scroll(index: .absoluteUpperBound, sourceIndex: .absoluteLowerBound
|
let location: ChatListNodeLocation = .scroll(index: .chatList(.absoluteUpperBound), sourceIndex: .chatList(.absoluteLowerBound), scrollPosition: .top(0.0), animated: true, filter: self.chatListFilter)
|
||||||
, scrollPosition: .top(0.0), animated: true, filter: self.chatListFilter)
|
|
||||||
self.setChatListLocation(location)
|
self.setChatListLocation(location)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2022,7 +2042,10 @@ public final class ChatListNode: ListView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func relativeUnreadChatListIndex(position: EngineChatList.RelativePosition) -> Signal<EngineChatList.Item.Index?, NoError> {
|
private func relativeUnreadChatListIndex(position: EngineChatList.RelativePosition) -> Signal<EngineChatList.Item.Index?, NoError> {
|
||||||
let groupId = self.groupId
|
guard case let .chatList(groupId) = self.location else {
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
let engine = self.context.engine
|
let engine = self.context.engine
|
||||||
return self.context.sharedContext.accountManager.transaction { transaction -> Signal<EngineChatList.Item.Index?, NoError> in
|
return self.context.sharedContext.accountManager.transaction { transaction -> Signal<EngineChatList.Item.Index?, NoError> in
|
||||||
var filter = true
|
var filter = true
|
||||||
@ -2061,7 +2084,7 @@ public final class ChatListNode: ListView {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch chatListView.filteredEntries[entryCount - i - 1] {
|
switch chatListView.filteredEntries[entryCount - i - 1] {
|
||||||
case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _):
|
case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
if interaction.highlightedChatLocation?.location == ChatLocation.peer(id: peer.peerId) {
|
if interaction.highlightedChatLocation?.location == ChatLocation.peer(id: peer.peerId) {
|
||||||
current = (index, peer.peer!, entryCount - i - 1)
|
current = (index, peer.peer!, entryCount - i - 1)
|
||||||
break outer
|
break outer
|
||||||
@ -2086,11 +2109,11 @@ public final class ChatListNode: ListView {
|
|||||||
let engine = self.context.engine
|
let engine = self.context.engine
|
||||||
let _ = (relativeUnreadChatListIndex(position: position)
|
let _ = (relativeUnreadChatListIndex(position: position)
|
||||||
|> mapToSignal { index -> Signal<(EngineChatList.Item.Index, EnginePeer)?, NoError> in
|
|> mapToSignal { index -> Signal<(EngineChatList.Item.Index, EnginePeer)?, NoError> in
|
||||||
if let index = index {
|
if case let .chatList(index) = index {
|
||||||
return engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: index.messageIndex.id.peerId))
|
return engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: index.messageIndex.id.peerId))
|
||||||
|> map { peer -> (EngineChatList.Item.Index, EnginePeer)? in
|
|> map { peer -> (EngineChatList.Item.Index, EnginePeer)? in
|
||||||
return peer.flatMap { peer -> (EngineChatList.Item.Index, EnginePeer)? in
|
return peer.flatMap { peer -> (EngineChatList.Item.Index, EnginePeer)? in
|
||||||
(index, peer)
|
(.chatList(index), peer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -2101,17 +2124,17 @@ public final class ChatListNode: ListView {
|
|||||||
guard let strongSelf = self, let (index, peer) = indexAndPeer else {
|
guard let strongSelf = self, let (index, peer) = indexAndPeer else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: strongSelf.currentlyVisibleLatestChatListIndex() ?? .absoluteUpperBound, scrollPosition: .center(.top), animated: true, filter: strongSelf.chatListFilter)
|
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: strongSelf.currentlyVisibleLatestChatListIndex() ?? .chatList(.absoluteLowerBound), scrollPosition: .center(.top), animated: true, filter: strongSelf.chatListFilter)
|
||||||
strongSelf.setChatListLocation(location)
|
strongSelf.setChatListLocation(location)
|
||||||
strongSelf.peerSelected?(peer, false, false, nil)
|
strongSelf.peerSelected?(peer, nil, false, false, nil)
|
||||||
})
|
})
|
||||||
case .previous(unread: false), .next(unread: false):
|
case .previous(unread: false), .next(unread: false):
|
||||||
var target: (EngineChatList.Item.Index, EnginePeer)? = nil
|
var target: (EngineChatList.Item.Index, EnginePeer)? = nil
|
||||||
if let current = current, entryCount > 1 {
|
if let current = current, entryCount > 1 {
|
||||||
if current.2 > 0, case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _) = chatListView.filteredEntries[current.2 - 1] {
|
if current.2 > 0, case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _, _) = chatListView.filteredEntries[current.2 - 1] {
|
||||||
next = (index, peer.peer!)
|
next = (index, peer.peer!)
|
||||||
}
|
}
|
||||||
if current.2 <= entryCount - 2, case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _) = chatListView.filteredEntries[current.2 + 1] {
|
if current.2 <= entryCount - 2, case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _, _) = chatListView.filteredEntries[current.2 + 1] {
|
||||||
previous = (index, peer.peer!)
|
previous = (index, peer.peer!)
|
||||||
}
|
}
|
||||||
if case .previous = option {
|
if case .previous = option {
|
||||||
@ -2120,14 +2143,14 @@ public final class ChatListNode: ListView {
|
|||||||
target = next
|
target = next
|
||||||
}
|
}
|
||||||
} else if entryCount > 0 {
|
} else if entryCount > 0 {
|
||||||
if case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _) = chatListView.filteredEntries[entryCount - 1] {
|
if case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _, _, _, _, _, _, _) = chatListView.filteredEntries[entryCount - 1] {
|
||||||
target = (index, peer.peer!)
|
target = (index, peer.peer!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let target = target {
|
if let target = target {
|
||||||
let location: ChatListNodeLocation = .scroll(index: target.0, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true, filter: self.chatListFilter)
|
let location: ChatListNodeLocation = .scroll(index: target.0, sourceIndex: .chatList(.absoluteLowerBound), scrollPosition: .center(.top), animated: true, filter: self.chatListFilter)
|
||||||
self.setChatListLocation(location)
|
self.setChatListLocation(location)
|
||||||
self.peerSelected?(target.1, false, false, nil)
|
self.peerSelected?(target.1, nil, false, false, nil)
|
||||||
}
|
}
|
||||||
case let .peerId(peerId):
|
case let .peerId(peerId):
|
||||||
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||||
@ -2135,7 +2158,7 @@ public final class ChatListNode: ListView {
|
|||||||
guard let strongSelf = self, let peer = peer else {
|
guard let strongSelf = self, let peer = peer else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.peerSelected?(peer, false, false, nil)
|
strongSelf.peerSelected?(peer, nil, false, false, nil)
|
||||||
})
|
})
|
||||||
case let .index(index):
|
case let .index(index):
|
||||||
guard index < 10 else {
|
guard index < 10 else {
|
||||||
@ -2147,14 +2170,18 @@ public final class ChatListNode: ListView {
|
|||||||
guard let self = self else {
|
guard let self = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let _ = (chatListViewForLocation(groupId: self.groupId._asGroup(), location: .initial(count: 10, filter: filter), account: self.context.account)
|
guard case let .chatList(groupId) = self.location else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let _ = (chatListViewForLocation(chatListLocation: .chatList(groupId: groupId), location: .initial(count: 10, filter: filter), account: self.context.account)
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).start(next: { update in
|
|> deliverOnMainQueue).start(next: { update in
|
||||||
let entries = update.view.entries
|
let items = update.list.items
|
||||||
if entries.count > index, case let .MessageEntry(index, _, _, _, _, renderedPeer, _, _, _, _) = entries[9 - index - 1] {
|
if items.count > index {
|
||||||
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: .absoluteLowerBound, scrollPosition: .center(.top), animated: true, filter: filter)
|
let item = items[9 - index - 1]
|
||||||
|
let location: ChatListNodeLocation = .scroll(index: item.index, sourceIndex: .chatList(.absoluteLowerBound), scrollPosition: .center(.top), animated: true, filter: filter)
|
||||||
self.setChatListLocation(location)
|
self.setChatListLocation(location)
|
||||||
self.peerSelected?(EnginePeer(renderedPeer.peer!), false, false, nil)
|
self.peerSelected?(EnginePeer(item.renderedPeer.peer!._asPeer()), nil, false, false, nil)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -2194,7 +2221,7 @@ public final class ChatListNode: ListView {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch chatListView.filteredEntries[entryCount - i - 1] {
|
switch chatListView.filteredEntries[entryCount - i - 1] {
|
||||||
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
return index
|
return index
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
@ -2210,7 +2237,7 @@ public final class ChatListNode: ListView {
|
|||||||
if resultPeer == nil, let itemNode = itemNode as? ListViewItemNode, itemNode.frame.contains(point) {
|
if resultPeer == nil, let itemNode = itemNode as? ListViewItemNode, itemNode.frame.contains(point) {
|
||||||
if let itemNode = itemNode as? ChatListItemNode, let item = itemNode.item {
|
if let itemNode = itemNode as? ChatListItemNode, let item = itemNode.item {
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
resultPeer = peer.peer
|
resultPeer = peer.peer
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
@ -10,6 +10,7 @@ enum ChatListNodeEntryId: Hashable {
|
|||||||
case Header
|
case Header
|
||||||
case Hole(Int64)
|
case Hole(Int64)
|
||||||
case PeerId(Int64)
|
case PeerId(Int64)
|
||||||
|
case ThreadId(Int64)
|
||||||
case GroupId(EngineChatList.Group)
|
case GroupId(EngineChatList.Group)
|
||||||
case ArchiveIntro
|
case ArchiveIntro
|
||||||
case additionalCategory(Int)
|
case additionalCategory(Int)
|
||||||
@ -46,7 +47,7 @@ public enum ChatListNodeEntryPromoInfo: Equatable {
|
|||||||
|
|
||||||
enum ChatListNodeEntry: Comparable, Identifiable {
|
enum ChatListNodeEntry: Comparable, Identifiable {
|
||||||
case HeaderEntry
|
case HeaderEntry
|
||||||
case PeerEntry(index: EngineChatList.Item.Index, presentationData: ChatListPresentationData, messages: [EngineMessage], readState: EnginePeerReadCounters?, isRemovedFromTotalUnreadCount: Bool, draftState: ChatListItemContent.DraftState?, peer: EngineRenderedPeer, presence: EnginePeer.Presence?, hasUnseenMentions: Bool, hasUnseenReactions: Bool, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, inputActivities: [(EnginePeer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, hasFailedMessages: Bool, isContact: Bool)
|
case PeerEntry(index: EngineChatList.Item.Index, presentationData: ChatListPresentationData, messages: [EngineMessage], readState: EnginePeerReadCounters?, isRemovedFromTotalUnreadCount: Bool, draftState: ChatListItemContent.DraftState?, peer: EngineRenderedPeer, threadInfo: EngineMessageHistoryThreads.Info?, presence: EnginePeer.Presence?, hasUnseenMentions: Bool, hasUnseenReactions: Bool, editing: Bool, hasActiveRevealControls: Bool, selected: Bool, inputActivities: [(EnginePeer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, hasFailedMessages: Bool, isContact: Bool)
|
||||||
case HoleEntry(EngineMessage.Index, theme: PresentationTheme)
|
case HoleEntry(EngineMessage.Index, theme: PresentationTheme)
|
||||||
case GroupReferenceEntry(index: EngineChatList.Item.Index, presentationData: ChatListPresentationData, groupId: EngineChatList.Group, peers: [EngineChatList.GroupItem.Item], message: EngineMessage?, editing: Bool, unreadCount: Int, revealed: Bool, hiddenByDefault: Bool)
|
case GroupReferenceEntry(index: EngineChatList.Item.Index, presentationData: ChatListPresentationData, groupId: EngineChatList.Group, peers: [EngineChatList.GroupItem.Item], message: EngineMessage?, editing: Bool, unreadCount: Int, revealed: Bool, hiddenByDefault: Bool)
|
||||||
case ArchiveIntro(presentationData: ChatListPresentationData)
|
case ArchiveIntro(presentationData: ChatListPresentationData)
|
||||||
@ -55,15 +56,15 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
|||||||
var sortIndex: ChatListNodeEntrySortIndex {
|
var sortIndex: ChatListNodeEntrySortIndex {
|
||||||
switch self {
|
switch self {
|
||||||
case .HeaderEntry:
|
case .HeaderEntry:
|
||||||
return .index(EngineChatList.Item.Index.absoluteUpperBound)
|
return .index(.chatList(.absoluteUpperBound))
|
||||||
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
return .index(index)
|
return .index(index)
|
||||||
case let .HoleEntry(holeIndex, _):
|
case let .HoleEntry(holeIndex, _):
|
||||||
return .index(EngineChatList.Item.Index(pinningIndex: nil, messageIndex: holeIndex))
|
return .index(.chatList(EngineChatList.Item.Index.ChatList(pinningIndex: nil, messageIndex: holeIndex)))
|
||||||
case let .GroupReferenceEntry(index, _, _, _, _, _, _, _, _):
|
case let .GroupReferenceEntry(index, _, _, _, _, _, _, _, _):
|
||||||
return .index(index)
|
return .index(index)
|
||||||
case .ArchiveIntro:
|
case .ArchiveIntro:
|
||||||
return .index(EngineChatList.Item.Index.absoluteUpperBound.successor)
|
return .index(.chatList(EngineChatList.Item.Index.ChatList.absoluteUpperBound.successor))
|
||||||
case let .AdditionalCategory(index, _, _, _, _, _, _):
|
case let .AdditionalCategory(index, _, _, _, _, _, _):
|
||||||
return .additionalCategory(index)
|
return .additionalCategory(index)
|
||||||
}
|
}
|
||||||
@ -73,8 +74,13 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
|||||||
switch self {
|
switch self {
|
||||||
case .HeaderEntry:
|
case .HeaderEntry:
|
||||||
return .Header
|
return .Header
|
||||||
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
return .PeerId(index.messageIndex.id.peerId.toInt64())
|
switch index {
|
||||||
|
case let .chatList(index):
|
||||||
|
return .PeerId(index.messageIndex.id.peerId.toInt64())
|
||||||
|
case let .forum(_, threadId, _, _):
|
||||||
|
return .ThreadId(threadId)
|
||||||
|
}
|
||||||
case let .HoleEntry(holeIndex, _):
|
case let .HoleEntry(holeIndex, _):
|
||||||
return .Hole(Int64(holeIndex.id.id))
|
return .Hole(Int64(holeIndex.id.id))
|
||||||
case let .GroupReferenceEntry(_, _, groupId, _, _, _, _, _, _):
|
case let .GroupReferenceEntry(_, _, groupId, _, _, _, _, _, _):
|
||||||
@ -98,9 +104,9 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .PeerEntry(lhsIndex, lhsPresentationData, lhsMessages, lhsUnreadCount, lhsIsRemovedFromTotalUnreadCount, lhsEmbeddedState, lhsPeer, lhsPresence, lhsHasUnseenMentions, lhsHasUnseenReactions, lhsEditing, lhsHasRevealControls, lhsSelected, lhsInputActivities, lhsAd, lhsHasFailedMessages, lhsIsContact):
|
case let .PeerEntry(lhsIndex, lhsPresentationData, lhsMessages, lhsUnreadCount, lhsIsRemovedFromTotalUnreadCount, lhsEmbeddedState, lhsPeer, lhsThreadInfo, lhsPresence, lhsHasUnseenMentions, lhsHasUnseenReactions, lhsEditing, lhsHasRevealControls, lhsSelected, lhsInputActivities, lhsAd, lhsHasFailedMessages, lhsIsContact):
|
||||||
switch rhs {
|
switch rhs {
|
||||||
case let .PeerEntry(rhsIndex, rhsPresentationData, rhsMessages, rhsUnreadCount, rhsIsRemovedFromTotalUnreadCount, rhsEmbeddedState, rhsPeer, rhsPresence, rhsHasUnseenMentions, rhsHasUnseenReactions, rhsEditing, rhsHasRevealControls, rhsSelected, rhsInputActivities, rhsAd, rhsHasFailedMessages, rhsIsContact):
|
case let .PeerEntry(rhsIndex, rhsPresentationData, rhsMessages, rhsUnreadCount, rhsIsRemovedFromTotalUnreadCount, rhsEmbeddedState, rhsPeer, rhsThreadInfo, rhsPresence, rhsHasUnseenMentions, rhsHasUnseenReactions, rhsEditing, rhsHasRevealControls, rhsSelected, rhsInputActivities, rhsAd, rhsHasFailedMessages, rhsIsContact):
|
||||||
if lhsIndex != rhsIndex {
|
if lhsIndex != rhsIndex {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -162,6 +168,9 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
|||||||
if lhsPeer != rhsPeer {
|
if lhsPeer != rhsPeer {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhsThreadInfo != rhsThreadInfo {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhsHasUnseenMentions != rhsHasUnseenMentions {
|
if lhsHasUnseenMentions != rhsHasUnseenMentions {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -277,8 +286,8 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func offsetPinnedIndex(_ index: EngineChatList.Item.Index, offset: UInt16) -> EngineChatList.Item.Index {
|
private func offsetPinnedIndex(_ index: EngineChatList.Item.Index, offset: UInt16) -> EngineChatList.Item.Index {
|
||||||
if let pinningIndex = index.pinningIndex {
|
if case let .chatList(index) = index, let pinningIndex = index.pinningIndex {
|
||||||
return EngineChatList.Item.Index(pinningIndex: pinningIndex + offset, messageIndex: index.messageIndex)
|
return .chatList(EngineChatList.Item.Index.ChatList(pinningIndex: pinningIndex + offset, messageIndex: index.messageIndex))
|
||||||
} else {
|
} else {
|
||||||
return index
|
return index
|
||||||
}
|
}
|
||||||
@ -310,16 +319,20 @@ func chatListNodeEntriesForView(_ view: EngineChatList, state: ChatListNodeState
|
|||||||
pinnedIndexOffset += UInt16(filteredAdditionalItemEntries.count)
|
pinnedIndexOffset += UInt16(filteredAdditionalItemEntries.count)
|
||||||
}
|
}
|
||||||
loop: for entry in view.items {
|
loop: for entry in view.items {
|
||||||
//case let .MessageEntry(index, messages, combinedReadState, isRemovedFromTotalUnreadCount, embeddedState, peer, peerPresence, summaryInfo, hasFailed, isContact):
|
var peerId: EnginePeer.Id?
|
||||||
if let savedMessagesPeer = savedMessagesPeer, savedMessagesPeer.id == entry.index.messageIndex.id.peerId || foundPeerIds.contains(entry.index.messageIndex.id.peerId) {
|
if case let .chatList(index) = entry.index {
|
||||||
|
peerId = index.messageIndex.id.peerId
|
||||||
|
}
|
||||||
|
|
||||||
|
if let savedMessagesPeer = savedMessagesPeer, let peerId = peerId, savedMessagesPeer.id == peerId || foundPeerIds.contains(peerId) {
|
||||||
continue loop
|
continue loop
|
||||||
}
|
}
|
||||||
if state.pendingRemovalPeerIds.contains(entry.index.messageIndex.id.peerId) {
|
if let peerId = peerId, state.pendingRemovalPeerIds.contains(peerId) {
|
||||||
continue loop
|
continue loop
|
||||||
}
|
}
|
||||||
var updatedMessages = entry.messages
|
var updatedMessages = entry.messages
|
||||||
var updatedCombinedReadState = entry.readCounters
|
var updatedCombinedReadState = entry.readCounters
|
||||||
if state.pendingClearHistoryPeerIds.contains(entry.index.messageIndex.id.peerId) {
|
if let peerId = peerId, state.pendingClearHistoryPeerIds.contains(peerId) {
|
||||||
updatedMessages = []
|
updatedMessages = []
|
||||||
updatedCombinedReadState = nil
|
updatedCombinedReadState = nil
|
||||||
}
|
}
|
||||||
@ -328,8 +341,21 @@ func chatListNodeEntriesForView(_ view: EngineChatList, state: ChatListNodeState
|
|||||||
if let draft = entry.draft {
|
if let draft = entry.draft {
|
||||||
draftState = ChatListItemContent.DraftState(draft: draft)
|
draftState = ChatListItemContent.DraftState(draft: draft)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hasActiveRevealControls = false
|
||||||
|
if let peerId {
|
||||||
|
hasActiveRevealControls = peerId == state.peerIdWithRevealedOptions
|
||||||
|
}
|
||||||
|
var isSelected = false
|
||||||
|
if let peerId {
|
||||||
|
isSelected = state.selectedPeerIds.contains(peerId)
|
||||||
|
}
|
||||||
|
var inputActivities: [(EnginePeer, PeerInputActivity)]?
|
||||||
|
if let peerId {
|
||||||
|
inputActivities = state.peerInputActivities?.activities[peerId]
|
||||||
|
}
|
||||||
|
|
||||||
result.append(.PeerEntry(index: offsetPinnedIndex(entry.index, offset: pinnedIndexOffset), presentationData: state.presentationData, messages: updatedMessages, readState: updatedCombinedReadState, isRemovedFromTotalUnreadCount: entry.isMuted, draftState: draftState, peer: entry.renderedPeer, presence: entry.presence, hasUnseenMentions: entry.hasUnseenMentions, hasUnseenReactions: entry.hasUnseenReactions, editing: state.editing, hasActiveRevealControls: entry.index.messageIndex.id.peerId == state.peerIdWithRevealedOptions, selected: state.selectedPeerIds.contains(entry.index.messageIndex.id.peerId), inputActivities: state.peerInputActivities?.activities[entry.index.messageIndex.id.peerId], promoInfo: nil, hasFailedMessages: entry.hasFailed, isContact: entry.isContact))
|
result.append(.PeerEntry(index: offsetPinnedIndex(entry.index, offset: pinnedIndexOffset), presentationData: state.presentationData, messages: updatedMessages, readState: updatedCombinedReadState, isRemovedFromTotalUnreadCount: entry.isMuted, draftState: draftState, peer: entry.renderedPeer, threadInfo: entry.threadInfo, presence: entry.presence, hasUnseenMentions: entry.hasUnseenMentions, hasUnseenReactions: entry.hasUnseenReactions, editing: state.editing, hasActiveRevealControls: hasActiveRevealControls, selected: isSelected, inputActivities: inputActivities, promoInfo: nil, hasFailedMessages: entry.hasFailed, isContact: entry.isContact))
|
||||||
}
|
}
|
||||||
if !view.hasLater {
|
if !view.hasLater {
|
||||||
var pinningIndex: UInt16 = UInt16(pinnedIndexOffset == 0 ? 0 : (pinnedIndexOffset - 1))
|
var pinningIndex: UInt16 = UInt16(pinnedIndexOffset == 0 ? 0 : (pinnedIndexOffset - 1))
|
||||||
@ -345,13 +371,14 @@ func chatListNodeEntriesForView(_ view: EngineChatList, state: ChatListNodeState
|
|||||||
|
|
||||||
let messageIndex = EngineMessage.Index(id: EngineMessage.Id(peerId: peer.0.id, namespace: 0, id: 0), timestamp: 1)
|
let messageIndex = EngineMessage.Index(id: EngineMessage.Id(peerId: peer.0.id, namespace: 0, id: 0), timestamp: 1)
|
||||||
result.append(.PeerEntry(
|
result.append(.PeerEntry(
|
||||||
index: EngineChatList.Item.Index(pinningIndex: foundPinningIndex, messageIndex: messageIndex),
|
index: .chatList(EngineChatList.Item.Index.ChatList(pinningIndex: foundPinningIndex, messageIndex: messageIndex)),
|
||||||
presentationData: state.presentationData,
|
presentationData: state.presentationData,
|
||||||
messages: [],
|
messages: [],
|
||||||
readState: nil,
|
readState: nil,
|
||||||
isRemovedFromTotalUnreadCount: false,
|
isRemovedFromTotalUnreadCount: false,
|
||||||
draftState: nil,
|
draftState: nil,
|
||||||
peer: EngineRenderedPeer(peerId: peer.0.id, peers: peers, associatedMedia: [:]),
|
peer: EngineRenderedPeer(peerId: peer.0.id, peers: peers, associatedMedia: [:]),
|
||||||
|
threadInfo: nil,
|
||||||
presence: nil,
|
presence: nil,
|
||||||
hasUnseenMentions: false,
|
hasUnseenMentions: false,
|
||||||
hasUnseenReactions: false,
|
hasUnseenReactions: false,
|
||||||
@ -369,10 +396,14 @@ func chatListNodeEntriesForView(_ view: EngineChatList, state: ChatListNodeState
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.append(.PeerEntry(index: EngineChatList.Item.Index.absoluteUpperBound.predecessor, presentationData: state.presentationData, messages: [], readState: nil, isRemovedFromTotalUnreadCount: false, draftState: nil, peer: EngineRenderedPeer(peerId: savedMessagesPeer.id, peers: [savedMessagesPeer.id: savedMessagesPeer], associatedMedia: [:]), presence: nil, hasUnseenMentions: false, hasUnseenReactions: false, editing: state.editing, hasActiveRevealControls: false, selected: state.selectedPeerIds.contains(savedMessagesPeer.id), inputActivities: nil, promoInfo: nil, hasFailedMessages: false, isContact: false))
|
result.append(.PeerEntry(index: .chatList(EngineChatList.Item.Index.ChatList.absoluteUpperBound.predecessor), presentationData: state.presentationData, messages: [], readState: nil, isRemovedFromTotalUnreadCount: false, draftState: nil, peer: EngineRenderedPeer(peerId: savedMessagesPeer.id, peers: [savedMessagesPeer.id: savedMessagesPeer], associatedMedia: [:]), threadInfo: nil, presence: nil, hasUnseenMentions: false, hasUnseenReactions: false, editing: state.editing, hasActiveRevealControls: false, selected: state.selectedPeerIds.contains(savedMessagesPeer.id), inputActivities: nil, promoInfo: nil, hasFailedMessages: false, isContact: false))
|
||||||
} else {
|
} else {
|
||||||
if !filteredAdditionalItemEntries.isEmpty {
|
if !filteredAdditionalItemEntries.isEmpty {
|
||||||
for item in filteredAdditionalItemEntries.reversed() {
|
for item in filteredAdditionalItemEntries.reversed() {
|
||||||
|
guard case let .chatList(index) = item.item.index else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
let promoInfo: ChatListNodeEntryPromoInfo
|
let promoInfo: ChatListNodeEntryPromoInfo
|
||||||
switch item.promoInfo.content {
|
switch item.promoInfo.content {
|
||||||
case .proxy:
|
case .proxy:
|
||||||
@ -381,21 +412,26 @@ func chatListNodeEntriesForView(_ view: EngineChatList, state: ChatListNodeState
|
|||||||
promoInfo = .psa(type: type, message: message)
|
promoInfo = .psa(type: type, message: message)
|
||||||
}
|
}
|
||||||
let draftState = item.item.draft.flatMap(ChatListItemContent.DraftState.init)
|
let draftState = item.item.draft.flatMap(ChatListItemContent.DraftState.init)
|
||||||
|
|
||||||
|
let peerId = index.messageIndex.id.peerId
|
||||||
|
let isSelected = state.selectedPeerIds.contains(peerId)
|
||||||
|
|
||||||
result.append(.PeerEntry(
|
result.append(.PeerEntry(
|
||||||
index: EngineChatList.Item.Index(pinningIndex: pinningIndex, messageIndex: item.item.index.messageIndex),
|
index: .chatList(EngineChatList.Item.Index.ChatList(pinningIndex: pinningIndex, messageIndex: index.messageIndex)),
|
||||||
presentationData: state.presentationData,
|
presentationData: state.presentationData,
|
||||||
messages: item.item.messages,
|
messages: item.item.messages,
|
||||||
readState: item.item.readCounters,
|
readState: item.item.readCounters,
|
||||||
isRemovedFromTotalUnreadCount: item.item.isMuted,
|
isRemovedFromTotalUnreadCount: item.item.isMuted,
|
||||||
draftState: draftState,
|
draftState: draftState,
|
||||||
peer: item.item.renderedPeer,
|
peer: item.item.renderedPeer,
|
||||||
|
threadInfo: item.item.threadInfo,
|
||||||
presence: item.item.presence,
|
presence: item.item.presence,
|
||||||
hasUnseenMentions: item.item.hasUnseenMentions,
|
hasUnseenMentions: item.item.hasUnseenMentions,
|
||||||
hasUnseenReactions: item.item.hasUnseenReactions,
|
hasUnseenReactions: item.item.hasUnseenReactions,
|
||||||
editing: state.editing,
|
editing: state.editing,
|
||||||
hasActiveRevealControls: item.item.index.messageIndex.id.peerId == state.peerIdWithRevealedOptions,
|
hasActiveRevealControls: peerId == state.peerIdWithRevealedOptions,
|
||||||
selected: state.selectedPeerIds.contains(item.item.index.messageIndex.id.peerId),
|
selected: isSelected,
|
||||||
inputActivities: state.peerInputActivities?.activities[item.item.index.messageIndex.id.peerId],
|
inputActivities: state.peerInputActivities?.activities[peerId],
|
||||||
promoInfo: promoInfo,
|
promoInfo: promoInfo,
|
||||||
hasFailedMessages: item.item.hasFailed,
|
hasFailedMessages: item.item.hasFailed,
|
||||||
isContact: item.item.isContact
|
isContact: item.item.isContact
|
||||||
@ -411,7 +447,7 @@ func chatListNodeEntriesForView(_ view: EngineChatList, state: ChatListNodeState
|
|||||||
for groupReference in view.groupItems {
|
for groupReference in view.groupItems {
|
||||||
let messageIndex = EngineMessage.Index(id: EngineMessage.Id(peerId: EnginePeer.Id(0), namespace: 0, id: 0), timestamp: 1)
|
let messageIndex = EngineMessage.Index(id: EngineMessage.Id(peerId: EnginePeer.Id(0), namespace: 0, id: 0), timestamp: 1)
|
||||||
result.append(.GroupReferenceEntry(
|
result.append(.GroupReferenceEntry(
|
||||||
index: EngineChatList.Item.Index(pinningIndex: pinningIndex, messageIndex: messageIndex),
|
index: .chatList(EngineChatList.Item.Index.ChatList(pinningIndex: pinningIndex, messageIndex: messageIndex)),
|
||||||
presentationData: state.presentationData,
|
presentationData: state.presentationData,
|
||||||
groupId: groupReference.id,
|
groupId: groupReference.id,
|
||||||
peers: groupReference.items,
|
peers: groupReference.items,
|
||||||
|
@ -4,11 +4,12 @@ import TelegramCore
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import Display
|
import Display
|
||||||
import TelegramUIPreferences
|
import TelegramUIPreferences
|
||||||
|
import AccountContext
|
||||||
|
|
||||||
enum ChatListNodeLocation: Equatable {
|
enum ChatListNodeLocation: Equatable {
|
||||||
case initial(count: Int, filter: ChatListFilter?)
|
case initial(count: Int, filter: ChatListFilter?)
|
||||||
case navigation(index: ChatListIndex, filter: ChatListFilter?)
|
case navigation(index: EngineChatList.Item.Index, filter: ChatListFilter?)
|
||||||
case scroll(index: ChatListIndex, sourceIndex: ChatListIndex, scrollPosition: ListViewScrollPosition, animated: Bool, filter: ChatListFilter?)
|
case scroll(index: EngineChatList.Item.Index, sourceIndex: EngineChatList.Item.Index, scrollPosition: ListViewScrollPosition, animated: Bool, filter: ChatListFilter?)
|
||||||
|
|
||||||
var filter: ChatListFilter? {
|
var filter: ChatListFilter? {
|
||||||
switch self {
|
switch self {
|
||||||
@ -23,7 +24,7 @@ enum ChatListNodeLocation: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ChatListNodeViewUpdate {
|
struct ChatListNodeViewUpdate {
|
||||||
let view: ChatListView
|
let list: EngineChatList
|
||||||
let type: ViewUpdateType
|
let type: ViewUpdateType
|
||||||
let scrollPosition: ChatListNodeViewScrollPosition?
|
let scrollPosition: ChatListNodeViewScrollPosition?
|
||||||
}
|
}
|
||||||
@ -109,25 +110,30 @@ public func chatListFilterPredicate(filter: ChatListFilterData) -> ChatListFilte
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func chatListViewForLocation(groupId: PeerGroupId, location: ChatListNodeLocation, account: Account) -> Signal<ChatListNodeViewUpdate, NoError> {
|
func chatListViewForLocation(chatListLocation: ChatListControllerLocation, location: ChatListNodeLocation, account: Account) -> Signal<ChatListNodeViewUpdate, NoError> {
|
||||||
let filterPredicate: ChatListFilterPredicate?
|
switch chatListLocation {
|
||||||
if let filter = location.filter, case let .filter(_, _, _, data) = filter {
|
case let .chatList(groupId):
|
||||||
filterPredicate = chatListFilterPredicate(filter: data)
|
let filterPredicate: ChatListFilterPredicate?
|
||||||
} else {
|
if let filter = location.filter, case let .filter(_, _, _, data) = filter {
|
||||||
filterPredicate = nil
|
filterPredicate = chatListFilterPredicate(filter: data)
|
||||||
}
|
} else {
|
||||||
|
filterPredicate = nil
|
||||||
switch location {
|
}
|
||||||
|
|
||||||
|
switch location {
|
||||||
case let .initial(count, _):
|
case let .initial(count, _):
|
||||||
let signal: Signal<(ChatListView, ViewUpdateType), NoError>
|
let signal: Signal<(ChatListView, ViewUpdateType), NoError>
|
||||||
signal = account.viewTracker.tailChatListView(groupId: groupId, filterPredicate: filterPredicate, count: count)
|
signal = account.viewTracker.tailChatListView(groupId: groupId._asGroup(), filterPredicate: filterPredicate, count: count)
|
||||||
return signal
|
return signal
|
||||||
|> map { view, updateType -> ChatListNodeViewUpdate in
|
|> map { view, updateType -> ChatListNodeViewUpdate in
|
||||||
return ChatListNodeViewUpdate(view: view, type: updateType, scrollPosition: nil)
|
return ChatListNodeViewUpdate(list: EngineChatList(view), type: updateType, scrollPosition: nil)
|
||||||
}
|
}
|
||||||
case let .navigation(index, _):
|
case let .navigation(index, _):
|
||||||
|
guard case let .chatList(index) = index else {
|
||||||
|
return .never()
|
||||||
|
}
|
||||||
var first = true
|
var first = true
|
||||||
return account.viewTracker.aroundChatListView(groupId: groupId, filterPredicate: filterPredicate, index: index, count: 80)
|
return account.viewTracker.aroundChatListView(groupId: groupId._asGroup(), filterPredicate: filterPredicate, index: index, count: 80)
|
||||||
|> map { view, updateType -> ChatListNodeViewUpdate in
|
|> map { view, updateType -> ChatListNodeViewUpdate in
|
||||||
let genericType: ViewUpdateType
|
let genericType: ViewUpdateType
|
||||||
if first {
|
if first {
|
||||||
@ -136,13 +142,17 @@ func chatListViewForLocation(groupId: PeerGroupId, location: ChatListNodeLocatio
|
|||||||
} else {
|
} else {
|
||||||
genericType = updateType
|
genericType = updateType
|
||||||
}
|
}
|
||||||
return ChatListNodeViewUpdate(view: view, type: genericType, scrollPosition: nil)
|
return ChatListNodeViewUpdate(list: EngineChatList(view), type: genericType, scrollPosition: nil)
|
||||||
}
|
}
|
||||||
case let .scroll(index, sourceIndex, scrollPosition, animated, _):
|
case let .scroll(index, sourceIndex, scrollPosition, animated, _):
|
||||||
let directionHint: ListViewScrollToItemDirectionHint = sourceIndex > index ? .Down : .Up
|
guard case let .chatList(index) = index else {
|
||||||
|
return .never()
|
||||||
|
}
|
||||||
|
|
||||||
|
let directionHint: ListViewScrollToItemDirectionHint = sourceIndex > .chatList(index) ? .Down : .Up
|
||||||
let chatScrollPosition: ChatListNodeViewScrollPosition = .index(index: index, position: scrollPosition, directionHint: directionHint, animated: animated)
|
let chatScrollPosition: ChatListNodeViewScrollPosition = .index(index: index, position: scrollPosition, directionHint: directionHint, animated: animated)
|
||||||
var first = true
|
var first = true
|
||||||
return account.viewTracker.aroundChatListView(groupId: groupId, filterPredicate: filterPredicate, index: index, count: 80)
|
return account.viewTracker.aroundChatListView(groupId: groupId._asGroup(), filterPredicate: filterPredicate, index: index, count: 80)
|
||||||
|> map { view, updateType -> ChatListNodeViewUpdate in
|
|> map { view, updateType -> ChatListNodeViewUpdate in
|
||||||
let genericType: ViewUpdateType
|
let genericType: ViewUpdateType
|
||||||
let scrollPosition: ChatListNodeViewScrollPosition? = first ? chatScrollPosition : nil
|
let scrollPosition: ChatListNodeViewScrollPosition? = first ? chatScrollPosition : nil
|
||||||
@ -152,7 +162,60 @@ func chatListViewForLocation(groupId: PeerGroupId, location: ChatListNodeLocatio
|
|||||||
} else {
|
} else {
|
||||||
genericType = updateType
|
genericType = updateType
|
||||||
}
|
}
|
||||||
return ChatListNodeViewUpdate(view: view, type: genericType, scrollPosition: scrollPosition)
|
return ChatListNodeViewUpdate(list: EngineChatList(view), type: genericType, scrollPosition: scrollPosition)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
case let .forum(peerId):
|
||||||
|
let viewKey: PostboxViewKey = .messageHistoryThreadIndex(id: peerId)
|
||||||
|
var isFirst = false
|
||||||
|
return account.postbox.combinedView(keys: [viewKey])
|
||||||
|
|> map { views -> ChatListNodeViewUpdate in
|
||||||
|
guard let view = views.views[viewKey] as? MessageHistoryThreadIndexView else {
|
||||||
|
preconditionFailure()
|
||||||
|
}
|
||||||
|
|
||||||
|
var items: [EngineChatList.Item] = []
|
||||||
|
for item in view.items {
|
||||||
|
guard let peer = view.peer else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
guard let info = item.info.get(EngineMessageHistoryThreads.Info.self) else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
items.append(EngineChatList.Item(
|
||||||
|
id: .forum(item.id),
|
||||||
|
index: .forum(timestamp: item.index.timestamp, threadId: item.id, namespace: item.index.id.namespace, id: item.index.id.id),
|
||||||
|
messages: item.topMessage.flatMap { [EngineMessage($0)] } ?? [],
|
||||||
|
readCounters: nil,
|
||||||
|
isMuted: false,
|
||||||
|
draft: nil,
|
||||||
|
threadInfo: info,
|
||||||
|
renderedPeer: EngineRenderedPeer(peer: EnginePeer(peer)),
|
||||||
|
presence: nil,
|
||||||
|
hasUnseenMentions: false,
|
||||||
|
hasUnseenReactions: false,
|
||||||
|
hasFailed: false,
|
||||||
|
isContact: false
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
let list = EngineChatList(
|
||||||
|
items: items.reversed(),
|
||||||
|
groupItems: [],
|
||||||
|
additionalItems: [],
|
||||||
|
hasEarlier: false,
|
||||||
|
hasLater: false,
|
||||||
|
isLoading: false
|
||||||
|
)
|
||||||
|
|
||||||
|
let type: ViewUpdateType
|
||||||
|
if isFirst {
|
||||||
|
type = .Initial
|
||||||
|
} else {
|
||||||
|
type = .Generic
|
||||||
|
}
|
||||||
|
isFirst = false
|
||||||
|
return ChatListNodeViewUpdate(list: list, type: type, scrollPosition: nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ final class ChatListInputActivitiesNode: ASDisplayNode {
|
|||||||
self.addSubnode(self.activityNode)
|
self.addSubnode(self.activityNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func asyncLayout() -> (CGSize, ChatListPresentationData, UIColor, EnginePeer.Id, [(EnginePeer, PeerInputActivity)]) -> (CGSize, () -> Void) {
|
func asyncLayout() -> (CGSize, ChatListPresentationData, UIColor, EnginePeer.Id?, [(EnginePeer, PeerInputActivity)]) -> (CGSize, () -> Void) {
|
||||||
return { [weak self] boundingSize, presentationData, color, peerId, activities in
|
return { [weak self] boundingSize, presentationData, color, peerId, activities in
|
||||||
let strings = presentationData.strings
|
let strings = presentationData.strings
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import SearchUI
|
|||||||
import TelegramUIPreferences
|
import TelegramUIPreferences
|
||||||
|
|
||||||
struct ChatListNodeView {
|
struct ChatListNodeView {
|
||||||
let originalView: ChatListView
|
let originalList: EngineChatList
|
||||||
let filteredEntries: [ChatListNodeEntry]
|
let filteredEntries: [ChatListNodeEntry]
|
||||||
let isLoading: Bool
|
let isLoading: Bool
|
||||||
let filter: ChatListFilter?
|
let filter: ChatListFilter?
|
||||||
@ -52,7 +52,7 @@ enum ChatListNodeViewScrollPosition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func preparedChatListNodeViewTransition(from fromView: ChatListNodeView?, to toView: ChatListNodeView, reason: ChatListNodeViewTransitionReason, previewing: Bool, disableAnimations: Bool, account: Account, scrollPosition: ChatListNodeViewScrollPosition?, searchMode: Bool) -> Signal<ChatListNodeViewTransition, NoError> {
|
func preparedChatListNodeViewTransition(from fromView: ChatListNodeView?, to toView: ChatListNodeView, reason: ChatListNodeViewTransitionReason, previewing: Bool, disableAnimations: Bool, account: Account, scrollPosition: ChatListNodeViewScrollPosition?, searchMode: Bool) -> Signal<ChatListNodeViewTransition, NoError> {
|
||||||
return Signal { subscriber in
|
return Signal<ChatListNodeViewTransition, NoError> { subscriber in
|
||||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromView?.filteredEntries ?? [], rightList: toView.filteredEntries)
|
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromView?.filteredEntries ?? [], rightList: toView.filteredEntries)
|
||||||
|
|
||||||
var adjustedDeleteIndices: [ListViewDeleteItem] = []
|
var adjustedDeleteIndices: [ListViewDeleteItem] = []
|
||||||
@ -74,44 +74,40 @@ func preparedChatListNodeViewTransition(from fromView: ChatListNodeView?, to toV
|
|||||||
var scrollToItem: ListViewScrollToItem?
|
var scrollToItem: ListViewScrollToItem?
|
||||||
|
|
||||||
switch reason {
|
switch reason {
|
||||||
case .initial:
|
case .initial:
|
||||||
let _ = options.insert(.LowLatency)
|
let _ = options.insert(.LowLatency)
|
||||||
let _ = options.insert(.Synchronous)
|
let _ = options.insert(.Synchronous)
|
||||||
case .interactiveChanges:
|
case .interactiveChanges:
|
||||||
for (index, _, _) in indicesAndItems.sorted(by: { $0.0 > $1.0 }) {
|
for (index, _, _) in indicesAndItems.sorted(by: { $0.0 > $1.0 }) {
|
||||||
let adjustedIndex = updatedCount - 1 - index
|
let adjustedIndex = updatedCount - 1 - index
|
||||||
if adjustedIndex == maxAnimatedInsertionIndex + 1 {
|
if adjustedIndex == maxAnimatedInsertionIndex + 1 {
|
||||||
maxAnimatedInsertionIndex += 1
|
maxAnimatedInsertionIndex += 1
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var minTimestamp: Int32?
|
var minTimestamp: Int32?
|
||||||
var maxTimestamp: Int32?
|
var maxTimestamp: Int32?
|
||||||
for (_, item, _) in indicesAndItems {
|
for (_, item, _) in indicesAndItems {
|
||||||
if case .PeerEntry = item, case let .index(index) = item.sortIndex, index.pinningIndex == nil {
|
if case .PeerEntry = item, case let .index(index) = item.sortIndex, case let .chatList(chatListIndex) = index, chatListIndex.pinningIndex == nil {
|
||||||
let timestamp = index.messageIndex.timestamp
|
let timestamp = chatListIndex.messageIndex.timestamp
|
||||||
|
|
||||||
if minTimestamp == nil || timestamp < minTimestamp! {
|
if minTimestamp == nil || timestamp < minTimestamp! {
|
||||||
minTimestamp = timestamp
|
minTimestamp = timestamp
|
||||||
}
|
}
|
||||||
if maxTimestamp == nil || timestamp > maxTimestamp! {
|
if maxTimestamp == nil || timestamp > maxTimestamp! {
|
||||||
maxTimestamp = timestamp
|
maxTimestamp = timestamp
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if false, let minTimestamp = minTimestamp, let maxTimestamp = maxTimestamp, abs(maxTimestamp - minTimestamp) > 60 * 60 {
|
let _ = options.insert(.AnimateAlpha)
|
||||||
let _ = options.insert(.AnimateCrossfade)
|
if !disableAnimations {
|
||||||
} else {
|
let _ = options.insert(.AnimateInsertion)
|
||||||
let _ = options.insert(.AnimateAlpha)
|
}
|
||||||
if !disableAnimations {
|
case .reload:
|
||||||
let _ = options.insert(.AnimateInsertion)
|
break
|
||||||
}
|
case .holeChanges:
|
||||||
}
|
break
|
||||||
case .reload:
|
|
||||||
break
|
|
||||||
case .holeChanges:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index, entry, previousIndex) in indicesAndItems {
|
for (index, entry, previousIndex) in indicesAndItems {
|
||||||
@ -142,31 +138,33 @@ func preparedChatListNodeViewTransition(from fromView: ChatListNodeView?, to toV
|
|||||||
|
|
||||||
if let scrollPosition = scrollPosition {
|
if let scrollPosition = scrollPosition {
|
||||||
switch scrollPosition {
|
switch scrollPosition {
|
||||||
case let .index(scrollIndex, position, directionHint, animated):
|
case let .index(scrollIndex, position, directionHint, animated):
|
||||||
var index = toView.filteredEntries.count - 1
|
var index = toView.filteredEntries.count - 1
|
||||||
for entry in toView.filteredEntries {
|
for entry in toView.filteredEntries {
|
||||||
if entry.sortIndex >= .index(scrollIndex) {
|
if entry.sortIndex >= .index(.chatList(scrollIndex)) {
|
||||||
|
scrollToItem = ListViewScrollToItem(index: index, position: position, animated: animated, curve: .Default(duration: nil), directionHint: directionHint)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
index -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if scrollToItem == nil {
|
||||||
|
var index = 0
|
||||||
|
for entry in toView.filteredEntries.reversed() {
|
||||||
|
if entry.sortIndex < .index(.chatList(scrollIndex)) {
|
||||||
scrollToItem = ListViewScrollToItem(index: index, position: position, animated: animated, curve: .Default(duration: nil), directionHint: directionHint)
|
scrollToItem = ListViewScrollToItem(index: index, position: position, animated: animated, curve: .Default(duration: nil), directionHint: directionHint)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
index -= 1
|
index += 1
|
||||||
}
|
|
||||||
|
|
||||||
if scrollToItem == nil {
|
|
||||||
var index = 0
|
|
||||||
for entry in toView.filteredEntries.reversed() {
|
|
||||||
if entry.sortIndex < .index(scrollIndex) {
|
|
||||||
scrollToItem = ListViewScrollToItem(index: index, position: position, animated: animated, curve: .Default(duration: nil), directionHint: directionHint)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
index += 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var fromEmptyView = false
|
var fromEmptyView: Bool
|
||||||
var animateCrossfade = false
|
fromEmptyView = false
|
||||||
|
var animateCrossfade: Bool
|
||||||
|
animateCrossfade = false
|
||||||
if let fromView = fromView {
|
if let fromView = fromView {
|
||||||
var wasSingleHeader = false
|
var wasSingleHeader = false
|
||||||
if fromView.filteredEntries.count == 1, case .HeaderEntry = fromView.filteredEntries[0] {
|
if fromView.filteredEntries.count == 1, case .HeaderEntry = fromView.filteredEntries[0] {
|
||||||
|
@ -57,12 +57,12 @@ public final class HashtagSearchController: TelegramBaseController {
|
|||||||
return result.messages.map({ .message(EngineMessage($0), EngineRenderedPeer(message: EngineMessage($0)), result.readStates[$0.id.peerId].flatMap(EnginePeerReadCounters.init), chatListPresentationData, result.totalCount, nil, false, .index($0.index), nil, .generic, false) })
|
return result.messages.map({ .message(EngineMessage($0), EngineRenderedPeer(message: EngineMessage($0)), result.readStates[$0.id.peerId].flatMap(EnginePeerReadCounters.init), chatListPresentationData, result.totalCount, nil, false, .index($0.index), nil, .generic, false) })
|
||||||
}
|
}
|
||||||
let interaction = ChatListNodeInteraction(context: context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, activateSearch: {
|
let interaction = ChatListNodeInteraction(context: context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, activateSearch: {
|
||||||
}, peerSelected: { _, _, _ in
|
}, peerSelected: { _, _, _, _ in
|
||||||
}, disabledPeerSelected: { _ in
|
}, disabledPeerSelected: { _ in
|
||||||
}, togglePeerSelected: { _ in
|
}, togglePeerSelected: { _ in
|
||||||
}, togglePeersSelection: { _, _ in
|
}, togglePeersSelection: { _, _ in
|
||||||
}, additionalCategorySelected: { _ in
|
}, additionalCategorySelected: { _ in
|
||||||
}, messageSelected: { [weak self] peer, message, _ in
|
}, messageSelected: { [weak self] peer, _, message, _ in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.openMessageFromSearchDisposable.set((strongSelf.context.engine.peers.ensurePeerIsLocallyAvailable(peer: peer) |> deliverOnMainQueue).start(next: { actualPeerId in
|
strongSelf.openMessageFromSearchDisposable.set((strongSelf.context.engine.peers.ensurePeerIsLocallyAvailable(peer: peer) |> deliverOnMainQueue).start(next: { actualPeerId in
|
||||||
if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController {
|
if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController {
|
||||||
|
@ -6,4 +6,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
void debug_linker_fail_test(void);
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
@ -473,6 +473,10 @@ public struct MessageFlags: OptionSet {
|
|||||||
rawValue |= MessageFlags.CopyProtected.rawValue
|
rawValue |= MessageFlags.CopyProtected.rawValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if flags.contains(StoreMessageFlags.IsForumTopic) {
|
||||||
|
rawValue |= MessageFlags.IsForumTopic.rawValue
|
||||||
|
}
|
||||||
|
|
||||||
self.rawValue = rawValue
|
self.rawValue = rawValue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,6 +489,7 @@ public struct MessageFlags: OptionSet {
|
|||||||
public static let WasScheduled = MessageFlags(rawValue: 128)
|
public static let WasScheduled = MessageFlags(rawValue: 128)
|
||||||
public static let CountedAsIncoming = MessageFlags(rawValue: 256)
|
public static let CountedAsIncoming = MessageFlags(rawValue: 256)
|
||||||
public static let CopyProtected = MessageFlags(rawValue: 512)
|
public static let CopyProtected = MessageFlags(rawValue: 512)
|
||||||
|
public static let IsForumTopic = MessageFlags(rawValue: 1024)
|
||||||
|
|
||||||
public static let IsIncomingMask = MessageFlags([.Incoming, .CountedAsIncoming])
|
public static let IsIncomingMask = MessageFlags([.Incoming, .CountedAsIncoming])
|
||||||
}
|
}
|
||||||
@ -745,6 +750,10 @@ public struct StoreMessageFlags: OptionSet {
|
|||||||
rawValue |= StoreMessageFlags.CopyProtected.rawValue
|
rawValue |= StoreMessageFlags.CopyProtected.rawValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if flags.contains(.IsForumTopic) {
|
||||||
|
rawValue |= StoreMessageFlags.IsForumTopic.rawValue
|
||||||
|
}
|
||||||
|
|
||||||
self.rawValue = rawValue
|
self.rawValue = rawValue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -757,6 +766,7 @@ public struct StoreMessageFlags: OptionSet {
|
|||||||
public static let WasScheduled = StoreMessageFlags(rawValue: 128)
|
public static let WasScheduled = StoreMessageFlags(rawValue: 128)
|
||||||
public static let CountedAsIncoming = StoreMessageFlags(rawValue: 256)
|
public static let CountedAsIncoming = StoreMessageFlags(rawValue: 256)
|
||||||
public static let CopyProtected = StoreMessageFlags(rawValue: 512)
|
public static let CopyProtected = StoreMessageFlags(rawValue: 512)
|
||||||
|
public static let IsForumTopic = StoreMessageFlags(rawValue: 1024)
|
||||||
|
|
||||||
public static let IsIncomingMask = StoreMessageFlags([.Incoming, .CountedAsIncoming])
|
public static let IsIncomingMask = StoreMessageFlags([.Incoming, .CountedAsIncoming])
|
||||||
}
|
}
|
||||||
|
131
submodules/Postbox/Sources/MessageHistoryThreadIndexView.swift
Normal file
131
submodules/Postbox/Sources/MessageHistoryThreadIndexView.swift
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
final class MutableMessageHistoryThreadIndexView: MutablePostboxView {
|
||||||
|
final class Item {
|
||||||
|
let id: Int64
|
||||||
|
let index: MessageIndex
|
||||||
|
var info: CodableEntry
|
||||||
|
var topMessage: Message?
|
||||||
|
|
||||||
|
init(
|
||||||
|
id: Int64,
|
||||||
|
index: MessageIndex,
|
||||||
|
info: CodableEntry,
|
||||||
|
topMessage: Message?
|
||||||
|
) {
|
||||||
|
self.id = id
|
||||||
|
self.index = index
|
||||||
|
self.info = info
|
||||||
|
self.topMessage = topMessage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate let peerId: PeerId
|
||||||
|
fileprivate var peer: Peer?
|
||||||
|
fileprivate var items: [Item] = []
|
||||||
|
|
||||||
|
init(postbox: PostboxImpl, peerId: PeerId) {
|
||||||
|
self.peerId = peerId
|
||||||
|
|
||||||
|
self.reload(postbox: postbox)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func reload(postbox: PostboxImpl) {
|
||||||
|
self.items.removeAll()
|
||||||
|
|
||||||
|
self.peer = postbox.peerTable.get(self.peerId)
|
||||||
|
|
||||||
|
for item in postbox.messageHistoryThreadIndexTable.getAll(peerId: self.peerId) {
|
||||||
|
self.items.append(Item(
|
||||||
|
id: item.threadId,
|
||||||
|
index: item.index,
|
||||||
|
info: item.info,
|
||||||
|
topMessage: postbox.getMessage(item.index.id)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func replay(postbox: PostboxImpl, transaction: PostboxTransaction) -> Bool {
|
||||||
|
var updated = false
|
||||||
|
|
||||||
|
if transaction.updatedMessageThreadPeerIds.contains(self.peerId) {
|
||||||
|
self.reload(postbox: postbox)
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return updated
|
||||||
|
}
|
||||||
|
|
||||||
|
func refreshDueToExternalTransaction(postbox: PostboxImpl) -> Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func immutableView() -> PostboxView {
|
||||||
|
return MessageHistoryThreadIndexView(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class EngineMessageHistoryThread {
|
||||||
|
public final class Item: Equatable {
|
||||||
|
public let id: Int64
|
||||||
|
public let index: MessageIndex
|
||||||
|
public let info: CodableEntry
|
||||||
|
public let topMessage: Message?
|
||||||
|
|
||||||
|
public init(
|
||||||
|
id: Int64,
|
||||||
|
index: MessageIndex,
|
||||||
|
info: CodableEntry,
|
||||||
|
topMessage: Message?
|
||||||
|
) {
|
||||||
|
self.id = id
|
||||||
|
self.index = index
|
||||||
|
self.info = info
|
||||||
|
self.topMessage = topMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: Item, rhs: Item) -> Bool {
|
||||||
|
if lhs.id != rhs.id {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.index != rhs.index {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.info != rhs.info {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if let lhsMessage = lhs.topMessage, let rhsMessage = rhs.topMessage {
|
||||||
|
if lhsMessage.index != rhsMessage.index {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhsMessage.stableVersion != rhsMessage.stableVersion {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else if (lhs.topMessage == nil) != (rhs.topMessage == nil) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class MessageHistoryThreadIndexView: PostboxView {
|
||||||
|
public let peer: Peer?
|
||||||
|
public let items: [EngineMessageHistoryThread.Item]
|
||||||
|
|
||||||
|
init(_ view: MutableMessageHistoryThreadIndexView) {
|
||||||
|
self.peer = view.peer
|
||||||
|
|
||||||
|
var items: [EngineMessageHistoryThread.Item] = []
|
||||||
|
for item in view.items {
|
||||||
|
items.append(EngineMessageHistoryThread.Item(
|
||||||
|
id: item.id,
|
||||||
|
index: item.index,
|
||||||
|
info: item.info,
|
||||||
|
topMessage: item.topMessage
|
||||||
|
))
|
||||||
|
}
|
||||||
|
self.items = items
|
||||||
|
}
|
||||||
|
}
|
@ -5,12 +5,19 @@ private func extractKey(_ key: ValueBoxKey) -> MessageIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MessageHistoryThreadsTable: Table {
|
class MessageHistoryThreadsTable: Table {
|
||||||
|
struct ItemId: Hashable {
|
||||||
|
var peerId: PeerId
|
||||||
|
var threadId: Int64
|
||||||
|
}
|
||||||
|
|
||||||
static func tableSpec(_ id: Int32) -> ValueBoxTable {
|
static func tableSpec(_ id: Int32) -> ValueBoxTable {
|
||||||
return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: true)
|
return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private let sharedKey = ValueBoxKey(length: 8 + 8 + 4 + 4 + 4)
|
private let sharedKey = ValueBoxKey(length: 8 + 8 + 4 + 4 + 4)
|
||||||
|
|
||||||
|
private(set) var updatedIds = Set<ItemId>()
|
||||||
|
|
||||||
override init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool) {
|
override init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool) {
|
||||||
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
|
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
|
||||||
}
|
}
|
||||||
@ -38,10 +45,12 @@ class MessageHistoryThreadsTable: Table {
|
|||||||
|
|
||||||
func add(threadId: Int64, index: MessageIndex) {
|
func add(threadId: Int64, index: MessageIndex) {
|
||||||
self.valueBox.set(self.table, key: self.key(threadId: threadId, index: index, key: self.sharedKey), value: MemoryBuffer())
|
self.valueBox.set(self.table, key: self.key(threadId: threadId, index: index, key: self.sharedKey), value: MemoryBuffer())
|
||||||
|
self.updatedIds.insert(ItemId(peerId: index.id.peerId, threadId: threadId))
|
||||||
}
|
}
|
||||||
|
|
||||||
func remove(threadId: Int64, index: MessageIndex) {
|
func remove(threadId: Int64, index: MessageIndex) {
|
||||||
self.valueBox.remove(self.table, key: self.key(threadId: threadId, index: index, key: self.sharedKey), secure: false)
|
self.valueBox.remove(self.table, key: self.key(threadId: threadId, index: index, key: self.sharedKey), secure: false)
|
||||||
|
self.updatedIds.insert(ItemId(peerId: index.id.peerId, threadId: threadId))
|
||||||
}
|
}
|
||||||
|
|
||||||
func earlierIndices(threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace, index: MessageIndex?, includeFrom: Bool, count: Int) -> [MessageIndex] {
|
func earlierIndices(threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace, index: MessageIndex?, includeFrom: Bool, count: Int) -> [MessageIndex] {
|
||||||
@ -82,6 +91,27 @@ class MessageHistoryThreadsTable: Table {
|
|||||||
return indices
|
return indices
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTop(peerId: PeerId, threadId: Int64, namespaces: Set<MessageId.Namespace>) -> MessageIndex? {
|
||||||
|
var maxIndex: MessageIndex?
|
||||||
|
for namespace in namespaces {
|
||||||
|
var namespaceIndex: MessageIndex?
|
||||||
|
self.valueBox.range(self.table, start: self.upperBound(threadId: threadId, peerId: peerId, namespace: namespace), end: self.lowerBound(threadId: threadId, peerId: peerId, namespace: namespace), keys: { key in
|
||||||
|
namespaceIndex = extractKey(key)
|
||||||
|
return false
|
||||||
|
}, limit: 1)
|
||||||
|
if let namespaceIndex = namespaceIndex {
|
||||||
|
if let maxIndexValue = maxIndex {
|
||||||
|
if namespaceIndex > maxIndexValue {
|
||||||
|
maxIndex = namespaceIndex
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
maxIndex = namespaceIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxIndex
|
||||||
|
}
|
||||||
|
|
||||||
func getMessageCountInRange(threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace, lowerBound: MessageIndex?, upperBound: MessageIndex?) -> Int {
|
func getMessageCountInRange(threadId: Int64, peerId: PeerId, namespace: MessageId.Namespace, lowerBound: MessageIndex?, upperBound: MessageIndex?) -> Int {
|
||||||
if let lowerBound = lowerBound {
|
if let lowerBound = lowerBound {
|
||||||
precondition(lowerBound.id.namespace == namespace)
|
precondition(lowerBound.id.namespace == namespace)
|
||||||
@ -109,4 +139,10 @@ class MessageHistoryThreadsTable: Table {
|
|||||||
}
|
}
|
||||||
return Int(self.valueBox.count(self.table, start: lowerBoundKey, end: upperBoundKey))
|
return Int(self.valueBox.count(self.table, start: lowerBoundKey, end: upperBoundKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func beforeCommit() {
|
||||||
|
super.beforeCommit()
|
||||||
|
|
||||||
|
self.updatedIds.removeAll()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
180
submodules/Postbox/Sources/MessageThreadIndexTable.swift
Normal file
180
submodules/Postbox/Sources/MessageThreadIndexTable.swift
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
private func extractKey(_ key: ValueBoxKey) -> MessageIndex {
|
||||||
|
return MessageIndex(id: MessageId(peerId: PeerId(key.getInt64(0)), namespace: key.getInt32(8 + 8), id: key.getInt32(8 + 8 + 4 + 4)), timestamp: key.getInt32(8 + 8 + 4))
|
||||||
|
}
|
||||||
|
|
||||||
|
class MessageHistoryThreadReverseIndexTable: Table {
|
||||||
|
static func tableSpec(_ id: Int32) -> ValueBoxTable {
|
||||||
|
return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private let sharedKey = ValueBoxKey(length: 8 + 8)
|
||||||
|
|
||||||
|
override init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool) {
|
||||||
|
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func key(peerId: PeerId, threadId: Int64, key: ValueBoxKey) -> ValueBoxKey {
|
||||||
|
key.setInt64(0, value: peerId.toInt64())
|
||||||
|
key.setInt64(8, value: threadId)
|
||||||
|
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
func get(peerId: PeerId, threadId: Int64) -> MessageIndex? {
|
||||||
|
if let value = self.valueBox.get(self.table, key: self.key(peerId: peerId, threadId: threadId, key: self.sharedKey)) {
|
||||||
|
var result: MessageIndex?
|
||||||
|
withExtendedLifetime(value, {
|
||||||
|
let readBuffer = ReadBuffer(memoryBufferNoCopy: value)
|
||||||
|
var namespace: Int32 = 0
|
||||||
|
readBuffer.read(&namespace, offset: 0, length: 4)
|
||||||
|
var id: Int32 = 0
|
||||||
|
readBuffer.read(&id, offset: 0, length: 4)
|
||||||
|
var timestamp: Int32 = 0
|
||||||
|
readBuffer.read(×tamp, offset: 0, length: 4)
|
||||||
|
result = MessageIndex(id: MessageId(peerId: peerId, namespace: namespace, id: id), timestamp: timestamp)
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func set(peerId: PeerId, threadId: Int64, timestamp: Int32, namespace: MessageId.Namespace, id: MessageId.Id, hasValue: Bool) {
|
||||||
|
if hasValue {
|
||||||
|
let buffer = WriteBuffer()
|
||||||
|
var namespace = namespace
|
||||||
|
buffer.write(&namespace, length: 4)
|
||||||
|
var id = id
|
||||||
|
buffer.write(&id, length: 4)
|
||||||
|
var timestamp = timestamp
|
||||||
|
buffer.write(×tamp, length: 4)
|
||||||
|
withExtendedLifetime(buffer, {
|
||||||
|
self.valueBox.set(self.table, key: self.key(peerId: peerId, threadId: threadId, key: self.sharedKey), value: buffer.readBufferNoCopy())
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
self.valueBox.remove(self.table, key: self.key(peerId: peerId, threadId: threadId, key: self.sharedKey), secure: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MessageHistoryThreadIndexTable: Table {
|
||||||
|
static func tableSpec(_ id: Int32) -> ValueBoxTable {
|
||||||
|
return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private let reverseIndexTable: MessageHistoryThreadReverseIndexTable
|
||||||
|
|
||||||
|
private let sharedKey = ValueBoxKey(length: 8 + 4 + 8 + 4 + 4)
|
||||||
|
|
||||||
|
private var updatedInfoItems: [MessageHistoryThreadsTable.ItemId: CodableEntry] = [:]
|
||||||
|
|
||||||
|
init(valueBox: ValueBox, table: ValueBoxTable, reverseIndexTable: MessageHistoryThreadReverseIndexTable, useCaches: Bool) {
|
||||||
|
self.reverseIndexTable = reverseIndexTable
|
||||||
|
|
||||||
|
super.init(valueBox: valueBox, table: table, useCaches: useCaches)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func key(peerId: PeerId, timestamp: Int32, threadId: Int64, namespace: MessageId.Namespace, id: MessageId.Id, key: ValueBoxKey) -> ValueBoxKey {
|
||||||
|
key.setInt64(0, value: peerId.toInt64())
|
||||||
|
key.setInt32(8, value: timestamp)
|
||||||
|
key.setInt64(8 + 4, value: threadId)
|
||||||
|
key.setInt32(8 + 4 + 8, value: namespace)
|
||||||
|
key.setInt32(8 + 4 + 8 + 4, value: id)
|
||||||
|
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func extract(key: ValueBoxKey) -> (threadId: Int64, index: MessageIndex) {
|
||||||
|
return (
|
||||||
|
threadId: key.getInt64(8 + 4),
|
||||||
|
index: MessageIndex(
|
||||||
|
id: MessageId(
|
||||||
|
peerId: PeerId(key.getInt64(0)),
|
||||||
|
namespace: key.getInt32(8 + 4 + 8),
|
||||||
|
id: key.getInt32(8 + 4 + 8 + 4)
|
||||||
|
),
|
||||||
|
timestamp: key.getInt32(8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func lowerBound(peerId: PeerId) -> ValueBoxKey {
|
||||||
|
let key = ValueBoxKey(length: 8)
|
||||||
|
key.setInt64(0, value: peerId.toInt64())
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
private func upperBound(peerId: PeerId) -> ValueBoxKey {
|
||||||
|
return self.lowerBound(peerId: peerId).successor
|
||||||
|
}
|
||||||
|
|
||||||
|
func set(peerId: PeerId, threadId: Int64, info: CodableEntry) {
|
||||||
|
self.updatedInfoItems[MessageHistoryThreadsTable.ItemId(peerId: peerId, threadId: threadId)] = info
|
||||||
|
}
|
||||||
|
|
||||||
|
func replay(threadsTable: MessageHistoryThreadsTable, namespaces: Set<MessageId.Namespace>, updatedIds: Set<MessageHistoryThreadsTable.ItemId>) -> Set<PeerId> {
|
||||||
|
var peerIds = Set<PeerId>()
|
||||||
|
for itemId in updatedIds.union(Set(self.updatedInfoItems.keys)) {
|
||||||
|
let topIndex = threadsTable.getTop(peerId: itemId.peerId, threadId: itemId.threadId, namespaces: namespaces)
|
||||||
|
let previousIndex = self.reverseIndexTable.get(peerId: itemId.peerId, threadId: itemId.threadId)
|
||||||
|
if topIndex != previousIndex || self.updatedInfoItems[itemId] != nil {
|
||||||
|
peerIds.insert(itemId.peerId)
|
||||||
|
|
||||||
|
var info: ReadBuffer?
|
||||||
|
if let previousIndex = previousIndex {
|
||||||
|
let previousKey = self.key(peerId: itemId.peerId, timestamp: previousIndex.timestamp, threadId: itemId.threadId, namespace: previousIndex.id.namespace, id: previousIndex.id.id, key: self.sharedKey)
|
||||||
|
if let previousValue = self.valueBox.get(self.table, key: previousKey) {
|
||||||
|
if previousValue.length != 0 {
|
||||||
|
info = previousValue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(false)
|
||||||
|
}
|
||||||
|
self.valueBox.remove(self.table, key: previousKey, secure: true)
|
||||||
|
}
|
||||||
|
if let updatedInfo = self.updatedInfoItems[itemId] {
|
||||||
|
info = ReadBuffer(data: updatedInfo.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let topIndex = topIndex, let info = info {
|
||||||
|
if let previousIndex = previousIndex {
|
||||||
|
self.reverseIndexTable.set(peerId: itemId.peerId, threadId: itemId.threadId, timestamp: previousIndex.timestamp, namespace: previousIndex.id.namespace, id: previousIndex.id.id, hasValue: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.reverseIndexTable.set(peerId: itemId.peerId, threadId: itemId.threadId, timestamp: topIndex.timestamp, namespace: topIndex.id.namespace, id: topIndex.id.id, hasValue: true)
|
||||||
|
self.valueBox.set(self.table, key: self.key(peerId: itemId.peerId, timestamp: topIndex.timestamp, threadId: itemId.threadId, namespace: topIndex.id.namespace, id: topIndex.id.id, key: self.sharedKey), value: info)
|
||||||
|
} else {
|
||||||
|
if let previousIndex = previousIndex {
|
||||||
|
self.reverseIndexTable.set(peerId: itemId.peerId, threadId: itemId.threadId, timestamp: previousIndex.timestamp, namespace: previousIndex.id.namespace, id: previousIndex.id.id, hasValue: false)
|
||||||
|
self.valueBox.remove(self.table, key: self.key(peerId: itemId.peerId, timestamp: previousIndex.timestamp, threadId: itemId.threadId, namespace: previousIndex.id.namespace, id: previousIndex.id.id, key: self.sharedKey), secure: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return peerIds
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAll(peerId: PeerId) -> [(threadId: Int64, index: MessageIndex, info: CodableEntry)] {
|
||||||
|
var result: [(threadId: Int64, index: MessageIndex, info: CodableEntry)] = []
|
||||||
|
self.valueBox.range(self.table, start: self.upperBound(peerId: peerId), end: self.lowerBound(peerId: peerId), values: { key, value in
|
||||||
|
let keyData = MessageHistoryThreadIndexTable.extract(key: key)
|
||||||
|
if value.length == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
let info = CodableEntry(data: value.makeData())
|
||||||
|
result.append((keyData.threadId, keyData.index, info))
|
||||||
|
return true
|
||||||
|
}, limit: 100000)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override func beforeCommit() {
|
||||||
|
super.beforeCommit()
|
||||||
|
|
||||||
|
self.updatedInfoItems.removeAll()
|
||||||
|
}
|
||||||
|
}
|
@ -1158,6 +1158,16 @@ public final class Transaction {
|
|||||||
assert(!self.disposed)
|
assert(!self.disposed)
|
||||||
self.postbox?.removePeerTimeoutAttributeEntry(peerId: peerId, timestamp: timestamp)
|
self.postbox?.removePeerTimeoutAttributeEntry(peerId: peerId, timestamp: timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func getMessageHistoryThreadIndex(peerId: PeerId) -> [(threadId: Int64, index: MessageIndex, info: CodableEntry)] {
|
||||||
|
assert(!self.disposed)
|
||||||
|
return self.postbox!.messageHistoryThreadIndexTable.getAll(peerId: peerId)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func setMessageHistoryThreadInfo(peerId: PeerId, threadId: Int64, info: CodableEntry) {
|
||||||
|
assert(!self.disposed)
|
||||||
|
self.postbox!.messageHistoryThreadIndexTable.set(peerId: peerId, threadId: threadId, info: info)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PostboxResult {
|
public enum PostboxResult {
|
||||||
@ -1433,6 +1443,8 @@ final class PostboxImpl {
|
|||||||
let messageHistoryTagsTable: MessageHistoryTagsTable
|
let messageHistoryTagsTable: MessageHistoryTagsTable
|
||||||
let messageHistoryThreadsTable: MessageHistoryThreadsTable
|
let messageHistoryThreadsTable: MessageHistoryThreadsTable
|
||||||
let messageHistoryThreadHoleIndexTable: MessageHistoryThreadHoleIndexTable
|
let messageHistoryThreadHoleIndexTable: MessageHistoryThreadHoleIndexTable
|
||||||
|
let messageHistoryThreadReverseIndexTable: MessageHistoryThreadReverseIndexTable
|
||||||
|
let messageHistoryThreadIndexTable: MessageHistoryThreadIndexTable
|
||||||
let globalMessageHistoryTagsTable: GlobalMessageHistoryTagsTable
|
let globalMessageHistoryTagsTable: GlobalMessageHistoryTagsTable
|
||||||
let localMessageHistoryTagsTable: LocalMessageHistoryTagsTable
|
let localMessageHistoryTagsTable: LocalMessageHistoryTagsTable
|
||||||
let peerChatStateTable: PeerChatStateTable
|
let peerChatStateTable: PeerChatStateTable
|
||||||
@ -1508,6 +1520,8 @@ final class PostboxImpl {
|
|||||||
self.messageHistoryTagsTable = MessageHistoryTagsTable(valueBox: self.valueBox, table: MessageHistoryTagsTable.tableSpec(12), useCaches: useCaches, seedConfiguration: self.seedConfiguration, summaryTable: self.messageHistoryTagsSummaryTable)
|
self.messageHistoryTagsTable = MessageHistoryTagsTable(valueBox: self.valueBox, table: MessageHistoryTagsTable.tableSpec(12), useCaches: useCaches, seedConfiguration: self.seedConfiguration, summaryTable: self.messageHistoryTagsSummaryTable)
|
||||||
self.messageHistoryThreadsTable = MessageHistoryThreadsTable(valueBox: self.valueBox, table: MessageHistoryThreadsTable.tableSpec(62), useCaches: useCaches)
|
self.messageHistoryThreadsTable = MessageHistoryThreadsTable(valueBox: self.valueBox, table: MessageHistoryThreadsTable.tableSpec(62), useCaches: useCaches)
|
||||||
self.messageHistoryThreadHoleIndexTable = MessageHistoryThreadHoleIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadHoleIndexTable.tableSpec(63), useCaches: useCaches, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
|
self.messageHistoryThreadHoleIndexTable = MessageHistoryThreadHoleIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadHoleIndexTable.tableSpec(63), useCaches: useCaches, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
|
||||||
|
self.messageHistoryThreadReverseIndexTable = MessageHistoryThreadReverseIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadReverseIndexTable.tableSpec(69), useCaches: useCaches)
|
||||||
|
self.messageHistoryThreadIndexTable = MessageHistoryThreadIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadIndexTable.tableSpec(70), reverseIndexTable: self.messageHistoryThreadReverseIndexTable, useCaches: useCaches)
|
||||||
self.globalMessageHistoryTagsTable = GlobalMessageHistoryTagsTable(valueBox: self.valueBox, table: GlobalMessageHistoryTagsTable.tableSpec(39), useCaches: useCaches)
|
self.globalMessageHistoryTagsTable = GlobalMessageHistoryTagsTable(valueBox: self.valueBox, table: GlobalMessageHistoryTagsTable.tableSpec(39), useCaches: useCaches)
|
||||||
self.localMessageHistoryTagsTable = LocalMessageHistoryTagsTable(valueBox: self.valueBox, table: GlobalMessageHistoryTagsTable.tableSpec(52), useCaches: useCaches)
|
self.localMessageHistoryTagsTable = LocalMessageHistoryTagsTable(valueBox: self.valueBox, table: GlobalMessageHistoryTagsTable.tableSpec(52), useCaches: useCaches)
|
||||||
self.messageHistoryIndexTable = MessageHistoryIndexTable(valueBox: self.valueBox, table: MessageHistoryIndexTable.tableSpec(4), useCaches: useCaches, messageHistoryHoleIndexTable: self.messageHistoryHoleIndexTable, globalMessageIdsTable: self.globalMessageIdsTable, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
|
self.messageHistoryIndexTable = MessageHistoryIndexTable(valueBox: self.valueBox, table: MessageHistoryIndexTable.tableSpec(4), useCaches: useCaches, messageHistoryHoleIndexTable: self.messageHistoryHoleIndexTable, globalMessageIdsTable: self.globalMessageIdsTable, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration)
|
||||||
@ -1564,6 +1578,8 @@ final class PostboxImpl {
|
|||||||
tables.append(self.messageHistoryTagsTable)
|
tables.append(self.messageHistoryTagsTable)
|
||||||
tables.append(self.messageHistoryThreadsTable)
|
tables.append(self.messageHistoryThreadsTable)
|
||||||
tables.append(self.messageHistoryThreadHoleIndexTable)
|
tables.append(self.messageHistoryThreadHoleIndexTable)
|
||||||
|
tables.append(self.messageHistoryThreadReverseIndexTable)
|
||||||
|
tables.append(self.messageHistoryThreadIndexTable)
|
||||||
tables.append(self.globalMessageHistoryTagsTable)
|
tables.append(self.globalMessageHistoryTagsTable)
|
||||||
tables.append(self.localMessageHistoryTagsTable)
|
tables.append(self.localMessageHistoryTagsTable)
|
||||||
tables.append(self.messageHistoryIndexTable)
|
tables.append(self.messageHistoryIndexTable)
|
||||||
@ -2002,13 +2018,15 @@ final class PostboxImpl {
|
|||||||
|
|
||||||
self.peerTable.commitDependentTables()
|
self.peerTable.commitDependentTables()
|
||||||
|
|
||||||
|
let updatedMessageThreadPeerIds = self.messageHistoryThreadIndexTable.replay(threadsTable: self.messageHistoryThreadsTable, namespaces: self.seedConfiguration.chatMessagesNamespaces, updatedIds: self.messageHistoryThreadsTable.updatedIds)
|
||||||
|
|
||||||
if self.currentNeedsReindexUnreadCounters {
|
if self.currentNeedsReindexUnreadCounters {
|
||||||
self.reindexUnreadCounters(currentTransaction: currentTransaction)
|
self.reindexUnreadCounters(currentTransaction: currentTransaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
let updatedPeerTimeoutAttributes = self.peerTimeoutPropertiesTable.hasUpdates
|
let updatedPeerTimeoutAttributes = self.peerTimeoutPropertiesTable.hasUpdates
|
||||||
|
|
||||||
let transaction = PostboxTransaction(currentUpdatedState: self.currentUpdatedState, currentPeerHoleOperations: self.currentPeerHoleOperations, currentOperationsByPeerId: self.currentOperationsByPeerId, chatListOperations: self.currentChatListOperations, currentUpdatedChatListInclusions: self.currentUpdatedChatListInclusions, currentUpdatedPeers: self.currentUpdatedPeers, currentUpdatedPeerNotificationSettings: self.currentUpdatedPeerNotificationSettings, currentUpdatedPeerNotificationBehaviorTimestamps: self.currentUpdatedPeerNotificationBehaviorTimestamps, currentUpdatedCachedPeerData: self.currentUpdatedCachedPeerData, currentUpdatedPeerPresences: currentUpdatedPeerPresences, currentUpdatedPeerChatListEmbeddedStates: self.currentUpdatedPeerChatListEmbeddedStates, currentUpdatedTotalUnreadStates: self.currentUpdatedTotalUnreadStates, currentUpdatedTotalUnreadSummaries: self.currentUpdatedGroupTotalUnreadSummaries, alteredInitialPeerCombinedReadStates: alteredInitialPeerCombinedReadStates, currentPeerMergedOperationLogOperations: self.currentPeerMergedOperationLogOperations, currentTimestampBasedMessageAttributesOperations: self.currentTimestampBasedMessageAttributesOperations, unsentMessageOperations: self.currentUnsentOperations, updatedSynchronizePeerReadStateOperations: self.currentUpdatedSynchronizeReadStateOperations, currentUpdatedGroupSummarySynchronizeOperations: self.currentUpdatedGroupSummarySynchronizeOperations, currentPreferencesOperations: self.currentPreferencesOperations, currentOrderedItemListOperations: self.currentOrderedItemListOperations, currentItemCollectionItemsOperations: self.currentItemCollectionItemsOperations, currentItemCollectionInfosOperations: self.currentItemCollectionInfosOperations, currentUpdatedPeerChatStates: self.currentUpdatedPeerChatStates, currentGlobalTagsOperations: self.currentGlobalTagsOperations, currentLocalTagsOperations: self.currentLocalTagsOperations, updatedMedia: self.currentUpdatedMedia, replaceRemoteContactCount: self.currentReplaceRemoteContactCount, replaceContactPeerIds: self.currentReplacedContactPeerIds, currentPendingMessageActionsOperations: self.currentPendingMessageActionsOperations, currentUpdatedMessageActionsSummaries: self.currentUpdatedMessageActionsSummaries, currentUpdatedMessageTagSummaries: self.currentUpdatedMessageTagSummaries, currentInvalidateMessageTagSummaries: self.currentInvalidateMessageTagSummaries, currentUpdatedPendingPeerNotificationSettings: self.currentUpdatedPendingPeerNotificationSettings, replacedAdditionalChatListItems: self.currentReplacedAdditionalChatListItems, updatedNoticeEntryKeys: self.currentUpdatedNoticeEntryKeys, updatedCacheEntryKeys: self.currentUpdatedCacheEntryKeys, currentUpdatedMasterClientId: currentUpdatedMasterClientId, updatedFailedMessagePeerIds: self.messageHistoryFailedTable.updatedPeerIds, updatedFailedMessageIds: self.messageHistoryFailedTable.updatedMessageIds, updatedGlobalNotificationSettings: self.currentNeedsReindexUnreadCounters, updatedPeerTimeoutAttributes: updatedPeerTimeoutAttributes)
|
let transaction = PostboxTransaction(currentUpdatedState: self.currentUpdatedState, currentPeerHoleOperations: self.currentPeerHoleOperations, currentOperationsByPeerId: self.currentOperationsByPeerId, chatListOperations: self.currentChatListOperations, currentUpdatedChatListInclusions: self.currentUpdatedChatListInclusions, currentUpdatedPeers: self.currentUpdatedPeers, currentUpdatedPeerNotificationSettings: self.currentUpdatedPeerNotificationSettings, currentUpdatedPeerNotificationBehaviorTimestamps: self.currentUpdatedPeerNotificationBehaviorTimestamps, currentUpdatedCachedPeerData: self.currentUpdatedCachedPeerData, currentUpdatedPeerPresences: currentUpdatedPeerPresences, currentUpdatedPeerChatListEmbeddedStates: self.currentUpdatedPeerChatListEmbeddedStates, currentUpdatedTotalUnreadStates: self.currentUpdatedTotalUnreadStates, currentUpdatedTotalUnreadSummaries: self.currentUpdatedGroupTotalUnreadSummaries, alteredInitialPeerCombinedReadStates: alteredInitialPeerCombinedReadStates, currentPeerMergedOperationLogOperations: self.currentPeerMergedOperationLogOperations, currentTimestampBasedMessageAttributesOperations: self.currentTimestampBasedMessageAttributesOperations, unsentMessageOperations: self.currentUnsentOperations, updatedSynchronizePeerReadStateOperations: self.currentUpdatedSynchronizeReadStateOperations, currentUpdatedGroupSummarySynchronizeOperations: self.currentUpdatedGroupSummarySynchronizeOperations, currentPreferencesOperations: self.currentPreferencesOperations, currentOrderedItemListOperations: self.currentOrderedItemListOperations, currentItemCollectionItemsOperations: self.currentItemCollectionItemsOperations, currentItemCollectionInfosOperations: self.currentItemCollectionInfosOperations, currentUpdatedPeerChatStates: self.currentUpdatedPeerChatStates, currentGlobalTagsOperations: self.currentGlobalTagsOperations, currentLocalTagsOperations: self.currentLocalTagsOperations, updatedMedia: self.currentUpdatedMedia, replaceRemoteContactCount: self.currentReplaceRemoteContactCount, replaceContactPeerIds: self.currentReplacedContactPeerIds, currentPendingMessageActionsOperations: self.currentPendingMessageActionsOperations, currentUpdatedMessageActionsSummaries: self.currentUpdatedMessageActionsSummaries, currentUpdatedMessageTagSummaries: self.currentUpdatedMessageTagSummaries, currentInvalidateMessageTagSummaries: self.currentInvalidateMessageTagSummaries, currentUpdatedPendingPeerNotificationSettings: self.currentUpdatedPendingPeerNotificationSettings, replacedAdditionalChatListItems: self.currentReplacedAdditionalChatListItems, updatedNoticeEntryKeys: self.currentUpdatedNoticeEntryKeys, updatedCacheEntryKeys: self.currentUpdatedCacheEntryKeys, currentUpdatedMasterClientId: currentUpdatedMasterClientId, updatedFailedMessagePeerIds: self.messageHistoryFailedTable.updatedPeerIds, updatedFailedMessageIds: self.messageHistoryFailedTable.updatedMessageIds, updatedGlobalNotificationSettings: self.currentNeedsReindexUnreadCounters, updatedPeerTimeoutAttributes: updatedPeerTimeoutAttributes, updatedMessageThreadPeerIds: updatedMessageThreadPeerIds)
|
||||||
var updatedTransactionState: Int64?
|
var updatedTransactionState: Int64?
|
||||||
var updatedMasterClientId: Int64?
|
var updatedMasterClientId: Int64?
|
||||||
if !transaction.isEmpty {
|
if !transaction.isEmpty {
|
||||||
|
@ -44,6 +44,7 @@ final class PostboxTransaction {
|
|||||||
let updatedFailedMessageIds: Set<MessageId>
|
let updatedFailedMessageIds: Set<MessageId>
|
||||||
let updatedGlobalNotificationSettings: Bool
|
let updatedGlobalNotificationSettings: Bool
|
||||||
let updatedPeerTimeoutAttributes: Bool
|
let updatedPeerTimeoutAttributes: Bool
|
||||||
|
let updatedMessageThreadPeerIds: Set<PeerId>
|
||||||
|
|
||||||
var isEmpty: Bool {
|
var isEmpty: Bool {
|
||||||
if currentUpdatedState != nil {
|
if currentUpdatedState != nil {
|
||||||
@ -175,10 +176,13 @@ final class PostboxTransaction {
|
|||||||
if self.updatedPeerTimeoutAttributes {
|
if self.updatedPeerTimeoutAttributes {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if !self.updatedMessageThreadPeerIds.isEmpty {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
init(currentUpdatedState: PostboxCoding?, currentPeerHoleOperations: [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]] = [:], currentOperationsByPeerId: [PeerId: [MessageHistoryOperation]], chatListOperations: [PeerGroupId: [ChatListOperation]], currentUpdatedChatListInclusions: [PeerId: PeerChatListInclusion], currentUpdatedPeers: [PeerId: Peer], currentUpdatedPeerNotificationSettings: [PeerId: (PeerNotificationSettings?, PeerNotificationSettings)], currentUpdatedPeerNotificationBehaviorTimestamps: [PeerId: PeerNotificationSettingsBehaviorTimestamp], currentUpdatedCachedPeerData: [PeerId: CachedPeerData], currentUpdatedPeerPresences: [PeerId: PeerPresence], currentUpdatedPeerChatListEmbeddedStates: Set<PeerId>, currentUpdatedTotalUnreadStates: [PeerGroupId: ChatListTotalUnreadState], currentUpdatedTotalUnreadSummaries: [PeerGroupId: PeerGroupUnreadCountersCombinedSummary], alteredInitialPeerCombinedReadStates: [PeerId: CombinedPeerReadState], currentPeerMergedOperationLogOperations: [PeerMergedOperationLogOperation], currentTimestampBasedMessageAttributesOperations: [TimestampBasedMessageAttributesOperation], unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation], updatedSynchronizePeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?], currentUpdatedGroupSummarySynchronizeOperations: [PeerGroupAndNamespace: Bool], currentPreferencesOperations: [PreferencesOperation], currentOrderedItemListOperations: [Int32: [OrderedItemListOperation]], currentItemCollectionItemsOperations: [ItemCollectionId: [ItemCollectionItemsOperation]], currentItemCollectionInfosOperations: [ItemCollectionInfosOperation], currentUpdatedPeerChatStates: Set<PeerId>, currentGlobalTagsOperations: [GlobalMessageHistoryTagsOperation], currentLocalTagsOperations: [IntermediateMessageHistoryLocalTagsOperation], updatedMedia: [MediaId: Media?], replaceRemoteContactCount: Int32?, replaceContactPeerIds: Set<PeerId>?, currentPendingMessageActionsOperations: [PendingMessageActionsOperation], currentUpdatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32], currentUpdatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], currentInvalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation], currentUpdatedPendingPeerNotificationSettings: Set<PeerId>, replacedAdditionalChatListItems: [AdditionalChatListItem]?, updatedNoticeEntryKeys: Set<NoticeEntryKey>, updatedCacheEntryKeys: Set<ItemCacheEntryId>, currentUpdatedMasterClientId: Int64?, updatedFailedMessagePeerIds: Set<PeerId>, updatedFailedMessageIds: Set<MessageId>, updatedGlobalNotificationSettings: Bool, updatedPeerTimeoutAttributes: Bool) {
|
init(currentUpdatedState: PostboxCoding?, currentPeerHoleOperations: [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]] = [:], currentOperationsByPeerId: [PeerId: [MessageHistoryOperation]], chatListOperations: [PeerGroupId: [ChatListOperation]], currentUpdatedChatListInclusions: [PeerId: PeerChatListInclusion], currentUpdatedPeers: [PeerId: Peer], currentUpdatedPeerNotificationSettings: [PeerId: (PeerNotificationSettings?, PeerNotificationSettings)], currentUpdatedPeerNotificationBehaviorTimestamps: [PeerId: PeerNotificationSettingsBehaviorTimestamp], currentUpdatedCachedPeerData: [PeerId: CachedPeerData], currentUpdatedPeerPresences: [PeerId: PeerPresence], currentUpdatedPeerChatListEmbeddedStates: Set<PeerId>, currentUpdatedTotalUnreadStates: [PeerGroupId: ChatListTotalUnreadState], currentUpdatedTotalUnreadSummaries: [PeerGroupId: PeerGroupUnreadCountersCombinedSummary], alteredInitialPeerCombinedReadStates: [PeerId: CombinedPeerReadState], currentPeerMergedOperationLogOperations: [PeerMergedOperationLogOperation], currentTimestampBasedMessageAttributesOperations: [TimestampBasedMessageAttributesOperation], unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation], updatedSynchronizePeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?], currentUpdatedGroupSummarySynchronizeOperations: [PeerGroupAndNamespace: Bool], currentPreferencesOperations: [PreferencesOperation], currentOrderedItemListOperations: [Int32: [OrderedItemListOperation]], currentItemCollectionItemsOperations: [ItemCollectionId: [ItemCollectionItemsOperation]], currentItemCollectionInfosOperations: [ItemCollectionInfosOperation], currentUpdatedPeerChatStates: Set<PeerId>, currentGlobalTagsOperations: [GlobalMessageHistoryTagsOperation], currentLocalTagsOperations: [IntermediateMessageHistoryLocalTagsOperation], updatedMedia: [MediaId: Media?], replaceRemoteContactCount: Int32?, replaceContactPeerIds: Set<PeerId>?, currentPendingMessageActionsOperations: [PendingMessageActionsOperation], currentUpdatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32], currentUpdatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], currentInvalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation], currentUpdatedPendingPeerNotificationSettings: Set<PeerId>, replacedAdditionalChatListItems: [AdditionalChatListItem]?, updatedNoticeEntryKeys: Set<NoticeEntryKey>, updatedCacheEntryKeys: Set<ItemCacheEntryId>, currentUpdatedMasterClientId: Int64?, updatedFailedMessagePeerIds: Set<PeerId>, updatedFailedMessageIds: Set<MessageId>, updatedGlobalNotificationSettings: Bool, updatedPeerTimeoutAttributes: Bool, updatedMessageThreadPeerIds: Set<PeerId>) {
|
||||||
self.currentUpdatedState = currentUpdatedState
|
self.currentUpdatedState = currentUpdatedState
|
||||||
self.currentPeerHoleOperations = currentPeerHoleOperations
|
self.currentPeerHoleOperations = currentPeerHoleOperations
|
||||||
self.currentOperationsByPeerId = currentOperationsByPeerId
|
self.currentOperationsByPeerId = currentOperationsByPeerId
|
||||||
@ -221,5 +225,6 @@ final class PostboxTransaction {
|
|||||||
self.updatedFailedMessageIds = updatedFailedMessageIds
|
self.updatedFailedMessageIds = updatedFailedMessageIds
|
||||||
self.updatedGlobalNotificationSettings = updatedGlobalNotificationSettings
|
self.updatedGlobalNotificationSettings = updatedGlobalNotificationSettings
|
||||||
self.updatedPeerTimeoutAttributes = updatedPeerTimeoutAttributes
|
self.updatedPeerTimeoutAttributes = updatedPeerTimeoutAttributes
|
||||||
|
self.updatedMessageThreadPeerIds = updatedMessageThreadPeerIds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ public enum PostboxViewKey: Hashable {
|
|||||||
case isContact(id: PeerId)
|
case isContact(id: PeerId)
|
||||||
case chatListIndex(id: PeerId)
|
case chatListIndex(id: PeerId)
|
||||||
case peerTimeoutAttributes
|
case peerTimeoutAttributes
|
||||||
|
case messageHistoryThreadIndex(id: PeerId)
|
||||||
|
|
||||||
public func hash(into hasher: inout Hasher) {
|
public func hash(into hasher: inout Hasher) {
|
||||||
switch self {
|
switch self {
|
||||||
@ -124,6 +125,8 @@ public enum PostboxViewKey: Hashable {
|
|||||||
hasher.combine(id)
|
hasher.combine(id)
|
||||||
case .peerTimeoutAttributes:
|
case .peerTimeoutAttributes:
|
||||||
hasher.combine(17)
|
hasher.combine(17)
|
||||||
|
case let .messageHistoryThreadIndex(id):
|
||||||
|
hasher.combine(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,6 +354,12 @@ public enum PostboxViewKey: Hashable {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
case let .messageHistoryThreadIndex(id):
|
||||||
|
if case .messageHistoryThreadIndex(id) = rhs {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -431,5 +440,7 @@ func postboxViewForKey(postbox: PostboxImpl, key: PostboxViewKey) -> MutablePost
|
|||||||
return MutableChatListIndexView(postbox: postbox, id: id)
|
return MutableChatListIndexView(postbox: postbox, id: id)
|
||||||
case .peerTimeoutAttributes:
|
case .peerTimeoutAttributes:
|
||||||
return MutablePeerTimeoutAttributesView(postbox: postbox)
|
return MutablePeerTimeoutAttributesView(postbox: postbox)
|
||||||
|
case let .messageHistoryThreadIndex(id):
|
||||||
|
return MutableMessageHistoryThreadIndexView(postbox: postbox, peerId: id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,8 +218,8 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
|||||||
private func updateChatsLayout(layout: ContainerViewLayout, topInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
private func updateChatsLayout(layout: ContainerViewLayout, topInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
var items: [ChatListItem] = []
|
var items: [ChatListItem] = []
|
||||||
|
|
||||||
let interaction = ChatListNodeInteraction(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, activateSearch: {}, peerSelected: { _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
let interaction = ChatListNodeInteraction(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, 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
|
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
|
||||||
}, activateChatPreview: { _, _, gesture, _ in
|
}, activateChatPreview: { _, _, gesture, _ in
|
||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
}, present: { _ in })
|
}, present: { _ in })
|
||||||
@ -239,9 +239,9 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
|||||||
return ChatListItem(
|
return ChatListItem(
|
||||||
presentationData: chatListPresentationData,
|
presentationData: chatListPresentationData,
|
||||||
context: self.context,
|
context: self.context,
|
||||||
peerGroupId: .root,
|
chatListLocation: .chatList(groupId: .root),
|
||||||
filterData: nil,
|
filterData: nil,
|
||||||
index: ChatListIndex(pinningIndex: isPinned ? 0 : nil, messageIndex: MessageIndex(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), timestamp: timestamp)),
|
index: .chatList(ChatListIndex(pinningIndex: isPinned ? 0 : nil, messageIndex: MessageIndex(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), timestamp: timestamp))),
|
||||||
content: .peer(
|
content: .peer(
|
||||||
messages: [
|
messages: [
|
||||||
EngineMessage(
|
EngineMessage(
|
||||||
@ -269,6 +269,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
peer: EngineRenderedPeer(peer: peer),
|
peer: EngineRenderedPeer(peer: peer),
|
||||||
|
threadInfo: nil,
|
||||||
combinedReadState: EnginePeerReadCounters(incomingReadId: 1000, outgoingReadId: 1000, count: unreadCount, markedUnread: false),
|
combinedReadState: EnginePeerReadCounters(incomingReadId: 1000, outgoingReadId: 1000, count: unreadCount, markedUnread: false),
|
||||||
isRemovedFromTotalUnreadCount: false,
|
isRemovedFromTotalUnreadCount: false,
|
||||||
presence: presenceTimestamp.flatMap { presenceTimestamp in
|
presence: presenceTimestamp.flatMap { presenceTimestamp in
|
||||||
|
@ -838,8 +838,8 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
|||||||
private func updateChatsLayout(layout: ContainerViewLayout, topInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
private func updateChatsLayout(layout: ContainerViewLayout, topInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
var items: [ChatListItem] = []
|
var items: [ChatListItem] = []
|
||||||
|
|
||||||
let interaction = ChatListNodeInteraction(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, activateSearch: {}, peerSelected: { _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
let interaction = ChatListNodeInteraction(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, 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
|
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
|
||||||
}, activateChatPreview: { _, _, gesture, _ in
|
}, activateChatPreview: { _, _, gesture, _ in
|
||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
}, present: { _ in
|
}, present: { _ in
|
||||||
@ -859,9 +859,9 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
|||||||
return ChatListItem(
|
return ChatListItem(
|
||||||
presentationData: chatListPresentationData,
|
presentationData: chatListPresentationData,
|
||||||
context: self.context,
|
context: self.context,
|
||||||
peerGroupId: .root,
|
chatListLocation: .chatList(groupId: .root),
|
||||||
filterData: nil,
|
filterData: nil,
|
||||||
index: ChatListIndex(pinningIndex: isPinned ? 0 : nil, messageIndex: MessageIndex(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), timestamp: timestamp)),
|
index: .chatList(ChatListIndex(pinningIndex: isPinned ? 0 : nil, messageIndex: MessageIndex(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), timestamp: timestamp))),
|
||||||
content: .peer(
|
content: .peer(
|
||||||
messages: [
|
messages: [
|
||||||
EngineMessage(
|
EngineMessage(
|
||||||
@ -889,6 +889,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
peer: EngineRenderedPeer(peer: peer),
|
peer: EngineRenderedPeer(peer: peer),
|
||||||
|
threadInfo: nil,
|
||||||
combinedReadState: EnginePeerReadCounters(incomingReadId: 1000, outgoingReadId: 1000, count: unreadCount, markedUnread: false),
|
combinedReadState: EnginePeerReadCounters(incomingReadId: 1000, outgoingReadId: 1000, count: unreadCount, markedUnread: false),
|
||||||
isRemovedFromTotalUnreadCount: false,
|
isRemovedFromTotalUnreadCount: false,
|
||||||
presence: presenceTimestamp.flatMap { presenceTimestamp in
|
presence: presenceTimestamp.flatMap { presenceTimestamp in
|
||||||
|
@ -362,8 +362,8 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
private func updateChatsLayout(layout: ContainerViewLayout, topInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
private func updateChatsLayout(layout: ContainerViewLayout, topInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
var items: [ChatListItem] = []
|
var items: [ChatListItem] = []
|
||||||
|
|
||||||
let interaction = ChatListNodeInteraction(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, activateSearch: {}, peerSelected: { _, _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in
|
let interaction = ChatListNodeInteraction(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, 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
|
}, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
|
||||||
}, activateChatPreview: { _, _, gesture, _ in
|
}, activateChatPreview: { _, _, gesture, _ in
|
||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
}, present: { _ in
|
}, present: { _ in
|
||||||
@ -382,9 +382,9 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
return ChatListItem(
|
return ChatListItem(
|
||||||
presentationData: chatListPresentationData,
|
presentationData: chatListPresentationData,
|
||||||
context: self.context,
|
context: self.context,
|
||||||
peerGroupId: .root,
|
chatListLocation: .chatList(groupId: .root),
|
||||||
filterData: nil,
|
filterData: nil,
|
||||||
index: ChatListIndex(pinningIndex: isPinned ? 0 : nil, messageIndex: MessageIndex(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), timestamp: timestamp)),
|
index: .chatList(ChatListIndex(pinningIndex: isPinned ? 0 : nil, messageIndex: MessageIndex(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), timestamp: timestamp))),
|
||||||
content: .peer(
|
content: .peer(
|
||||||
messages: [
|
messages: [
|
||||||
EngineMessage(
|
EngineMessage(
|
||||||
@ -412,6 +412,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
peer: EngineRenderedPeer(peer: peer),
|
peer: EngineRenderedPeer(peer: peer),
|
||||||
|
threadInfo: nil,
|
||||||
combinedReadState: EnginePeerReadCounters(incomingReadId: 1000, outgoingReadId: 1000, count: unreadCount, markedUnread: false),
|
combinedReadState: EnginePeerReadCounters(incomingReadId: 1000, outgoingReadId: 1000, count: unreadCount, markedUnread: false),
|
||||||
isRemovedFromTotalUnreadCount: false,
|
isRemovedFromTotalUnreadCount: false,
|
||||||
presence: presenceTimestamp.flatMap { presenceTimestamp in
|
presence: presenceTimestamp.flatMap { presenceTimestamp in
|
||||||
|
@ -222,6 +222,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-207944868] = { return Api.FileHash.parse_fileHash($0) }
|
dict[-207944868] = { return Api.FileHash.parse_fileHash($0) }
|
||||||
dict[-11252123] = { return Api.Folder.parse_folder($0) }
|
dict[-11252123] = { return Api.Folder.parse_folder($0) }
|
||||||
dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) }
|
dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) }
|
||||||
|
dict[1885902651] = { return Api.ForumTopic.parse_forumTopic($0) }
|
||||||
dict[-1107729093] = { return Api.Game.parse_game($0) }
|
dict[-1107729093] = { return Api.Game.parse_game($0) }
|
||||||
dict[-1297942941] = { return Api.GeoPoint.parse_geoPoint($0) }
|
dict[-1297942941] = { return Api.GeoPoint.parse_geoPoint($0) }
|
||||||
dict[286776671] = { return Api.GeoPoint.parse_geoPointEmpty($0) }
|
dict[286776671] = { return Api.GeoPoint.parse_geoPointEmpty($0) }
|
||||||
@ -445,6 +446,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[455635795] = { return Api.MessageAction.parse_messageActionSecureValuesSentMe($0) }
|
dict[455635795] = { return Api.MessageAction.parse_messageActionSecureValuesSentMe($0) }
|
||||||
dict[-1434950843] = { return Api.MessageAction.parse_messageActionSetChatTheme($0) }
|
dict[-1434950843] = { return Api.MessageAction.parse_messageActionSetChatTheme($0) }
|
||||||
dict[-1441072131] = { return Api.MessageAction.parse_messageActionSetMessagesTTL($0) }
|
dict[-1441072131] = { return Api.MessageAction.parse_messageActionSetMessagesTTL($0) }
|
||||||
|
dict[1873254060] = { return Api.MessageAction.parse_messageActionTopicCreate($0) }
|
||||||
|
dict[-2113245653] = { return Api.MessageAction.parse_messageActionTopicEditIcon($0) }
|
||||||
|
dict[-838130739] = { return Api.MessageAction.parse_messageActionTopicEditTitle($0) }
|
||||||
dict[-1262252875] = { return Api.MessageAction.parse_messageActionWebViewDataSent($0) }
|
dict[-1262252875] = { return Api.MessageAction.parse_messageActionWebViewDataSent($0) }
|
||||||
dict[1205698681] = { return Api.MessageAction.parse_messageActionWebViewDataSentMe($0) }
|
dict[1205698681] = { return Api.MessageAction.parse_messageActionWebViewDataSentMe($0) }
|
||||||
dict[546203849] = { return Api.MessageEntity.parse_inputMessageEntityMentionName($0) }
|
dict[546203849] = { return Api.MessageEntity.parse_inputMessageEntityMentionName($0) }
|
||||||
@ -1003,6 +1007,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-1634752813] = { return Api.messages.FavedStickers.parse_favedStickersNotModified($0) }
|
dict[-1634752813] = { return Api.messages.FavedStickers.parse_favedStickersNotModified($0) }
|
||||||
dict[-1103615738] = { return Api.messages.FeaturedStickers.parse_featuredStickers($0) }
|
dict[-1103615738] = { return Api.messages.FeaturedStickers.parse_featuredStickers($0) }
|
||||||
dict[-958657434] = { return Api.messages.FeaturedStickers.parse_featuredStickersNotModified($0) }
|
dict[-958657434] = { return Api.messages.FeaturedStickers.parse_featuredStickersNotModified($0) }
|
||||||
|
dict[913709011] = { return Api.messages.ForumTopics.parse_forumTopics($0) }
|
||||||
dict[-1963942446] = { return Api.messages.FoundStickerSets.parse_foundStickerSets($0) }
|
dict[-1963942446] = { return Api.messages.FoundStickerSets.parse_foundStickerSets($0) }
|
||||||
dict[223655517] = { return Api.messages.FoundStickerSets.parse_foundStickerSetsNotModified($0) }
|
dict[223655517] = { return Api.messages.FoundStickerSets.parse_foundStickerSetsNotModified($0) }
|
||||||
dict[-1707344487] = { return Api.messages.HighScores.parse_highScores($0) }
|
dict[-1707344487] = { return Api.messages.HighScores.parse_highScores($0) }
|
||||||
@ -1281,6 +1286,8 @@ public extension Api {
|
|||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.FolderPeer:
|
case let _1 as Api.FolderPeer:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
|
case let _1 as Api.ForumTopic:
|
||||||
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.Game:
|
case let _1 as Api.Game:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.GeoPoint:
|
case let _1 as Api.GeoPoint:
|
||||||
@ -1779,6 +1786,8 @@ public extension Api {
|
|||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.messages.FeaturedStickers:
|
case let _1 as Api.messages.FeaturedStickers:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
|
case let _1 as Api.messages.ForumTopics:
|
||||||
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.messages.FoundStickerSets:
|
case let _1 as Api.messages.FoundStickerSets:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.messages.HighScores:
|
case let _1 as Api.messages.HighScores:
|
||||||
|
@ -1,3 +1,155 @@
|
|||||||
|
public extension Api {
|
||||||
|
enum InputStickerSet: TypeConstructorDescription {
|
||||||
|
case inputStickerSetAnimatedEmoji
|
||||||
|
case inputStickerSetAnimatedEmojiAnimations
|
||||||
|
case inputStickerSetDice(emoticon: String)
|
||||||
|
case inputStickerSetEmojiDefaultStatuses
|
||||||
|
case inputStickerSetEmojiGenericAnimations
|
||||||
|
case inputStickerSetEmpty
|
||||||
|
case inputStickerSetID(id: Int64, accessHash: Int64)
|
||||||
|
case inputStickerSetPremiumGifts
|
||||||
|
case inputStickerSetShortName(shortName: String)
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .inputStickerSetAnimatedEmoji:
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(42402760)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
case .inputStickerSetAnimatedEmojiAnimations:
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(215889721)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
case .inputStickerSetDice(let emoticon):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-427863538)
|
||||||
|
}
|
||||||
|
serializeString(emoticon, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .inputStickerSetEmojiDefaultStatuses:
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(701560302)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
case .inputStickerSetEmojiGenericAnimations:
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(80008398)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
case .inputStickerSetEmpty:
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-4838507)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
case .inputStickerSetID(let id, let accessHash):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1645763991)
|
||||||
|
}
|
||||||
|
serializeInt64(id, buffer: buffer, boxed: false)
|
||||||
|
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .inputStickerSetPremiumGifts:
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-930399486)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
case .inputStickerSetShortName(let shortName):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-2044933984)
|
||||||
|
}
|
||||||
|
serializeString(shortName, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .inputStickerSetAnimatedEmoji:
|
||||||
|
return ("inputStickerSetAnimatedEmoji", [])
|
||||||
|
case .inputStickerSetAnimatedEmojiAnimations:
|
||||||
|
return ("inputStickerSetAnimatedEmojiAnimations", [])
|
||||||
|
case .inputStickerSetDice(let emoticon):
|
||||||
|
return ("inputStickerSetDice", [("emoticon", String(describing: emoticon))])
|
||||||
|
case .inputStickerSetEmojiDefaultStatuses:
|
||||||
|
return ("inputStickerSetEmojiDefaultStatuses", [])
|
||||||
|
case .inputStickerSetEmojiGenericAnimations:
|
||||||
|
return ("inputStickerSetEmojiGenericAnimations", [])
|
||||||
|
case .inputStickerSetEmpty:
|
||||||
|
return ("inputStickerSetEmpty", [])
|
||||||
|
case .inputStickerSetID(let id, let accessHash):
|
||||||
|
return ("inputStickerSetID", [("id", String(describing: id)), ("accessHash", String(describing: accessHash))])
|
||||||
|
case .inputStickerSetPremiumGifts:
|
||||||
|
return ("inputStickerSetPremiumGifts", [])
|
||||||
|
case .inputStickerSetShortName(let shortName):
|
||||||
|
return ("inputStickerSetShortName", [("shortName", String(describing: shortName))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_inputStickerSetAnimatedEmoji(_ reader: BufferReader) -> InputStickerSet? {
|
||||||
|
return Api.InputStickerSet.inputStickerSetAnimatedEmoji
|
||||||
|
}
|
||||||
|
public static func parse_inputStickerSetAnimatedEmojiAnimations(_ reader: BufferReader) -> InputStickerSet? {
|
||||||
|
return Api.InputStickerSet.inputStickerSetAnimatedEmojiAnimations
|
||||||
|
}
|
||||||
|
public static func parse_inputStickerSetDice(_ reader: BufferReader) -> InputStickerSet? {
|
||||||
|
var _1: String?
|
||||||
|
_1 = parseString(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
if _c1 {
|
||||||
|
return Api.InputStickerSet.inputStickerSetDice(emoticon: _1!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_inputStickerSetEmojiDefaultStatuses(_ reader: BufferReader) -> InputStickerSet? {
|
||||||
|
return Api.InputStickerSet.inputStickerSetEmojiDefaultStatuses
|
||||||
|
}
|
||||||
|
public static func parse_inputStickerSetEmojiGenericAnimations(_ reader: BufferReader) -> InputStickerSet? {
|
||||||
|
return Api.InputStickerSet.inputStickerSetEmojiGenericAnimations
|
||||||
|
}
|
||||||
|
public static func parse_inputStickerSetEmpty(_ reader: BufferReader) -> InputStickerSet? {
|
||||||
|
return Api.InputStickerSet.inputStickerSetEmpty
|
||||||
|
}
|
||||||
|
public static func parse_inputStickerSetID(_ reader: BufferReader) -> InputStickerSet? {
|
||||||
|
var _1: Int64?
|
||||||
|
_1 = reader.readInt64()
|
||||||
|
var _2: Int64?
|
||||||
|
_2 = reader.readInt64()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.InputStickerSet.inputStickerSetID(id: _1!, accessHash: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_inputStickerSetPremiumGifts(_ reader: BufferReader) -> InputStickerSet? {
|
||||||
|
return Api.InputStickerSet.inputStickerSetPremiumGifts
|
||||||
|
}
|
||||||
|
public static func parse_inputStickerSetShortName(_ reader: BufferReader) -> InputStickerSet? {
|
||||||
|
var _1: String?
|
||||||
|
_1 = parseString(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
if _c1 {
|
||||||
|
return Api.InputStickerSet.inputStickerSetShortName(shortName: _1!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum InputStickerSetItem: TypeConstructorDescription {
|
enum InputStickerSetItem: TypeConstructorDescription {
|
||||||
case inputStickerSetItem(flags: Int32, document: Api.InputDocument, emoji: String, maskCoords: Api.MaskCoords?)
|
case inputStickerSetItem(flags: Int32, document: Api.InputDocument, emoji: String, maskCoords: Api.MaskCoords?)
|
||||||
@ -904,401 +1056,3 @@ public extension Api {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api {
|
|
||||||
indirect enum KeyboardButton: TypeConstructorDescription {
|
|
||||||
case inputKeyboardButtonUrlAuth(flags: Int32, text: String, fwdText: String?, url: String, bot: Api.InputUser)
|
|
||||||
case inputKeyboardButtonUserProfile(text: String, userId: Api.InputUser)
|
|
||||||
case keyboardButton(text: String)
|
|
||||||
case keyboardButtonBuy(text: String)
|
|
||||||
case keyboardButtonCallback(flags: Int32, text: String, data: Buffer)
|
|
||||||
case keyboardButtonGame(text: String)
|
|
||||||
case keyboardButtonRequestGeoLocation(text: String)
|
|
||||||
case keyboardButtonRequestPhone(text: String)
|
|
||||||
case keyboardButtonRequestPoll(flags: Int32, quiz: Api.Bool?, text: String)
|
|
||||||
case keyboardButtonSimpleWebView(text: String, url: String)
|
|
||||||
case keyboardButtonSwitchInline(flags: Int32, text: String, query: String)
|
|
||||||
case keyboardButtonUrl(text: String, url: String)
|
|
||||||
case keyboardButtonUrlAuth(flags: Int32, text: String, fwdText: String?, url: String, buttonId: Int32)
|
|
||||||
case keyboardButtonUserProfile(text: String, userId: Int64)
|
|
||||||
case keyboardButtonWebView(text: String, url: String)
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .inputKeyboardButtonUrlAuth(let flags, let text, let fwdText, let url, let bot):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-802258988)
|
|
||||||
}
|
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
|
||||||
serializeString(text, buffer: buffer, boxed: false)
|
|
||||||
if Int(flags) & Int(1 << 1) != 0 {serializeString(fwdText!, buffer: buffer, boxed: false)}
|
|
||||||
serializeString(url, buffer: buffer, boxed: false)
|
|
||||||
bot.serialize(buffer, true)
|
|
||||||
break
|
|
||||||
case .inputKeyboardButtonUserProfile(let text, let userId):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-376962181)
|
|
||||||
}
|
|
||||||
serializeString(text, buffer: buffer, boxed: false)
|
|
||||||
userId.serialize(buffer, true)
|
|
||||||
break
|
|
||||||
case .keyboardButton(let text):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-1560655744)
|
|
||||||
}
|
|
||||||
serializeString(text, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .keyboardButtonBuy(let text):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-1344716869)
|
|
||||||
}
|
|
||||||
serializeString(text, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .keyboardButtonCallback(let flags, let text, let data):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(901503851)
|
|
||||||
}
|
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
|
||||||
serializeString(text, buffer: buffer, boxed: false)
|
|
||||||
serializeBytes(data, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .keyboardButtonGame(let text):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(1358175439)
|
|
||||||
}
|
|
||||||
serializeString(text, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .keyboardButtonRequestGeoLocation(let text):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-59151553)
|
|
||||||
}
|
|
||||||
serializeString(text, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .keyboardButtonRequestPhone(let text):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-1318425559)
|
|
||||||
}
|
|
||||||
serializeString(text, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .keyboardButtonRequestPoll(let flags, let quiz, let text):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-1144565411)
|
|
||||||
}
|
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
|
||||||
if Int(flags) & Int(1 << 0) != 0 {quiz!.serialize(buffer, true)}
|
|
||||||
serializeString(text, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .keyboardButtonSimpleWebView(let text, let url):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-1598009252)
|
|
||||||
}
|
|
||||||
serializeString(text, buffer: buffer, boxed: false)
|
|
||||||
serializeString(url, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .keyboardButtonSwitchInline(let flags, let text, let query):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(90744648)
|
|
||||||
}
|
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
|
||||||
serializeString(text, buffer: buffer, boxed: false)
|
|
||||||
serializeString(query, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .keyboardButtonUrl(let text, let url):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(629866245)
|
|
||||||
}
|
|
||||||
serializeString(text, buffer: buffer, boxed: false)
|
|
||||||
serializeString(url, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .keyboardButtonUrlAuth(let flags, let text, let fwdText, let url, let buttonId):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(280464681)
|
|
||||||
}
|
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
|
||||||
serializeString(text, buffer: buffer, boxed: false)
|
|
||||||
if Int(flags) & Int(1 << 0) != 0 {serializeString(fwdText!, buffer: buffer, boxed: false)}
|
|
||||||
serializeString(url, buffer: buffer, boxed: false)
|
|
||||||
serializeInt32(buttonId, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .keyboardButtonUserProfile(let text, let userId):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(814112961)
|
|
||||||
}
|
|
||||||
serializeString(text, buffer: buffer, boxed: false)
|
|
||||||
serializeInt64(userId, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .keyboardButtonWebView(let text, let url):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(326529584)
|
|
||||||
}
|
|
||||||
serializeString(text, buffer: buffer, boxed: false)
|
|
||||||
serializeString(url, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .inputKeyboardButtonUrlAuth(let flags, let text, let fwdText, let url, let bot):
|
|
||||||
return ("inputKeyboardButtonUrlAuth", [("flags", String(describing: flags)), ("text", String(describing: text)), ("fwdText", String(describing: fwdText)), ("url", String(describing: url)), ("bot", String(describing: bot))])
|
|
||||||
case .inputKeyboardButtonUserProfile(let text, let userId):
|
|
||||||
return ("inputKeyboardButtonUserProfile", [("text", String(describing: text)), ("userId", String(describing: userId))])
|
|
||||||
case .keyboardButton(let text):
|
|
||||||
return ("keyboardButton", [("text", String(describing: text))])
|
|
||||||
case .keyboardButtonBuy(let text):
|
|
||||||
return ("keyboardButtonBuy", [("text", String(describing: text))])
|
|
||||||
case .keyboardButtonCallback(let flags, let text, let data):
|
|
||||||
return ("keyboardButtonCallback", [("flags", String(describing: flags)), ("text", String(describing: text)), ("data", String(describing: data))])
|
|
||||||
case .keyboardButtonGame(let text):
|
|
||||||
return ("keyboardButtonGame", [("text", String(describing: text))])
|
|
||||||
case .keyboardButtonRequestGeoLocation(let text):
|
|
||||||
return ("keyboardButtonRequestGeoLocation", [("text", String(describing: text))])
|
|
||||||
case .keyboardButtonRequestPhone(let text):
|
|
||||||
return ("keyboardButtonRequestPhone", [("text", String(describing: text))])
|
|
||||||
case .keyboardButtonRequestPoll(let flags, let quiz, let text):
|
|
||||||
return ("keyboardButtonRequestPoll", [("flags", String(describing: flags)), ("quiz", String(describing: quiz)), ("text", String(describing: text))])
|
|
||||||
case .keyboardButtonSimpleWebView(let text, let url):
|
|
||||||
return ("keyboardButtonSimpleWebView", [("text", String(describing: text)), ("url", String(describing: url))])
|
|
||||||
case .keyboardButtonSwitchInline(let flags, let text, let query):
|
|
||||||
return ("keyboardButtonSwitchInline", [("flags", String(describing: flags)), ("text", String(describing: text)), ("query", String(describing: query))])
|
|
||||||
case .keyboardButtonUrl(let text, let url):
|
|
||||||
return ("keyboardButtonUrl", [("text", String(describing: text)), ("url", String(describing: url))])
|
|
||||||
case .keyboardButtonUrlAuth(let flags, let text, let fwdText, let url, let buttonId):
|
|
||||||
return ("keyboardButtonUrlAuth", [("flags", String(describing: flags)), ("text", String(describing: text)), ("fwdText", String(describing: fwdText)), ("url", String(describing: url)), ("buttonId", String(describing: buttonId))])
|
|
||||||
case .keyboardButtonUserProfile(let text, let userId):
|
|
||||||
return ("keyboardButtonUserProfile", [("text", String(describing: text)), ("userId", String(describing: userId))])
|
|
||||||
case .keyboardButtonWebView(let text, let url):
|
|
||||||
return ("keyboardButtonWebView", [("text", String(describing: text)), ("url", String(describing: url))])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_inputKeyboardButtonUrlAuth(_ reader: BufferReader) -> KeyboardButton? {
|
|
||||||
var _1: Int32?
|
|
||||||
_1 = reader.readInt32()
|
|
||||||
var _2: String?
|
|
||||||
_2 = parseString(reader)
|
|
||||||
var _3: String?
|
|
||||||
if Int(_1!) & Int(1 << 1) != 0 {_3 = parseString(reader) }
|
|
||||||
var _4: String?
|
|
||||||
_4 = parseString(reader)
|
|
||||||
var _5: Api.InputUser?
|
|
||||||
if let signature = reader.readInt32() {
|
|
||||||
_5 = Api.parse(reader, signature: signature) as? Api.InputUser
|
|
||||||
}
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
|
|
||||||
let _c4 = _4 != nil
|
|
||||||
let _c5 = _5 != nil
|
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
|
||||||
return Api.KeyboardButton.inputKeyboardButtonUrlAuth(flags: _1!, text: _2!, fwdText: _3, url: _4!, bot: _5!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_inputKeyboardButtonUserProfile(_ reader: BufferReader) -> KeyboardButton? {
|
|
||||||
var _1: String?
|
|
||||||
_1 = parseString(reader)
|
|
||||||
var _2: Api.InputUser?
|
|
||||||
if let signature = reader.readInt32() {
|
|
||||||
_2 = Api.parse(reader, signature: signature) as? Api.InputUser
|
|
||||||
}
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.KeyboardButton.inputKeyboardButtonUserProfile(text: _1!, userId: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_keyboardButton(_ reader: BufferReader) -> KeyboardButton? {
|
|
||||||
var _1: String?
|
|
||||||
_1 = parseString(reader)
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
if _c1 {
|
|
||||||
return Api.KeyboardButton.keyboardButton(text: _1!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_keyboardButtonBuy(_ reader: BufferReader) -> KeyboardButton? {
|
|
||||||
var _1: String?
|
|
||||||
_1 = parseString(reader)
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
if _c1 {
|
|
||||||
return Api.KeyboardButton.keyboardButtonBuy(text: _1!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_keyboardButtonCallback(_ reader: BufferReader) -> KeyboardButton? {
|
|
||||||
var _1: Int32?
|
|
||||||
_1 = reader.readInt32()
|
|
||||||
var _2: String?
|
|
||||||
_2 = parseString(reader)
|
|
||||||
var _3: Buffer?
|
|
||||||
_3 = parseBytes(reader)
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
if _c1 && _c2 && _c3 {
|
|
||||||
return Api.KeyboardButton.keyboardButtonCallback(flags: _1!, text: _2!, data: _3!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_keyboardButtonGame(_ reader: BufferReader) -> KeyboardButton? {
|
|
||||||
var _1: String?
|
|
||||||
_1 = parseString(reader)
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
if _c1 {
|
|
||||||
return Api.KeyboardButton.keyboardButtonGame(text: _1!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_keyboardButtonRequestGeoLocation(_ reader: BufferReader) -> KeyboardButton? {
|
|
||||||
var _1: String?
|
|
||||||
_1 = parseString(reader)
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
if _c1 {
|
|
||||||
return Api.KeyboardButton.keyboardButtonRequestGeoLocation(text: _1!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_keyboardButtonRequestPhone(_ reader: BufferReader) -> KeyboardButton? {
|
|
||||||
var _1: String?
|
|
||||||
_1 = parseString(reader)
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
if _c1 {
|
|
||||||
return Api.KeyboardButton.keyboardButtonRequestPhone(text: _1!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_keyboardButtonRequestPoll(_ reader: BufferReader) -> KeyboardButton? {
|
|
||||||
var _1: Int32?
|
|
||||||
_1 = reader.readInt32()
|
|
||||||
var _2: Api.Bool?
|
|
||||||
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
|
|
||||||
_2 = Api.parse(reader, signature: signature) as? Api.Bool
|
|
||||||
} }
|
|
||||||
var _3: String?
|
|
||||||
_3 = parseString(reader)
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
if _c1 && _c2 && _c3 {
|
|
||||||
return Api.KeyboardButton.keyboardButtonRequestPoll(flags: _1!, quiz: _2, text: _3!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_keyboardButtonSimpleWebView(_ reader: BufferReader) -> KeyboardButton? {
|
|
||||||
var _1: String?
|
|
||||||
_1 = parseString(reader)
|
|
||||||
var _2: String?
|
|
||||||
_2 = parseString(reader)
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.KeyboardButton.keyboardButtonSimpleWebView(text: _1!, url: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_keyboardButtonSwitchInline(_ reader: BufferReader) -> KeyboardButton? {
|
|
||||||
var _1: Int32?
|
|
||||||
_1 = reader.readInt32()
|
|
||||||
var _2: String?
|
|
||||||
_2 = parseString(reader)
|
|
||||||
var _3: String?
|
|
||||||
_3 = parseString(reader)
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
if _c1 && _c2 && _c3 {
|
|
||||||
return Api.KeyboardButton.keyboardButtonSwitchInline(flags: _1!, text: _2!, query: _3!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_keyboardButtonUrl(_ reader: BufferReader) -> KeyboardButton? {
|
|
||||||
var _1: String?
|
|
||||||
_1 = parseString(reader)
|
|
||||||
var _2: String?
|
|
||||||
_2 = parseString(reader)
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.KeyboardButton.keyboardButtonUrl(text: _1!, url: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_keyboardButtonUrlAuth(_ reader: BufferReader) -> KeyboardButton? {
|
|
||||||
var _1: Int32?
|
|
||||||
_1 = reader.readInt32()
|
|
||||||
var _2: String?
|
|
||||||
_2 = parseString(reader)
|
|
||||||
var _3: String?
|
|
||||||
if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) }
|
|
||||||
var _4: String?
|
|
||||||
_4 = parseString(reader)
|
|
||||||
var _5: Int32?
|
|
||||||
_5 = reader.readInt32()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
|
|
||||||
let _c4 = _4 != nil
|
|
||||||
let _c5 = _5 != nil
|
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
|
||||||
return Api.KeyboardButton.keyboardButtonUrlAuth(flags: _1!, text: _2!, fwdText: _3, url: _4!, buttonId: _5!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_keyboardButtonUserProfile(_ reader: BufferReader) -> KeyboardButton? {
|
|
||||||
var _1: String?
|
|
||||||
_1 = parseString(reader)
|
|
||||||
var _2: Int64?
|
|
||||||
_2 = reader.readInt64()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.KeyboardButton.keyboardButtonUserProfile(text: _1!, userId: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_keyboardButtonWebView(_ reader: BufferReader) -> KeyboardButton? {
|
|
||||||
var _1: String?
|
|
||||||
_1 = parseString(reader)
|
|
||||||
var _2: String?
|
|
||||||
_2 = parseString(reader)
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.KeyboardButton.keyboardButtonWebView(text: _1!, url: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,401 @@
|
|||||||
|
public extension Api {
|
||||||
|
indirect enum KeyboardButton: TypeConstructorDescription {
|
||||||
|
case inputKeyboardButtonUrlAuth(flags: Int32, text: String, fwdText: String?, url: String, bot: Api.InputUser)
|
||||||
|
case inputKeyboardButtonUserProfile(text: String, userId: Api.InputUser)
|
||||||
|
case keyboardButton(text: String)
|
||||||
|
case keyboardButtonBuy(text: String)
|
||||||
|
case keyboardButtonCallback(flags: Int32, text: String, data: Buffer)
|
||||||
|
case keyboardButtonGame(text: String)
|
||||||
|
case keyboardButtonRequestGeoLocation(text: String)
|
||||||
|
case keyboardButtonRequestPhone(text: String)
|
||||||
|
case keyboardButtonRequestPoll(flags: Int32, quiz: Api.Bool?, text: String)
|
||||||
|
case keyboardButtonSimpleWebView(text: String, url: String)
|
||||||
|
case keyboardButtonSwitchInline(flags: Int32, text: String, query: String)
|
||||||
|
case keyboardButtonUrl(text: String, url: String)
|
||||||
|
case keyboardButtonUrlAuth(flags: Int32, text: String, fwdText: String?, url: String, buttonId: Int32)
|
||||||
|
case keyboardButtonUserProfile(text: String, userId: Int64)
|
||||||
|
case keyboardButtonWebView(text: String, url: String)
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .inputKeyboardButtonUrlAuth(let flags, let text, let fwdText, let url, let bot):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-802258988)
|
||||||
|
}
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
serializeString(text, buffer: buffer, boxed: false)
|
||||||
|
if Int(flags) & Int(1 << 1) != 0 {serializeString(fwdText!, buffer: buffer, boxed: false)}
|
||||||
|
serializeString(url, buffer: buffer, boxed: false)
|
||||||
|
bot.serialize(buffer, true)
|
||||||
|
break
|
||||||
|
case .inputKeyboardButtonUserProfile(let text, let userId):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-376962181)
|
||||||
|
}
|
||||||
|
serializeString(text, buffer: buffer, boxed: false)
|
||||||
|
userId.serialize(buffer, true)
|
||||||
|
break
|
||||||
|
case .keyboardButton(let text):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1560655744)
|
||||||
|
}
|
||||||
|
serializeString(text, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .keyboardButtonBuy(let text):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1344716869)
|
||||||
|
}
|
||||||
|
serializeString(text, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .keyboardButtonCallback(let flags, let text, let data):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(901503851)
|
||||||
|
}
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
serializeString(text, buffer: buffer, boxed: false)
|
||||||
|
serializeBytes(data, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .keyboardButtonGame(let text):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(1358175439)
|
||||||
|
}
|
||||||
|
serializeString(text, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .keyboardButtonRequestGeoLocation(let text):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-59151553)
|
||||||
|
}
|
||||||
|
serializeString(text, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .keyboardButtonRequestPhone(let text):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1318425559)
|
||||||
|
}
|
||||||
|
serializeString(text, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .keyboardButtonRequestPoll(let flags, let quiz, let text):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1144565411)
|
||||||
|
}
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
if Int(flags) & Int(1 << 0) != 0 {quiz!.serialize(buffer, true)}
|
||||||
|
serializeString(text, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .keyboardButtonSimpleWebView(let text, let url):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1598009252)
|
||||||
|
}
|
||||||
|
serializeString(text, buffer: buffer, boxed: false)
|
||||||
|
serializeString(url, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .keyboardButtonSwitchInline(let flags, let text, let query):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(90744648)
|
||||||
|
}
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
serializeString(text, buffer: buffer, boxed: false)
|
||||||
|
serializeString(query, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .keyboardButtonUrl(let text, let url):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(629866245)
|
||||||
|
}
|
||||||
|
serializeString(text, buffer: buffer, boxed: false)
|
||||||
|
serializeString(url, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .keyboardButtonUrlAuth(let flags, let text, let fwdText, let url, let buttonId):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(280464681)
|
||||||
|
}
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
serializeString(text, buffer: buffer, boxed: false)
|
||||||
|
if Int(flags) & Int(1 << 0) != 0 {serializeString(fwdText!, buffer: buffer, boxed: false)}
|
||||||
|
serializeString(url, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(buttonId, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .keyboardButtonUserProfile(let text, let userId):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(814112961)
|
||||||
|
}
|
||||||
|
serializeString(text, buffer: buffer, boxed: false)
|
||||||
|
serializeInt64(userId, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .keyboardButtonWebView(let text, let url):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(326529584)
|
||||||
|
}
|
||||||
|
serializeString(text, buffer: buffer, boxed: false)
|
||||||
|
serializeString(url, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .inputKeyboardButtonUrlAuth(let flags, let text, let fwdText, let url, let bot):
|
||||||
|
return ("inputKeyboardButtonUrlAuth", [("flags", String(describing: flags)), ("text", String(describing: text)), ("fwdText", String(describing: fwdText)), ("url", String(describing: url)), ("bot", String(describing: bot))])
|
||||||
|
case .inputKeyboardButtonUserProfile(let text, let userId):
|
||||||
|
return ("inputKeyboardButtonUserProfile", [("text", String(describing: text)), ("userId", String(describing: userId))])
|
||||||
|
case .keyboardButton(let text):
|
||||||
|
return ("keyboardButton", [("text", String(describing: text))])
|
||||||
|
case .keyboardButtonBuy(let text):
|
||||||
|
return ("keyboardButtonBuy", [("text", String(describing: text))])
|
||||||
|
case .keyboardButtonCallback(let flags, let text, let data):
|
||||||
|
return ("keyboardButtonCallback", [("flags", String(describing: flags)), ("text", String(describing: text)), ("data", String(describing: data))])
|
||||||
|
case .keyboardButtonGame(let text):
|
||||||
|
return ("keyboardButtonGame", [("text", String(describing: text))])
|
||||||
|
case .keyboardButtonRequestGeoLocation(let text):
|
||||||
|
return ("keyboardButtonRequestGeoLocation", [("text", String(describing: text))])
|
||||||
|
case .keyboardButtonRequestPhone(let text):
|
||||||
|
return ("keyboardButtonRequestPhone", [("text", String(describing: text))])
|
||||||
|
case .keyboardButtonRequestPoll(let flags, let quiz, let text):
|
||||||
|
return ("keyboardButtonRequestPoll", [("flags", String(describing: flags)), ("quiz", String(describing: quiz)), ("text", String(describing: text))])
|
||||||
|
case .keyboardButtonSimpleWebView(let text, let url):
|
||||||
|
return ("keyboardButtonSimpleWebView", [("text", String(describing: text)), ("url", String(describing: url))])
|
||||||
|
case .keyboardButtonSwitchInline(let flags, let text, let query):
|
||||||
|
return ("keyboardButtonSwitchInline", [("flags", String(describing: flags)), ("text", String(describing: text)), ("query", String(describing: query))])
|
||||||
|
case .keyboardButtonUrl(let text, let url):
|
||||||
|
return ("keyboardButtonUrl", [("text", String(describing: text)), ("url", String(describing: url))])
|
||||||
|
case .keyboardButtonUrlAuth(let flags, let text, let fwdText, let url, let buttonId):
|
||||||
|
return ("keyboardButtonUrlAuth", [("flags", String(describing: flags)), ("text", String(describing: text)), ("fwdText", String(describing: fwdText)), ("url", String(describing: url)), ("buttonId", String(describing: buttonId))])
|
||||||
|
case .keyboardButtonUserProfile(let text, let userId):
|
||||||
|
return ("keyboardButtonUserProfile", [("text", String(describing: text)), ("userId", String(describing: userId))])
|
||||||
|
case .keyboardButtonWebView(let text, let url):
|
||||||
|
return ("keyboardButtonWebView", [("text", String(describing: text)), ("url", String(describing: url))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_inputKeyboardButtonUrlAuth(_ reader: BufferReader) -> KeyboardButton? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: String?
|
||||||
|
_2 = parseString(reader)
|
||||||
|
var _3: String?
|
||||||
|
if Int(_1!) & Int(1 << 1) != 0 {_3 = parseString(reader) }
|
||||||
|
var _4: String?
|
||||||
|
_4 = parseString(reader)
|
||||||
|
var _5: Api.InputUser?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_5 = Api.parse(reader, signature: signature) as? Api.InputUser
|
||||||
|
}
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
|
||||||
|
let _c4 = _4 != nil
|
||||||
|
let _c5 = _5 != nil
|
||||||
|
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||||
|
return Api.KeyboardButton.inputKeyboardButtonUrlAuth(flags: _1!, text: _2!, fwdText: _3, url: _4!, bot: _5!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_inputKeyboardButtonUserProfile(_ reader: BufferReader) -> KeyboardButton? {
|
||||||
|
var _1: String?
|
||||||
|
_1 = parseString(reader)
|
||||||
|
var _2: Api.InputUser?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_2 = Api.parse(reader, signature: signature) as? Api.InputUser
|
||||||
|
}
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.KeyboardButton.inputKeyboardButtonUserProfile(text: _1!, userId: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_keyboardButton(_ reader: BufferReader) -> KeyboardButton? {
|
||||||
|
var _1: String?
|
||||||
|
_1 = parseString(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
if _c1 {
|
||||||
|
return Api.KeyboardButton.keyboardButton(text: _1!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_keyboardButtonBuy(_ reader: BufferReader) -> KeyboardButton? {
|
||||||
|
var _1: String?
|
||||||
|
_1 = parseString(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
if _c1 {
|
||||||
|
return Api.KeyboardButton.keyboardButtonBuy(text: _1!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_keyboardButtonCallback(_ reader: BufferReader) -> KeyboardButton? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: String?
|
||||||
|
_2 = parseString(reader)
|
||||||
|
var _3: Buffer?
|
||||||
|
_3 = parseBytes(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
if _c1 && _c2 && _c3 {
|
||||||
|
return Api.KeyboardButton.keyboardButtonCallback(flags: _1!, text: _2!, data: _3!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_keyboardButtonGame(_ reader: BufferReader) -> KeyboardButton? {
|
||||||
|
var _1: String?
|
||||||
|
_1 = parseString(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
if _c1 {
|
||||||
|
return Api.KeyboardButton.keyboardButtonGame(text: _1!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_keyboardButtonRequestGeoLocation(_ reader: BufferReader) -> KeyboardButton? {
|
||||||
|
var _1: String?
|
||||||
|
_1 = parseString(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
if _c1 {
|
||||||
|
return Api.KeyboardButton.keyboardButtonRequestGeoLocation(text: _1!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_keyboardButtonRequestPhone(_ reader: BufferReader) -> KeyboardButton? {
|
||||||
|
var _1: String?
|
||||||
|
_1 = parseString(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
if _c1 {
|
||||||
|
return Api.KeyboardButton.keyboardButtonRequestPhone(text: _1!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_keyboardButtonRequestPoll(_ reader: BufferReader) -> KeyboardButton? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: Api.Bool?
|
||||||
|
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
|
||||||
|
_2 = Api.parse(reader, signature: signature) as? Api.Bool
|
||||||
|
} }
|
||||||
|
var _3: String?
|
||||||
|
_3 = parseString(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
if _c1 && _c2 && _c3 {
|
||||||
|
return Api.KeyboardButton.keyboardButtonRequestPoll(flags: _1!, quiz: _2, text: _3!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_keyboardButtonSimpleWebView(_ reader: BufferReader) -> KeyboardButton? {
|
||||||
|
var _1: String?
|
||||||
|
_1 = parseString(reader)
|
||||||
|
var _2: String?
|
||||||
|
_2 = parseString(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.KeyboardButton.keyboardButtonSimpleWebView(text: _1!, url: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_keyboardButtonSwitchInline(_ reader: BufferReader) -> KeyboardButton? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: String?
|
||||||
|
_2 = parseString(reader)
|
||||||
|
var _3: String?
|
||||||
|
_3 = parseString(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
if _c1 && _c2 && _c3 {
|
||||||
|
return Api.KeyboardButton.keyboardButtonSwitchInline(flags: _1!, text: _2!, query: _3!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_keyboardButtonUrl(_ reader: BufferReader) -> KeyboardButton? {
|
||||||
|
var _1: String?
|
||||||
|
_1 = parseString(reader)
|
||||||
|
var _2: String?
|
||||||
|
_2 = parseString(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.KeyboardButton.keyboardButtonUrl(text: _1!, url: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_keyboardButtonUrlAuth(_ reader: BufferReader) -> KeyboardButton? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: String?
|
||||||
|
_2 = parseString(reader)
|
||||||
|
var _3: String?
|
||||||
|
if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) }
|
||||||
|
var _4: String?
|
||||||
|
_4 = parseString(reader)
|
||||||
|
var _5: Int32?
|
||||||
|
_5 = reader.readInt32()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
|
||||||
|
let _c4 = _4 != nil
|
||||||
|
let _c5 = _5 != nil
|
||||||
|
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||||
|
return Api.KeyboardButton.keyboardButtonUrlAuth(flags: _1!, text: _2!, fwdText: _3, url: _4!, buttonId: _5!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_keyboardButtonUserProfile(_ reader: BufferReader) -> KeyboardButton? {
|
||||||
|
var _1: String?
|
||||||
|
_1 = parseString(reader)
|
||||||
|
var _2: Int64?
|
||||||
|
_2 = reader.readInt64()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.KeyboardButton.keyboardButtonUserProfile(text: _1!, userId: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_keyboardButtonWebView(_ reader: BufferReader) -> KeyboardButton? {
|
||||||
|
var _1: String?
|
||||||
|
_1 = parseString(reader)
|
||||||
|
var _2: String?
|
||||||
|
_2 = parseString(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.KeyboardButton.keyboardButtonWebView(text: _1!, url: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum KeyboardButtonRow: TypeConstructorDescription {
|
enum KeyboardButtonRow: TypeConstructorDescription {
|
||||||
case keyboardButtonRow(buttons: [Api.KeyboardButton])
|
case keyboardButtonRow(buttons: [Api.KeyboardButton])
|
||||||
@ -621,6 +1019,9 @@ public extension Api {
|
|||||||
case messageActionSecureValuesSentMe(values: [Api.SecureValue], credentials: Api.SecureCredentialsEncrypted)
|
case messageActionSecureValuesSentMe(values: [Api.SecureValue], credentials: Api.SecureCredentialsEncrypted)
|
||||||
case messageActionSetChatTheme(emoticon: String)
|
case messageActionSetChatTheme(emoticon: String)
|
||||||
case messageActionSetMessagesTTL(period: Int32)
|
case messageActionSetMessagesTTL(period: Int32)
|
||||||
|
case messageActionTopicCreate(flags: Int32, title: String, iconEmojiId: Int64?)
|
||||||
|
case messageActionTopicEditIcon(emojiDocumentId: Int64)
|
||||||
|
case messageActionTopicEditTitle(title: String)
|
||||||
case messageActionWebViewDataSent(text: String)
|
case messageActionWebViewDataSent(text: String)
|
||||||
case messageActionWebViewDataSentMe(text: String, data: String)
|
case messageActionWebViewDataSentMe(text: String, data: String)
|
||||||
|
|
||||||
@ -856,6 +1257,26 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
serializeInt32(period, buffer: buffer, boxed: false)
|
serializeInt32(period, buffer: buffer, boxed: false)
|
||||||
break
|
break
|
||||||
|
case .messageActionTopicCreate(let flags, let title, let iconEmojiId):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(1873254060)
|
||||||
|
}
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
serializeString(title, buffer: buffer, boxed: false)
|
||||||
|
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(iconEmojiId!, buffer: buffer, boxed: false)}
|
||||||
|
break
|
||||||
|
case .messageActionTopicEditIcon(let emojiDocumentId):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-2113245653)
|
||||||
|
}
|
||||||
|
serializeInt64(emojiDocumentId, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .messageActionTopicEditTitle(let title):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-838130739)
|
||||||
|
}
|
||||||
|
serializeString(title, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
case .messageActionWebViewDataSent(let text):
|
case .messageActionWebViewDataSent(let text):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-1262252875)
|
buffer.appendInt32(-1262252875)
|
||||||
@ -936,6 +1357,12 @@ public extension Api {
|
|||||||
return ("messageActionSetChatTheme", [("emoticon", String(describing: emoticon))])
|
return ("messageActionSetChatTheme", [("emoticon", String(describing: emoticon))])
|
||||||
case .messageActionSetMessagesTTL(let period):
|
case .messageActionSetMessagesTTL(let period):
|
||||||
return ("messageActionSetMessagesTTL", [("period", String(describing: period))])
|
return ("messageActionSetMessagesTTL", [("period", String(describing: period))])
|
||||||
|
case .messageActionTopicCreate(let flags, let title, let iconEmojiId):
|
||||||
|
return ("messageActionTopicCreate", [("flags", String(describing: flags)), ("title", String(describing: title)), ("iconEmojiId", String(describing: iconEmojiId))])
|
||||||
|
case .messageActionTopicEditIcon(let emojiDocumentId):
|
||||||
|
return ("messageActionTopicEditIcon", [("emojiDocumentId", String(describing: emojiDocumentId))])
|
||||||
|
case .messageActionTopicEditTitle(let title):
|
||||||
|
return ("messageActionTopicEditTitle", [("title", String(describing: title))])
|
||||||
case .messageActionWebViewDataSent(let text):
|
case .messageActionWebViewDataSent(let text):
|
||||||
return ("messageActionWebViewDataSent", [("text", String(describing: text))])
|
return ("messageActionWebViewDataSent", [("text", String(describing: text))])
|
||||||
case .messageActionWebViewDataSentMe(let text, let data):
|
case .messageActionWebViewDataSentMe(let text, let data):
|
||||||
@ -1330,6 +1757,45 @@ public extension Api {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public static func parse_messageActionTopicCreate(_ reader: BufferReader) -> MessageAction? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: String?
|
||||||
|
_2 = parseString(reader)
|
||||||
|
var _3: Int64?
|
||||||
|
if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt64() }
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
|
||||||
|
if _c1 && _c2 && _c3 {
|
||||||
|
return Api.MessageAction.messageActionTopicCreate(flags: _1!, title: _2!, iconEmojiId: _3)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_messageActionTopicEditIcon(_ reader: BufferReader) -> MessageAction? {
|
||||||
|
var _1: Int64?
|
||||||
|
_1 = reader.readInt64()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
if _c1 {
|
||||||
|
return Api.MessageAction.messageActionTopicEditIcon(emojiDocumentId: _1!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_messageActionTopicEditTitle(_ reader: BufferReader) -> MessageAction? {
|
||||||
|
var _1: String?
|
||||||
|
_1 = parseString(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
if _c1 {
|
||||||
|
return Api.MessageAction.messageActionTopicEditTitle(title: _1!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
public static func parse_messageActionWebViewDataSent(_ reader: BufferReader) -> MessageAction? {
|
public static func parse_messageActionWebViewDataSent(_ reader: BufferReader) -> MessageAction? {
|
||||||
var _1: String?
|
var _1: String?
|
||||||
_1 = parseString(reader)
|
_1 = parseString(reader)
|
||||||
|
@ -868,6 +868,90 @@ public extension Api.messages {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public extension Api.messages {
|
||||||
|
enum ForumTopics: TypeConstructorDescription {
|
||||||
|
case forumTopics(flags: Int32, count: Int32, topics: [Api.ForumTopic], messages: [Api.Message], chats: [Api.Chat], users: [Api.User], pts: Int32)
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .forumTopics(let flags, let count, let topics, let messages, let chats, let users, let pts):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(913709011)
|
||||||
|
}
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(count, buffer: buffer, boxed: false)
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(topics.count))
|
||||||
|
for item in topics {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(messages.count))
|
||||||
|
for item in messages {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(chats.count))
|
||||||
|
for item in chats {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(users.count))
|
||||||
|
for item in users {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
serializeInt32(pts, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .forumTopics(let flags, let count, let topics, let messages, let chats, let users, let pts):
|
||||||
|
return ("forumTopics", [("flags", String(describing: flags)), ("count", String(describing: count)), ("topics", String(describing: topics)), ("messages", String(describing: messages)), ("chats", String(describing: chats)), ("users", String(describing: users)), ("pts", String(describing: pts))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_forumTopics(_ reader: BufferReader) -> ForumTopics? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: Int32?
|
||||||
|
_2 = reader.readInt32()
|
||||||
|
var _3: [Api.ForumTopic]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ForumTopic.self)
|
||||||
|
}
|
||||||
|
var _4: [Api.Message]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
|
||||||
|
}
|
||||||
|
var _5: [Api.Chat]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
||||||
|
}
|
||||||
|
var _6: [Api.User]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||||
|
}
|
||||||
|
var _7: Int32?
|
||||||
|
_7 = reader.readInt32()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
let _c4 = _4 != nil
|
||||||
|
let _c5 = _5 != nil
|
||||||
|
let _c6 = _6 != nil
|
||||||
|
let _c7 = _7 != nil
|
||||||
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
|
||||||
|
return Api.messages.ForumTopics.forumTopics(flags: _1!, count: _2!, topics: _3!, messages: _4!, chats: _5!, users: _6!, pts: _7!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api.messages {
|
public extension Api.messages {
|
||||||
enum FoundStickerSets: TypeConstructorDescription {
|
enum FoundStickerSets: TypeConstructorDescription {
|
||||||
case foundStickerSets(hash: Int64, sets: [Api.StickerSetCovered])
|
case foundStickerSets(hash: Int64, sets: [Api.StickerSetCovered])
|
||||||
|
@ -1819,6 +1819,26 @@ public extension Api.functions.channels {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public extension Api.functions.channels {
|
||||||
|
static func createForumTopic(flags: Int32, channel: Api.InputChannel, title: String, iconEmojiId: Int64?, randomId: Int64, sendAs: Api.InputPeer?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(1623145417)
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
channel.serialize(buffer, true)
|
||||||
|
serializeString(title, buffer: buffer, boxed: false)
|
||||||
|
if Int(flags) & Int(1 << 3) != 0 {serializeInt64(iconEmojiId!, buffer: buffer, boxed: false)}
|
||||||
|
serializeInt64(randomId, buffer: buffer, boxed: false)
|
||||||
|
if Int(flags) & Int(1 << 2) != 0 {sendAs!.serialize(buffer, true)}
|
||||||
|
return (FunctionDescription(name: "channels.createForumTopic", parameters: [("flags", String(describing: flags)), ("channel", String(describing: channel)), ("title", String(describing: title)), ("iconEmojiId", String(describing: iconEmojiId)), ("randomId", String(describing: randomId)), ("sendAs", String(describing: sendAs))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.Updates?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api.functions.channels {
|
public extension Api.functions.channels {
|
||||||
static func deleteChannel(channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
static func deleteChannel(channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
@ -1939,6 +1959,40 @@ public extension Api.functions.channels {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public extension Api.functions.channels {
|
||||||
|
static func editForumIcon(channel: Api.InputChannel, topicId: Int32, emojiDocumentId: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(1439605469)
|
||||||
|
channel.serialize(buffer, true)
|
||||||
|
serializeInt32(topicId, buffer: buffer, boxed: false)
|
||||||
|
serializeInt64(emojiDocumentId, buffer: buffer, boxed: false)
|
||||||
|
return (FunctionDescription(name: "channels.editForumIcon", parameters: [("channel", String(describing: channel)), ("topicId", String(describing: topicId)), ("emojiDocumentId", String(describing: emojiDocumentId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.Updates?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public extension Api.functions.channels {
|
||||||
|
static func editForumTitle(channel: Api.InputChannel, topicId: Int32, title: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(-2004764239)
|
||||||
|
channel.serialize(buffer, true)
|
||||||
|
serializeInt32(topicId, buffer: buffer, boxed: false)
|
||||||
|
serializeString(title, buffer: buffer, boxed: false)
|
||||||
|
return (FunctionDescription(name: "channels.editForumTitle", parameters: [("channel", String(describing: channel)), ("topicId", String(describing: topicId)), ("title", String(describing: title))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.Updates?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api.functions.channels {
|
public extension Api.functions.channels {
|
||||||
static func editLocation(channel: Api.InputChannel, geoPoint: Api.InputGeoPoint, address: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
static func editLocation(channel: Api.InputChannel, geoPoint: Api.InputGeoPoint, address: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
@ -2065,6 +2119,47 @@ public extension Api.functions.channels {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public extension Api.functions.channels {
|
||||||
|
static func getForumTopics(flags: Int32, channel: Api.InputChannel, q: String?, offsetDate: Int32, offsetId: Int32, offsetTopic: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.ForumTopics>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(233136337)
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
channel.serialize(buffer, true)
|
||||||
|
if Int(flags) & Int(1 << 0) != 0 {serializeString(q!, buffer: buffer, boxed: false)}
|
||||||
|
serializeInt32(offsetDate, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(offsetId, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(offsetTopic, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(limit, buffer: buffer, boxed: false)
|
||||||
|
return (FunctionDescription(name: "channels.getForumTopics", parameters: [("flags", String(describing: flags)), ("channel", String(describing: channel)), ("q", String(describing: q)), ("offsetDate", String(describing: offsetDate)), ("offsetId", String(describing: offsetId)), ("offsetTopic", String(describing: offsetTopic)), ("limit", String(describing: limit))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ForumTopics? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.messages.ForumTopics?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.messages.ForumTopics
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public extension Api.functions.channels {
|
||||||
|
static func getForumTopicsByID(channel: Api.InputChannel, topics: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.ForumTopics>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(-1333584199)
|
||||||
|
channel.serialize(buffer, true)
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(topics.count))
|
||||||
|
for item in topics {
|
||||||
|
serializeInt32(item, buffer: buffer, boxed: false)
|
||||||
|
}
|
||||||
|
return (FunctionDescription(name: "channels.getForumTopicsByID", parameters: [("channel", String(describing: channel)), ("topics", String(describing: topics))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ForumTopics? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.messages.ForumTopics?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.messages.ForumTopics
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api.functions.channels {
|
public extension Api.functions.channels {
|
||||||
static func getFullChannel(channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.ChatFull>) {
|
static func getFullChannel(channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.ChatFull>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
@ -2349,6 +2444,22 @@ public extension Api.functions.channels {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public extension Api.functions.channels {
|
||||||
|
static func toggleForum(channel: Api.InputChannel, enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(-1540781271)
|
||||||
|
channel.serialize(buffer, true)
|
||||||
|
enabled.serialize(buffer, true)
|
||||||
|
return (FunctionDescription(name: "channels.toggleForum", parameters: [("channel", String(describing: channel)), ("enabled", String(describing: enabled))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.Updates?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api.functions.channels {
|
public extension Api.functions.channels {
|
||||||
static func toggleJoinRequest(channel: Api.InputChannel, enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
static func toggleJoinRequest(channel: Api.InputChannel, enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
|
@ -1093,65 +1093,65 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum Game: TypeConstructorDescription {
|
enum ForumTopic: TypeConstructorDescription {
|
||||||
case game(flags: Int32, id: Int64, accessHash: Int64, shortName: String, title: String, description: String, photo: Api.Photo, document: Api.Document?)
|
case forumTopic(flags: Int32, id: Int32, date: Int32, title: String, iconEmojiId: Int64?, topMessage: Int32, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32)
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
case .game(let flags, let id, let accessHash, let shortName, let title, let description, let photo, let document):
|
case .forumTopic(let flags, let id, let date, let title, let iconEmojiId, let topMessage, let readInboxMaxId, let readOutboxMaxId, let unreadCount):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-1107729093)
|
buffer.appendInt32(1885902651)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeInt64(id, buffer: buffer, boxed: false)
|
serializeInt32(id, buffer: buffer, boxed: false)
|
||||||
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
serializeInt32(date, buffer: buffer, boxed: false)
|
||||||
serializeString(shortName, buffer: buffer, boxed: false)
|
|
||||||
serializeString(title, buffer: buffer, boxed: false)
|
serializeString(title, buffer: buffer, boxed: false)
|
||||||
serializeString(description, buffer: buffer, boxed: false)
|
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(iconEmojiId!, buffer: buffer, boxed: false)}
|
||||||
photo.serialize(buffer, true)
|
serializeInt32(topMessage, buffer: buffer, boxed: false)
|
||||||
if Int(flags) & Int(1 << 0) != 0 {document!.serialize(buffer, true)}
|
serializeInt32(readInboxMaxId, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(readOutboxMaxId, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(unreadCount, buffer: buffer, boxed: false)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
switch self {
|
switch self {
|
||||||
case .game(let flags, let id, let accessHash, let shortName, let title, let description, let photo, let document):
|
case .forumTopic(let flags, let id, let date, let title, let iconEmojiId, let topMessage, let readInboxMaxId, let readOutboxMaxId, let unreadCount):
|
||||||
return ("game", [("flags", String(describing: flags)), ("id", String(describing: id)), ("accessHash", String(describing: accessHash)), ("shortName", String(describing: shortName)), ("title", String(describing: title)), ("description", String(describing: description)), ("photo", String(describing: photo)), ("document", String(describing: document))])
|
return ("forumTopic", [("flags", String(describing: flags)), ("id", String(describing: id)), ("date", String(describing: date)), ("title", String(describing: title)), ("iconEmojiId", String(describing: iconEmojiId)), ("topMessage", String(describing: topMessage)), ("readInboxMaxId", String(describing: readInboxMaxId)), ("readOutboxMaxId", String(describing: readOutboxMaxId)), ("unreadCount", String(describing: unreadCount))])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func parse_game(_ reader: BufferReader) -> Game? {
|
public static func parse_forumTopic(_ reader: BufferReader) -> ForumTopic? {
|
||||||
var _1: Int32?
|
var _1: Int32?
|
||||||
_1 = reader.readInt32()
|
_1 = reader.readInt32()
|
||||||
var _2: Int64?
|
var _2: Int32?
|
||||||
_2 = reader.readInt64()
|
_2 = reader.readInt32()
|
||||||
var _3: Int64?
|
var _3: Int32?
|
||||||
_3 = reader.readInt64()
|
_3 = reader.readInt32()
|
||||||
var _4: String?
|
var _4: String?
|
||||||
_4 = parseString(reader)
|
_4 = parseString(reader)
|
||||||
var _5: String?
|
var _5: Int64?
|
||||||
_5 = parseString(reader)
|
if Int(_1!) & Int(1 << 0) != 0 {_5 = reader.readInt64() }
|
||||||
var _6: String?
|
var _6: Int32?
|
||||||
_6 = parseString(reader)
|
_6 = reader.readInt32()
|
||||||
var _7: Api.Photo?
|
var _7: Int32?
|
||||||
if let signature = reader.readInt32() {
|
_7 = reader.readInt32()
|
||||||
_7 = Api.parse(reader, signature: signature) as? Api.Photo
|
var _8: Int32?
|
||||||
}
|
_8 = reader.readInt32()
|
||||||
var _8: Api.Document?
|
var _9: Int32?
|
||||||
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
|
_9 = reader.readInt32()
|
||||||
_8 = Api.parse(reader, signature: signature) as? Api.Document
|
|
||||||
} }
|
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
let _c4 = _4 != nil
|
let _c4 = _4 != nil
|
||||||
let _c5 = _5 != nil
|
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
|
||||||
let _c6 = _6 != nil
|
let _c6 = _6 != nil
|
||||||
let _c7 = _7 != nil
|
let _c7 = _7 != nil
|
||||||
let _c8 = (Int(_1!) & Int(1 << 0) == 0) || _8 != nil
|
let _c8 = _8 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
|
let _c9 = _9 != nil
|
||||||
return Api.Game.game(flags: _1!, id: _2!, accessHash: _3!, shortName: _4!, title: _5!, description: _6!, photo: _7!, document: _8)
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
|
||||||
|
return Api.ForumTopic.forumTopic(flags: _1!, id: _2!, date: _3!, title: _4!, iconEmojiId: _5, topMessage: _6!, readInboxMaxId: _7!, readOutboxMaxId: _8!, unreadCount: _9!)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -1,3 +1,71 @@
|
|||||||
|
public extension Api {
|
||||||
|
enum Game: TypeConstructorDescription {
|
||||||
|
case game(flags: Int32, id: Int64, accessHash: Int64, shortName: String, title: String, description: String, photo: Api.Photo, document: Api.Document?)
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .game(let flags, let id, let accessHash, let shortName, let title, let description, let photo, let document):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1107729093)
|
||||||
|
}
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
serializeInt64(id, buffer: buffer, boxed: false)
|
||||||
|
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
||||||
|
serializeString(shortName, buffer: buffer, boxed: false)
|
||||||
|
serializeString(title, buffer: buffer, boxed: false)
|
||||||
|
serializeString(description, buffer: buffer, boxed: false)
|
||||||
|
photo.serialize(buffer, true)
|
||||||
|
if Int(flags) & Int(1 << 0) != 0 {document!.serialize(buffer, true)}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .game(let flags, let id, let accessHash, let shortName, let title, let description, let photo, let document):
|
||||||
|
return ("game", [("flags", String(describing: flags)), ("id", String(describing: id)), ("accessHash", String(describing: accessHash)), ("shortName", String(describing: shortName)), ("title", String(describing: title)), ("description", String(describing: description)), ("photo", String(describing: photo)), ("document", String(describing: document))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_game(_ reader: BufferReader) -> Game? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: Int64?
|
||||||
|
_2 = reader.readInt64()
|
||||||
|
var _3: Int64?
|
||||||
|
_3 = reader.readInt64()
|
||||||
|
var _4: String?
|
||||||
|
_4 = parseString(reader)
|
||||||
|
var _5: String?
|
||||||
|
_5 = parseString(reader)
|
||||||
|
var _6: String?
|
||||||
|
_6 = parseString(reader)
|
||||||
|
var _7: Api.Photo?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_7 = Api.parse(reader, signature: signature) as? Api.Photo
|
||||||
|
}
|
||||||
|
var _8: Api.Document?
|
||||||
|
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
|
||||||
|
_8 = Api.parse(reader, signature: signature) as? Api.Document
|
||||||
|
} }
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
let _c4 = _4 != nil
|
||||||
|
let _c5 = _5 != nil
|
||||||
|
let _c6 = _6 != nil
|
||||||
|
let _c7 = _7 != nil
|
||||||
|
let _c8 = (Int(_1!) & Int(1 << 0) == 0) || _8 != nil
|
||||||
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
|
||||||
|
return Api.Game.game(flags: _1!, id: _2!, accessHash: _3!, shortName: _4!, title: _5!, description: _6!, photo: _7!, document: _8)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum GeoPoint: TypeConstructorDescription {
|
enum GeoPoint: TypeConstructorDescription {
|
||||||
case geoPoint(flags: Int32, long: Double, lat: Double, accessHash: Int64, accuracyRadius: Int32?)
|
case geoPoint(flags: Int32, long: Double, lat: Double, accessHash: Int64, accuracyRadius: Int32?)
|
||||||
@ -1264,85 +1332,3 @@ public extension Api {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api {
|
|
||||||
indirect enum InputChannel: TypeConstructorDescription {
|
|
||||||
case inputChannel(channelId: Int64, accessHash: Int64)
|
|
||||||
case inputChannelEmpty
|
|
||||||
case inputChannelFromMessage(peer: Api.InputPeer, msgId: Int32, channelId: Int64)
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .inputChannel(let channelId, let accessHash):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-212145112)
|
|
||||||
}
|
|
||||||
serializeInt64(channelId, buffer: buffer, boxed: false)
|
|
||||||
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .inputChannelEmpty:
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-292807034)
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
case .inputChannelFromMessage(let peer, let msgId, let channelId):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(1536380829)
|
|
||||||
}
|
|
||||||
peer.serialize(buffer, true)
|
|
||||||
serializeInt32(msgId, buffer: buffer, boxed: false)
|
|
||||||
serializeInt64(channelId, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .inputChannel(let channelId, let accessHash):
|
|
||||||
return ("inputChannel", [("channelId", String(describing: channelId)), ("accessHash", String(describing: accessHash))])
|
|
||||||
case .inputChannelEmpty:
|
|
||||||
return ("inputChannelEmpty", [])
|
|
||||||
case .inputChannelFromMessage(let peer, let msgId, let channelId):
|
|
||||||
return ("inputChannelFromMessage", [("peer", String(describing: peer)), ("msgId", String(describing: msgId)), ("channelId", String(describing: channelId))])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_inputChannel(_ reader: BufferReader) -> InputChannel? {
|
|
||||||
var _1: Int64?
|
|
||||||
_1 = reader.readInt64()
|
|
||||||
var _2: Int64?
|
|
||||||
_2 = reader.readInt64()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.InputChannel.inputChannel(channelId: _1!, accessHash: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_inputChannelEmpty(_ reader: BufferReader) -> InputChannel? {
|
|
||||||
return Api.InputChannel.inputChannelEmpty
|
|
||||||
}
|
|
||||||
public static func parse_inputChannelFromMessage(_ reader: BufferReader) -> InputChannel? {
|
|
||||||
var _1: Api.InputPeer?
|
|
||||||
if let signature = reader.readInt32() {
|
|
||||||
_1 = Api.parse(reader, signature: signature) as? Api.InputPeer
|
|
||||||
}
|
|
||||||
var _2: Int32?
|
|
||||||
_2 = reader.readInt32()
|
|
||||||
var _3: Int64?
|
|
||||||
_3 = reader.readInt64()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
if _c1 && _c2 && _c3 {
|
|
||||||
return Api.InputChannel.inputChannelFromMessage(peer: _1!, msgId: _2!, channelId: _3!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,85 @@
|
|||||||
|
public extension Api {
|
||||||
|
indirect enum InputChannel: TypeConstructorDescription {
|
||||||
|
case inputChannel(channelId: Int64, accessHash: Int64)
|
||||||
|
case inputChannelEmpty
|
||||||
|
case inputChannelFromMessage(peer: Api.InputPeer, msgId: Int32, channelId: Int64)
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .inputChannel(let channelId, let accessHash):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-212145112)
|
||||||
|
}
|
||||||
|
serializeInt64(channelId, buffer: buffer, boxed: false)
|
||||||
|
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .inputChannelEmpty:
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-292807034)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
case .inputChannelFromMessage(let peer, let msgId, let channelId):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(1536380829)
|
||||||
|
}
|
||||||
|
peer.serialize(buffer, true)
|
||||||
|
serializeInt32(msgId, buffer: buffer, boxed: false)
|
||||||
|
serializeInt64(channelId, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .inputChannel(let channelId, let accessHash):
|
||||||
|
return ("inputChannel", [("channelId", String(describing: channelId)), ("accessHash", String(describing: accessHash))])
|
||||||
|
case .inputChannelEmpty:
|
||||||
|
return ("inputChannelEmpty", [])
|
||||||
|
case .inputChannelFromMessage(let peer, let msgId, let channelId):
|
||||||
|
return ("inputChannelFromMessage", [("peer", String(describing: peer)), ("msgId", String(describing: msgId)), ("channelId", String(describing: channelId))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_inputChannel(_ reader: BufferReader) -> InputChannel? {
|
||||||
|
var _1: Int64?
|
||||||
|
_1 = reader.readInt64()
|
||||||
|
var _2: Int64?
|
||||||
|
_2 = reader.readInt64()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.InputChannel.inputChannel(channelId: _1!, accessHash: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_inputChannelEmpty(_ reader: BufferReader) -> InputChannel? {
|
||||||
|
return Api.InputChannel.inputChannelEmpty
|
||||||
|
}
|
||||||
|
public static func parse_inputChannelFromMessage(_ reader: BufferReader) -> InputChannel? {
|
||||||
|
var _1: Api.InputPeer?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_1 = Api.parse(reader, signature: signature) as? Api.InputPeer
|
||||||
|
}
|
||||||
|
var _2: Int32?
|
||||||
|
_2 = reader.readInt32()
|
||||||
|
var _3: Int64?
|
||||||
|
_3 = reader.readInt64()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
if _c1 && _c2 && _c3 {
|
||||||
|
return Api.InputChannel.inputChannelFromMessage(peer: _1!, msgId: _2!, channelId: _3!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum InputChatPhoto: TypeConstructorDescription {
|
enum InputChatPhoto: TypeConstructorDescription {
|
||||||
case inputChatPhoto(id: Api.InputPhoto)
|
case inputChatPhoto(id: Api.InputPhoto)
|
||||||
@ -922,129 +1004,3 @@ public extension Api {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api {
|
|
||||||
indirect enum InputGame: TypeConstructorDescription {
|
|
||||||
case inputGameID(id: Int64, accessHash: Int64)
|
|
||||||
case inputGameShortName(botId: Api.InputUser, shortName: String)
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .inputGameID(let id, let accessHash):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(53231223)
|
|
||||||
}
|
|
||||||
serializeInt64(id, buffer: buffer, boxed: false)
|
|
||||||
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .inputGameShortName(let botId, let shortName):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-1020139510)
|
|
||||||
}
|
|
||||||
botId.serialize(buffer, true)
|
|
||||||
serializeString(shortName, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .inputGameID(let id, let accessHash):
|
|
||||||
return ("inputGameID", [("id", String(describing: id)), ("accessHash", String(describing: accessHash))])
|
|
||||||
case .inputGameShortName(let botId, let shortName):
|
|
||||||
return ("inputGameShortName", [("botId", String(describing: botId)), ("shortName", String(describing: shortName))])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_inputGameID(_ reader: BufferReader) -> InputGame? {
|
|
||||||
var _1: Int64?
|
|
||||||
_1 = reader.readInt64()
|
|
||||||
var _2: Int64?
|
|
||||||
_2 = reader.readInt64()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.InputGame.inputGameID(id: _1!, accessHash: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_inputGameShortName(_ reader: BufferReader) -> InputGame? {
|
|
||||||
var _1: Api.InputUser?
|
|
||||||
if let signature = reader.readInt32() {
|
|
||||||
_1 = Api.parse(reader, signature: signature) as? Api.InputUser
|
|
||||||
}
|
|
||||||
var _2: String?
|
|
||||||
_2 = parseString(reader)
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.InputGame.inputGameShortName(botId: _1!, shortName: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public extension Api {
|
|
||||||
enum InputGeoPoint: TypeConstructorDescription {
|
|
||||||
case inputGeoPoint(flags: Int32, lat: Double, long: Double, accuracyRadius: Int32?)
|
|
||||||
case inputGeoPointEmpty
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .inputGeoPoint(let flags, let lat, let long, let accuracyRadius):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(1210199983)
|
|
||||||
}
|
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
|
||||||
serializeDouble(lat, buffer: buffer, boxed: false)
|
|
||||||
serializeDouble(long, buffer: buffer, boxed: false)
|
|
||||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(accuracyRadius!, buffer: buffer, boxed: false)}
|
|
||||||
break
|
|
||||||
case .inputGeoPointEmpty:
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-457104426)
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .inputGeoPoint(let flags, let lat, let long, let accuracyRadius):
|
|
||||||
return ("inputGeoPoint", [("flags", String(describing: flags)), ("lat", String(describing: lat)), ("long", String(describing: long)), ("accuracyRadius", String(describing: accuracyRadius))])
|
|
||||||
case .inputGeoPointEmpty:
|
|
||||||
return ("inputGeoPointEmpty", [])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_inputGeoPoint(_ reader: BufferReader) -> InputGeoPoint? {
|
|
||||||
var _1: Int32?
|
|
||||||
_1 = reader.readInt32()
|
|
||||||
var _2: Double?
|
|
||||||
_2 = reader.readDouble()
|
|
||||||
var _3: Double?
|
|
||||||
_3 = reader.readDouble()
|
|
||||||
var _4: Int32?
|
|
||||||
if Int(_1!) & Int(1 << 0) != 0 {_4 = reader.readInt32() }
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
|
|
||||||
if _c1 && _c2 && _c3 && _c4 {
|
|
||||||
return Api.InputGeoPoint.inputGeoPoint(flags: _1!, lat: _2!, long: _3!, accuracyRadius: _4)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_inputGeoPointEmpty(_ reader: BufferReader) -> InputGeoPoint? {
|
|
||||||
return Api.InputGeoPoint.inputGeoPointEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,129 @@
|
|||||||
|
public extension Api {
|
||||||
|
indirect enum InputGame: TypeConstructorDescription {
|
||||||
|
case inputGameID(id: Int64, accessHash: Int64)
|
||||||
|
case inputGameShortName(botId: Api.InputUser, shortName: String)
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .inputGameID(let id, let accessHash):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(53231223)
|
||||||
|
}
|
||||||
|
serializeInt64(id, buffer: buffer, boxed: false)
|
||||||
|
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .inputGameShortName(let botId, let shortName):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1020139510)
|
||||||
|
}
|
||||||
|
botId.serialize(buffer, true)
|
||||||
|
serializeString(shortName, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .inputGameID(let id, let accessHash):
|
||||||
|
return ("inputGameID", [("id", String(describing: id)), ("accessHash", String(describing: accessHash))])
|
||||||
|
case .inputGameShortName(let botId, let shortName):
|
||||||
|
return ("inputGameShortName", [("botId", String(describing: botId)), ("shortName", String(describing: shortName))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_inputGameID(_ reader: BufferReader) -> InputGame? {
|
||||||
|
var _1: Int64?
|
||||||
|
_1 = reader.readInt64()
|
||||||
|
var _2: Int64?
|
||||||
|
_2 = reader.readInt64()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.InputGame.inputGameID(id: _1!, accessHash: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_inputGameShortName(_ reader: BufferReader) -> InputGame? {
|
||||||
|
var _1: Api.InputUser?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_1 = Api.parse(reader, signature: signature) as? Api.InputUser
|
||||||
|
}
|
||||||
|
var _2: String?
|
||||||
|
_2 = parseString(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.InputGame.inputGameShortName(botId: _1!, shortName: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public extension Api {
|
||||||
|
enum InputGeoPoint: TypeConstructorDescription {
|
||||||
|
case inputGeoPoint(flags: Int32, lat: Double, long: Double, accuracyRadius: Int32?)
|
||||||
|
case inputGeoPointEmpty
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .inputGeoPoint(let flags, let lat, let long, let accuracyRadius):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(1210199983)
|
||||||
|
}
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
serializeDouble(lat, buffer: buffer, boxed: false)
|
||||||
|
serializeDouble(long, buffer: buffer, boxed: false)
|
||||||
|
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(accuracyRadius!, buffer: buffer, boxed: false)}
|
||||||
|
break
|
||||||
|
case .inputGeoPointEmpty:
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-457104426)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .inputGeoPoint(let flags, let lat, let long, let accuracyRadius):
|
||||||
|
return ("inputGeoPoint", [("flags", String(describing: flags)), ("lat", String(describing: lat)), ("long", String(describing: long)), ("accuracyRadius", String(describing: accuracyRadius))])
|
||||||
|
case .inputGeoPointEmpty:
|
||||||
|
return ("inputGeoPointEmpty", [])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_inputGeoPoint(_ reader: BufferReader) -> InputGeoPoint? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: Double?
|
||||||
|
_2 = reader.readDouble()
|
||||||
|
var _3: Double?
|
||||||
|
_3 = reader.readDouble()
|
||||||
|
var _4: Int32?
|
||||||
|
if Int(_1!) & Int(1 << 0) != 0 {_4 = reader.readInt32() }
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
|
||||||
|
if _c1 && _c2 && _c3 && _c4 {
|
||||||
|
return Api.InputGeoPoint.inputGeoPoint(flags: _1!, lat: _2!, long: _3!, accuracyRadius: _4)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_inputGeoPointEmpty(_ reader: BufferReader) -> InputGeoPoint? {
|
||||||
|
return Api.InputGeoPoint.inputGeoPointEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum InputGroupCall: TypeConstructorDescription {
|
enum InputGroupCall: TypeConstructorDescription {
|
||||||
case inputGroupCall(id: Int64, accessHash: Int64)
|
case inputGroupCall(id: Int64, accessHash: Int64)
|
||||||
@ -914,171 +1040,3 @@ public extension Api {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api {
|
|
||||||
indirect enum InputPeer: TypeConstructorDescription {
|
|
||||||
case inputPeerChannel(channelId: Int64, accessHash: Int64)
|
|
||||||
case inputPeerChannelFromMessage(peer: Api.InputPeer, msgId: Int32, channelId: Int64)
|
|
||||||
case inputPeerChat(chatId: Int64)
|
|
||||||
case inputPeerEmpty
|
|
||||||
case inputPeerSelf
|
|
||||||
case inputPeerUser(userId: Int64, accessHash: Int64)
|
|
||||||
case inputPeerUserFromMessage(peer: Api.InputPeer, msgId: Int32, userId: Int64)
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .inputPeerChannel(let channelId, let accessHash):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(666680316)
|
|
||||||
}
|
|
||||||
serializeInt64(channelId, buffer: buffer, boxed: false)
|
|
||||||
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .inputPeerChannelFromMessage(let peer, let msgId, let channelId):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-1121318848)
|
|
||||||
}
|
|
||||||
peer.serialize(buffer, true)
|
|
||||||
serializeInt32(msgId, buffer: buffer, boxed: false)
|
|
||||||
serializeInt64(channelId, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .inputPeerChat(let chatId):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(900291769)
|
|
||||||
}
|
|
||||||
serializeInt64(chatId, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .inputPeerEmpty:
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(2134579434)
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
case .inputPeerSelf:
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(2107670217)
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
case .inputPeerUser(let userId, let accessHash):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-571955892)
|
|
||||||
}
|
|
||||||
serializeInt64(userId, buffer: buffer, boxed: false)
|
|
||||||
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .inputPeerUserFromMessage(let peer, let msgId, let userId):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-1468331492)
|
|
||||||
}
|
|
||||||
peer.serialize(buffer, true)
|
|
||||||
serializeInt32(msgId, buffer: buffer, boxed: false)
|
|
||||||
serializeInt64(userId, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .inputPeerChannel(let channelId, let accessHash):
|
|
||||||
return ("inputPeerChannel", [("channelId", String(describing: channelId)), ("accessHash", String(describing: accessHash))])
|
|
||||||
case .inputPeerChannelFromMessage(let peer, let msgId, let channelId):
|
|
||||||
return ("inputPeerChannelFromMessage", [("peer", String(describing: peer)), ("msgId", String(describing: msgId)), ("channelId", String(describing: channelId))])
|
|
||||||
case .inputPeerChat(let chatId):
|
|
||||||
return ("inputPeerChat", [("chatId", String(describing: chatId))])
|
|
||||||
case .inputPeerEmpty:
|
|
||||||
return ("inputPeerEmpty", [])
|
|
||||||
case .inputPeerSelf:
|
|
||||||
return ("inputPeerSelf", [])
|
|
||||||
case .inputPeerUser(let userId, let accessHash):
|
|
||||||
return ("inputPeerUser", [("userId", String(describing: userId)), ("accessHash", String(describing: accessHash))])
|
|
||||||
case .inputPeerUserFromMessage(let peer, let msgId, let userId):
|
|
||||||
return ("inputPeerUserFromMessage", [("peer", String(describing: peer)), ("msgId", String(describing: msgId)), ("userId", String(describing: userId))])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_inputPeerChannel(_ reader: BufferReader) -> InputPeer? {
|
|
||||||
var _1: Int64?
|
|
||||||
_1 = reader.readInt64()
|
|
||||||
var _2: Int64?
|
|
||||||
_2 = reader.readInt64()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.InputPeer.inputPeerChannel(channelId: _1!, accessHash: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_inputPeerChannelFromMessage(_ reader: BufferReader) -> InputPeer? {
|
|
||||||
var _1: Api.InputPeer?
|
|
||||||
if let signature = reader.readInt32() {
|
|
||||||
_1 = Api.parse(reader, signature: signature) as? Api.InputPeer
|
|
||||||
}
|
|
||||||
var _2: Int32?
|
|
||||||
_2 = reader.readInt32()
|
|
||||||
var _3: Int64?
|
|
||||||
_3 = reader.readInt64()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
if _c1 && _c2 && _c3 {
|
|
||||||
return Api.InputPeer.inputPeerChannelFromMessage(peer: _1!, msgId: _2!, channelId: _3!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_inputPeerChat(_ reader: BufferReader) -> InputPeer? {
|
|
||||||
var _1: Int64?
|
|
||||||
_1 = reader.readInt64()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
if _c1 {
|
|
||||||
return Api.InputPeer.inputPeerChat(chatId: _1!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_inputPeerEmpty(_ reader: BufferReader) -> InputPeer? {
|
|
||||||
return Api.InputPeer.inputPeerEmpty
|
|
||||||
}
|
|
||||||
public static func parse_inputPeerSelf(_ reader: BufferReader) -> InputPeer? {
|
|
||||||
return Api.InputPeer.inputPeerSelf
|
|
||||||
}
|
|
||||||
public static func parse_inputPeerUser(_ reader: BufferReader) -> InputPeer? {
|
|
||||||
var _1: Int64?
|
|
||||||
_1 = reader.readInt64()
|
|
||||||
var _2: Int64?
|
|
||||||
_2 = reader.readInt64()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.InputPeer.inputPeerUser(userId: _1!, accessHash: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_inputPeerUserFromMessage(_ reader: BufferReader) -> InputPeer? {
|
|
||||||
var _1: Api.InputPeer?
|
|
||||||
if let signature = reader.readInt32() {
|
|
||||||
_1 = Api.parse(reader, signature: signature) as? Api.InputPeer
|
|
||||||
}
|
|
||||||
var _2: Int32?
|
|
||||||
_2 = reader.readInt32()
|
|
||||||
var _3: Int64?
|
|
||||||
_3 = reader.readInt64()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
if _c1 && _c2 && _c3 {
|
|
||||||
return Api.InputPeer.inputPeerUserFromMessage(peer: _1!, msgId: _2!, userId: _3!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,171 @@
|
|||||||
|
public extension Api {
|
||||||
|
indirect enum InputPeer: TypeConstructorDescription {
|
||||||
|
case inputPeerChannel(channelId: Int64, accessHash: Int64)
|
||||||
|
case inputPeerChannelFromMessage(peer: Api.InputPeer, msgId: Int32, channelId: Int64)
|
||||||
|
case inputPeerChat(chatId: Int64)
|
||||||
|
case inputPeerEmpty
|
||||||
|
case inputPeerSelf
|
||||||
|
case inputPeerUser(userId: Int64, accessHash: Int64)
|
||||||
|
case inputPeerUserFromMessage(peer: Api.InputPeer, msgId: Int32, userId: Int64)
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .inputPeerChannel(let channelId, let accessHash):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(666680316)
|
||||||
|
}
|
||||||
|
serializeInt64(channelId, buffer: buffer, boxed: false)
|
||||||
|
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .inputPeerChannelFromMessage(let peer, let msgId, let channelId):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1121318848)
|
||||||
|
}
|
||||||
|
peer.serialize(buffer, true)
|
||||||
|
serializeInt32(msgId, buffer: buffer, boxed: false)
|
||||||
|
serializeInt64(channelId, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .inputPeerChat(let chatId):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(900291769)
|
||||||
|
}
|
||||||
|
serializeInt64(chatId, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .inputPeerEmpty:
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(2134579434)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
case .inputPeerSelf:
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(2107670217)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
case .inputPeerUser(let userId, let accessHash):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-571955892)
|
||||||
|
}
|
||||||
|
serializeInt64(userId, buffer: buffer, boxed: false)
|
||||||
|
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .inputPeerUserFromMessage(let peer, let msgId, let userId):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1468331492)
|
||||||
|
}
|
||||||
|
peer.serialize(buffer, true)
|
||||||
|
serializeInt32(msgId, buffer: buffer, boxed: false)
|
||||||
|
serializeInt64(userId, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .inputPeerChannel(let channelId, let accessHash):
|
||||||
|
return ("inputPeerChannel", [("channelId", String(describing: channelId)), ("accessHash", String(describing: accessHash))])
|
||||||
|
case .inputPeerChannelFromMessage(let peer, let msgId, let channelId):
|
||||||
|
return ("inputPeerChannelFromMessage", [("peer", String(describing: peer)), ("msgId", String(describing: msgId)), ("channelId", String(describing: channelId))])
|
||||||
|
case .inputPeerChat(let chatId):
|
||||||
|
return ("inputPeerChat", [("chatId", String(describing: chatId))])
|
||||||
|
case .inputPeerEmpty:
|
||||||
|
return ("inputPeerEmpty", [])
|
||||||
|
case .inputPeerSelf:
|
||||||
|
return ("inputPeerSelf", [])
|
||||||
|
case .inputPeerUser(let userId, let accessHash):
|
||||||
|
return ("inputPeerUser", [("userId", String(describing: userId)), ("accessHash", String(describing: accessHash))])
|
||||||
|
case .inputPeerUserFromMessage(let peer, let msgId, let userId):
|
||||||
|
return ("inputPeerUserFromMessage", [("peer", String(describing: peer)), ("msgId", String(describing: msgId)), ("userId", String(describing: userId))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_inputPeerChannel(_ reader: BufferReader) -> InputPeer? {
|
||||||
|
var _1: Int64?
|
||||||
|
_1 = reader.readInt64()
|
||||||
|
var _2: Int64?
|
||||||
|
_2 = reader.readInt64()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.InputPeer.inputPeerChannel(channelId: _1!, accessHash: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_inputPeerChannelFromMessage(_ reader: BufferReader) -> InputPeer? {
|
||||||
|
var _1: Api.InputPeer?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_1 = Api.parse(reader, signature: signature) as? Api.InputPeer
|
||||||
|
}
|
||||||
|
var _2: Int32?
|
||||||
|
_2 = reader.readInt32()
|
||||||
|
var _3: Int64?
|
||||||
|
_3 = reader.readInt64()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
if _c1 && _c2 && _c3 {
|
||||||
|
return Api.InputPeer.inputPeerChannelFromMessage(peer: _1!, msgId: _2!, channelId: _3!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_inputPeerChat(_ reader: BufferReader) -> InputPeer? {
|
||||||
|
var _1: Int64?
|
||||||
|
_1 = reader.readInt64()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
if _c1 {
|
||||||
|
return Api.InputPeer.inputPeerChat(chatId: _1!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_inputPeerEmpty(_ reader: BufferReader) -> InputPeer? {
|
||||||
|
return Api.InputPeer.inputPeerEmpty
|
||||||
|
}
|
||||||
|
public static func parse_inputPeerSelf(_ reader: BufferReader) -> InputPeer? {
|
||||||
|
return Api.InputPeer.inputPeerSelf
|
||||||
|
}
|
||||||
|
public static func parse_inputPeerUser(_ reader: BufferReader) -> InputPeer? {
|
||||||
|
var _1: Int64?
|
||||||
|
_1 = reader.readInt64()
|
||||||
|
var _2: Int64?
|
||||||
|
_2 = reader.readInt64()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.InputPeer.inputPeerUser(userId: _1!, accessHash: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_inputPeerUserFromMessage(_ reader: BufferReader) -> InputPeer? {
|
||||||
|
var _1: Api.InputPeer?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_1 = Api.parse(reader, signature: signature) as? Api.InputPeer
|
||||||
|
}
|
||||||
|
var _2: Int32?
|
||||||
|
_2 = reader.readInt32()
|
||||||
|
var _3: Int64?
|
||||||
|
_3 = reader.readInt64()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
if _c1 && _c2 && _c3 {
|
||||||
|
return Api.InputPeer.inputPeerUserFromMessage(peer: _1!, msgId: _2!, userId: _3!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum InputPeerNotifySettings: TypeConstructorDescription {
|
enum InputPeerNotifySettings: TypeConstructorDescription {
|
||||||
case inputPeerNotifySettings(flags: Int32, showPreviews: Api.Bool?, silent: Api.Bool?, muteUntil: Int32?, sound: Api.NotificationSound?)
|
case inputPeerNotifySettings(flags: Int32, showPreviews: Api.Bool?, silent: Api.Bool?, muteUntil: Int32?, sound: Api.NotificationSound?)
|
||||||
@ -672,155 +840,3 @@ public extension Api {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api {
|
|
||||||
enum InputStickerSet: TypeConstructorDescription {
|
|
||||||
case inputStickerSetAnimatedEmoji
|
|
||||||
case inputStickerSetAnimatedEmojiAnimations
|
|
||||||
case inputStickerSetDice(emoticon: String)
|
|
||||||
case inputStickerSetEmojiDefaultStatuses
|
|
||||||
case inputStickerSetEmojiGenericAnimations
|
|
||||||
case inputStickerSetEmpty
|
|
||||||
case inputStickerSetID(id: Int64, accessHash: Int64)
|
|
||||||
case inputStickerSetPremiumGifts
|
|
||||||
case inputStickerSetShortName(shortName: String)
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .inputStickerSetAnimatedEmoji:
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(42402760)
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
case .inputStickerSetAnimatedEmojiAnimations:
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(215889721)
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
case .inputStickerSetDice(let emoticon):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-427863538)
|
|
||||||
}
|
|
||||||
serializeString(emoticon, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .inputStickerSetEmojiDefaultStatuses:
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(701560302)
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
case .inputStickerSetEmojiGenericAnimations:
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(80008398)
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
case .inputStickerSetEmpty:
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-4838507)
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
case .inputStickerSetID(let id, let accessHash):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-1645763991)
|
|
||||||
}
|
|
||||||
serializeInt64(id, buffer: buffer, boxed: false)
|
|
||||||
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .inputStickerSetPremiumGifts:
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-930399486)
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
case .inputStickerSetShortName(let shortName):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-2044933984)
|
|
||||||
}
|
|
||||||
serializeString(shortName, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .inputStickerSetAnimatedEmoji:
|
|
||||||
return ("inputStickerSetAnimatedEmoji", [])
|
|
||||||
case .inputStickerSetAnimatedEmojiAnimations:
|
|
||||||
return ("inputStickerSetAnimatedEmojiAnimations", [])
|
|
||||||
case .inputStickerSetDice(let emoticon):
|
|
||||||
return ("inputStickerSetDice", [("emoticon", String(describing: emoticon))])
|
|
||||||
case .inputStickerSetEmojiDefaultStatuses:
|
|
||||||
return ("inputStickerSetEmojiDefaultStatuses", [])
|
|
||||||
case .inputStickerSetEmojiGenericAnimations:
|
|
||||||
return ("inputStickerSetEmojiGenericAnimations", [])
|
|
||||||
case .inputStickerSetEmpty:
|
|
||||||
return ("inputStickerSetEmpty", [])
|
|
||||||
case .inputStickerSetID(let id, let accessHash):
|
|
||||||
return ("inputStickerSetID", [("id", String(describing: id)), ("accessHash", String(describing: accessHash))])
|
|
||||||
case .inputStickerSetPremiumGifts:
|
|
||||||
return ("inputStickerSetPremiumGifts", [])
|
|
||||||
case .inputStickerSetShortName(let shortName):
|
|
||||||
return ("inputStickerSetShortName", [("shortName", String(describing: shortName))])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_inputStickerSetAnimatedEmoji(_ reader: BufferReader) -> InputStickerSet? {
|
|
||||||
return Api.InputStickerSet.inputStickerSetAnimatedEmoji
|
|
||||||
}
|
|
||||||
public static func parse_inputStickerSetAnimatedEmojiAnimations(_ reader: BufferReader) -> InputStickerSet? {
|
|
||||||
return Api.InputStickerSet.inputStickerSetAnimatedEmojiAnimations
|
|
||||||
}
|
|
||||||
public static func parse_inputStickerSetDice(_ reader: BufferReader) -> InputStickerSet? {
|
|
||||||
var _1: String?
|
|
||||||
_1 = parseString(reader)
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
if _c1 {
|
|
||||||
return Api.InputStickerSet.inputStickerSetDice(emoticon: _1!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_inputStickerSetEmojiDefaultStatuses(_ reader: BufferReader) -> InputStickerSet? {
|
|
||||||
return Api.InputStickerSet.inputStickerSetEmojiDefaultStatuses
|
|
||||||
}
|
|
||||||
public static func parse_inputStickerSetEmojiGenericAnimations(_ reader: BufferReader) -> InputStickerSet? {
|
|
||||||
return Api.InputStickerSet.inputStickerSetEmojiGenericAnimations
|
|
||||||
}
|
|
||||||
public static func parse_inputStickerSetEmpty(_ reader: BufferReader) -> InputStickerSet? {
|
|
||||||
return Api.InputStickerSet.inputStickerSetEmpty
|
|
||||||
}
|
|
||||||
public static func parse_inputStickerSetID(_ reader: BufferReader) -> InputStickerSet? {
|
|
||||||
var _1: Int64?
|
|
||||||
_1 = reader.readInt64()
|
|
||||||
var _2: Int64?
|
|
||||||
_2 = reader.readInt64()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.InputStickerSet.inputStickerSetID(id: _1!, accessHash: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_inputStickerSetPremiumGifts(_ reader: BufferReader) -> InputStickerSet? {
|
|
||||||
return Api.InputStickerSet.inputStickerSetPremiumGifts
|
|
||||||
}
|
|
||||||
public static func parse_inputStickerSetShortName(_ reader: BufferReader) -> InputStickerSet? {
|
|
||||||
var _1: String?
|
|
||||||
_1 = parseString(reader)
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
if _c1 {
|
|
||||||
return Api.InputStickerSet.inputStickerSetShortName(shortName: _1!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -124,6 +124,9 @@ func parseTelegramGroupOrChannel(chat: Api.Chat) -> Peer? {
|
|||||||
if (flags & Int32(1 << 29)) != 0 {
|
if (flags & Int32(1 << 29)) != 0 {
|
||||||
channelFlags.insert(.requestToJoin)
|
channelFlags.insert(.requestToJoin)
|
||||||
}
|
}
|
||||||
|
if (flags & Int32(1 << 30)) != 0 {
|
||||||
|
channelFlags.insert(.isForum)
|
||||||
|
}
|
||||||
|
|
||||||
let restrictionInfo: PeerAccessRestrictionInfo?
|
let restrictionInfo: PeerAccessRestrictionInfo?
|
||||||
if let restrictionReason = restrictionReason {
|
if let restrictionReason = restrictionReason {
|
||||||
|
@ -201,7 +201,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch action {
|
switch action {
|
||||||
case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp, .messageActionGroupCall, .messageActionSetMessagesTTL, .messageActionGroupCallScheduled, .messageActionSetChatTheme, .messageActionChatJoinedByRequest, .messageActionWebViewDataSent, .messageActionWebViewDataSentMe, .messageActionGiftPremium:
|
case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp, .messageActionGroupCall, .messageActionSetMessagesTTL, .messageActionGroupCallScheduled, .messageActionSetChatTheme, .messageActionChatJoinedByRequest, .messageActionWebViewDataSent, .messageActionWebViewDataSentMe, .messageActionGiftPremium, .messageActionTopicCreate, .messageActionTopicEditTitle, .messageActionTopicEditIcon:
|
||||||
break
|
break
|
||||||
case let .messageActionChannelMigrateFrom(_, chatId):
|
case let .messageActionChannelMigrateFrom(_, chatId):
|
||||||
result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatId)))
|
result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatId)))
|
||||||
@ -632,6 +632,10 @@ extension StoreMessage {
|
|||||||
if (flags & (1 << 26)) != 0 {
|
if (flags & (1 << 26)) != 0 {
|
||||||
storeFlags.insert(.CopyProtected)
|
storeFlags.insert(.CopyProtected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & (1 << 27)) != 0 {
|
||||||
|
storeFlags.insert(.IsForumTopic)
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & (1 << 4)) != 0 || (flags & (1 << 13)) != 0 {
|
if (flags & (1 << 4)) != 0 || (flags & (1 << 13)) != 0 {
|
||||||
var notificationFlags: NotificationInfoMessageAttributeFlags = []
|
var notificationFlags: NotificationInfoMessageAttributeFlags = []
|
||||||
@ -723,6 +727,10 @@ extension StoreMessage {
|
|||||||
if (flags & (1 << 26)) != 0 {
|
if (flags & (1 << 26)) != 0 {
|
||||||
storeFlags.insert(.CopyProtected)
|
storeFlags.insert(.CopyProtected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & (1 << 27)) != 0 {
|
||||||
|
storeFlags.insert(.IsForumTopic)
|
||||||
|
}
|
||||||
|
|
||||||
self.init(id: MessageId(peerId: peerId, namespace: namespace, id: id), globallyUniqueId: nil, groupingKey: nil, threadId: threadId, timestamp: date, flags: storeFlags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: attributes, media: media)
|
self.init(id: MessageId(peerId: peerId, namespace: namespace, id: id), globallyUniqueId: nil, groupingKey: nil, threadId: threadId, timestamp: date, flags: storeFlags, tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: attributes, media: media)
|
||||||
}
|
}
|
||||||
|
@ -5,88 +5,94 @@ import TelegramApi
|
|||||||
|
|
||||||
func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMediaAction? {
|
func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMediaAction? {
|
||||||
switch action {
|
switch action {
|
||||||
case let .messageActionChannelCreate(title):
|
case let .messageActionChannelCreate(title):
|
||||||
return TelegramMediaAction(action: .groupCreated(title: title))
|
return TelegramMediaAction(action: .groupCreated(title: title))
|
||||||
case let .messageActionChannelMigrateFrom(title, chatId):
|
case let .messageActionChannelMigrateFrom(title, chatId):
|
||||||
return TelegramMediaAction(action: .channelMigratedFromGroup(title: title, groupId: PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatId))))
|
return TelegramMediaAction(action: .channelMigratedFromGroup(title: title, groupId: PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatId))))
|
||||||
case let .messageActionChatAddUser(users):
|
case let .messageActionChatAddUser(users):
|
||||||
return TelegramMediaAction(action: .addedMembers(peerIds: users.map({ PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value($0)) })))
|
return TelegramMediaAction(action: .addedMembers(peerIds: users.map({ PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value($0)) })))
|
||||||
case let .messageActionChatCreate(title, _):
|
case let .messageActionChatCreate(title, _):
|
||||||
return TelegramMediaAction(action: .groupCreated(title: title))
|
return TelegramMediaAction(action: .groupCreated(title: title))
|
||||||
case .messageActionChatDeletePhoto:
|
case .messageActionChatDeletePhoto:
|
||||||
return TelegramMediaAction(action: .photoUpdated(image: nil))
|
return TelegramMediaAction(action: .photoUpdated(image: nil))
|
||||||
case let .messageActionChatDeleteUser(userId):
|
case let .messageActionChatDeleteUser(userId):
|
||||||
return TelegramMediaAction(action: .removedMembers(peerIds: [PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))]))
|
return TelegramMediaAction(action: .removedMembers(peerIds: [PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))]))
|
||||||
case let .messageActionChatEditPhoto(photo):
|
case let .messageActionChatEditPhoto(photo):
|
||||||
return TelegramMediaAction(action: .photoUpdated(image: telegramMediaImageFromApiPhoto(photo)))
|
return TelegramMediaAction(action: .photoUpdated(image: telegramMediaImageFromApiPhoto(photo)))
|
||||||
case let .messageActionChatEditTitle(title):
|
case let .messageActionChatEditTitle(title):
|
||||||
return TelegramMediaAction(action: .titleUpdated(title: title))
|
return TelegramMediaAction(action: .titleUpdated(title: title))
|
||||||
case let .messageActionChatJoinedByLink(inviterId):
|
case let .messageActionChatJoinedByLink(inviterId):
|
||||||
return TelegramMediaAction(action: .joinedByLink(inviter: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(inviterId))))
|
return TelegramMediaAction(action: .joinedByLink(inviter: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(inviterId))))
|
||||||
case let .messageActionChatMigrateTo(channelId):
|
case let .messageActionChatMigrateTo(channelId):
|
||||||
return TelegramMediaAction(action: .groupMigratedToChannel(channelId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))))
|
return TelegramMediaAction(action: .groupMigratedToChannel(channelId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))))
|
||||||
case .messageActionHistoryClear:
|
case .messageActionHistoryClear:
|
||||||
return TelegramMediaAction(action: .historyCleared)
|
return TelegramMediaAction(action: .historyCleared)
|
||||||
case .messageActionPinMessage:
|
case .messageActionPinMessage:
|
||||||
return TelegramMediaAction(action: .pinnedMessageUpdated)
|
return TelegramMediaAction(action: .pinnedMessageUpdated)
|
||||||
case let .messageActionGameScore(gameId, score):
|
case let .messageActionGameScore(gameId, score):
|
||||||
return TelegramMediaAction(action: .gameScore(gameId: gameId, score: score))
|
return TelegramMediaAction(action: .gameScore(gameId: gameId, score: score))
|
||||||
case let .messageActionPhoneCall(flags, callId, reason, duration):
|
case let .messageActionPhoneCall(flags, callId, reason, duration):
|
||||||
var discardReason: PhoneCallDiscardReason?
|
var discardReason: PhoneCallDiscardReason?
|
||||||
if let reason = reason {
|
if let reason = reason {
|
||||||
discardReason = PhoneCallDiscardReason(apiReason: reason)
|
discardReason = PhoneCallDiscardReason(apiReason: reason)
|
||||||
}
|
}
|
||||||
let isVideo = (flags & (1 << 2)) != 0
|
let isVideo = (flags & (1 << 2)) != 0
|
||||||
return TelegramMediaAction(action: .phoneCall(callId: callId, discardReason: discardReason, duration: duration, isVideo: isVideo))
|
return TelegramMediaAction(action: .phoneCall(callId: callId, discardReason: discardReason, duration: duration, isVideo: isVideo))
|
||||||
case .messageActionEmpty:
|
case .messageActionEmpty:
|
||||||
return nil
|
return nil
|
||||||
case let .messageActionPaymentSent(flags, currency, totalAmount, invoiceSlug):
|
case let .messageActionPaymentSent(flags, currency, totalAmount, invoiceSlug):
|
||||||
let isRecurringInit = (flags & (1 << 2)) != 0
|
let isRecurringInit = (flags & (1 << 2)) != 0
|
||||||
let isRecurringUsed = (flags & (1 << 3)) != 0
|
let isRecurringUsed = (flags & (1 << 3)) != 0
|
||||||
return TelegramMediaAction(action: .paymentSent(currency: currency, totalAmount: totalAmount, invoiceSlug: invoiceSlug, isRecurringInit: isRecurringInit, isRecurringUsed: isRecurringUsed))
|
return TelegramMediaAction(action: .paymentSent(currency: currency, totalAmount: totalAmount, invoiceSlug: invoiceSlug, isRecurringInit: isRecurringInit, isRecurringUsed: isRecurringUsed))
|
||||||
case .messageActionPaymentSentMe:
|
case .messageActionPaymentSentMe:
|
||||||
return nil
|
return nil
|
||||||
case .messageActionScreenshotTaken:
|
case .messageActionScreenshotTaken:
|
||||||
return TelegramMediaAction(action: .historyScreenshot)
|
return TelegramMediaAction(action: .historyScreenshot)
|
||||||
case let .messageActionCustomAction(message):
|
case let .messageActionCustomAction(message):
|
||||||
return TelegramMediaAction(action: .customText(text: message, entities: []))
|
return TelegramMediaAction(action: .customText(text: message, entities: []))
|
||||||
case let .messageActionBotAllowed(domain):
|
case let .messageActionBotAllowed(domain):
|
||||||
return TelegramMediaAction(action: .botDomainAccessGranted(domain: domain))
|
return TelegramMediaAction(action: .botDomainAccessGranted(domain: domain))
|
||||||
case .messageActionSecureValuesSentMe:
|
case .messageActionSecureValuesSentMe:
|
||||||
return nil
|
return nil
|
||||||
case let .messageActionSecureValuesSent(types):
|
case let .messageActionSecureValuesSent(types):
|
||||||
return TelegramMediaAction(action: .botSentSecureValues(types: types.map(SentSecureValueType.init)))
|
return TelegramMediaAction(action: .botSentSecureValues(types: types.map(SentSecureValueType.init)))
|
||||||
case .messageActionContactSignUp:
|
case .messageActionContactSignUp:
|
||||||
return TelegramMediaAction(action: .peerJoined)
|
return TelegramMediaAction(action: .peerJoined)
|
||||||
case let .messageActionGeoProximityReached(fromId, toId, distance):
|
case let .messageActionGeoProximityReached(fromId, toId, distance):
|
||||||
return TelegramMediaAction(action: .geoProximityReached(from: fromId.peerId, to: toId.peerId, distance: distance))
|
return TelegramMediaAction(action: .geoProximityReached(from: fromId.peerId, to: toId.peerId, distance: distance))
|
||||||
case let .messageActionGroupCall(_, call, duration):
|
case let .messageActionGroupCall(_, call, duration):
|
||||||
switch call {
|
switch call {
|
||||||
case let .inputGroupCall(id, accessHash):
|
case let .inputGroupCall(id, accessHash):
|
||||||
return TelegramMediaAction(action: .groupPhoneCall(callId: id, accessHash: accessHash, scheduleDate: nil, duration: duration))
|
return TelegramMediaAction(action: .groupPhoneCall(callId: id, accessHash: accessHash, scheduleDate: nil, duration: duration))
|
||||||
}
|
}
|
||||||
case let .messageActionInviteToGroupCall(call, userIds):
|
case let .messageActionInviteToGroupCall(call, userIds):
|
||||||
switch call {
|
switch call {
|
||||||
case let .inputGroupCall(id, accessHash):
|
case let .inputGroupCall(id, accessHash):
|
||||||
return TelegramMediaAction(action: .inviteToGroupPhoneCall(callId: id, accessHash: accessHash, peerIds: userIds.map { userId in
|
return TelegramMediaAction(action: .inviteToGroupPhoneCall(callId: id, accessHash: accessHash, peerIds: userIds.map { userId in
|
||||||
PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
case let .messageActionSetMessagesTTL(period):
|
case let .messageActionSetMessagesTTL(period):
|
||||||
return TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(period))
|
return TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(period))
|
||||||
case let .messageActionGroupCallScheduled(call, scheduleDate):
|
case let .messageActionGroupCallScheduled(call, scheduleDate):
|
||||||
switch call {
|
switch call {
|
||||||
case let .inputGroupCall(id, accessHash):
|
case let .inputGroupCall(id, accessHash):
|
||||||
return TelegramMediaAction(action: .groupPhoneCall(callId: id, accessHash: accessHash, scheduleDate: scheduleDate, duration: nil))
|
return TelegramMediaAction(action: .groupPhoneCall(callId: id, accessHash: accessHash, scheduleDate: scheduleDate, duration: nil))
|
||||||
}
|
}
|
||||||
case let .messageActionSetChatTheme(emoji):
|
case let .messageActionSetChatTheme(emoji):
|
||||||
return TelegramMediaAction(action: .setChatTheme(emoji: emoji))
|
return TelegramMediaAction(action: .setChatTheme(emoji: emoji))
|
||||||
case .messageActionChatJoinedByRequest:
|
case .messageActionChatJoinedByRequest:
|
||||||
return TelegramMediaAction(action: .joinedByRequest)
|
return TelegramMediaAction(action: .joinedByRequest)
|
||||||
case let .messageActionWebViewDataSentMe(text, _), let .messageActionWebViewDataSent(text):
|
case let .messageActionWebViewDataSentMe(text, _), let .messageActionWebViewDataSent(text):
|
||||||
return TelegramMediaAction(action: .webViewData(text))
|
return TelegramMediaAction(action: .webViewData(text))
|
||||||
case let .messageActionGiftPremium(currency, amount, months):
|
case let .messageActionGiftPremium(currency, amount, months):
|
||||||
return TelegramMediaAction(action: .giftPremium(currency: currency, amount: amount, months: months))
|
return TelegramMediaAction(action: .giftPremium(currency: currency, amount: amount, months: months))
|
||||||
|
case let .messageActionTopicCreate(_, title, iconEmojiId):
|
||||||
|
return TelegramMediaAction(action: .topicCreated(title: title, iconFileId: iconEmojiId))
|
||||||
|
case let .messageActionTopicEditTitle(title):
|
||||||
|
return TelegramMediaAction(action: .topicEditTitle(title: title))
|
||||||
|
case let .messageActionTopicEditIcon(fileId):
|
||||||
|
return TelegramMediaAction(action: .topicEditIcon(fileId: fileId == 0 ? nil : fileId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
319
submodules/TelegramCore/Sources/ForumChannels.swift
Normal file
319
submodules/TelegramCore/Sources/ForumChannels.swift
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
import Foundation
|
||||||
|
import SwiftSignalKit
|
||||||
|
import Postbox
|
||||||
|
import TelegramApi
|
||||||
|
|
||||||
|
public final class EngineMessageHistoryThreads {
|
||||||
|
public final class Info: Equatable, Codable {
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case title
|
||||||
|
case icon
|
||||||
|
}
|
||||||
|
|
||||||
|
public let title: String
|
||||||
|
public let icon: Int64?
|
||||||
|
|
||||||
|
public init(
|
||||||
|
title: String,
|
||||||
|
icon: Int64?
|
||||||
|
) {
|
||||||
|
self.title = title
|
||||||
|
self.icon = icon
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
self.title = try container.decode(String.self, forKey: .title)
|
||||||
|
self.icon = try container.decodeIfPresent(Int64.self, forKey: .icon)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
try container.encode(self.title, forKey: .title)
|
||||||
|
try container.encodeIfPresent(self.icon, forKey: .icon)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: Info, rhs: Info) -> Bool {
|
||||||
|
if lhs.title != rhs.title {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.icon != rhs.icon {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func _internal_setChannelForumMode(account: Account, peerId: PeerId, isForum: Bool) -> Signal<Never, NoError> {
|
||||||
|
return account.postbox.transaction { transaction -> Api.InputChannel? in
|
||||||
|
return transaction.getPeer(peerId).flatMap(apiInputChannel)
|
||||||
|
}
|
||||||
|
|> mapToSignal { inputChannel -> Signal<Never, NoError> in
|
||||||
|
guard let inputChannel = inputChannel else {
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
return account.network.request(Api.functions.channels.toggleForum(channel: inputChannel, enabled: isForum ? .boolTrue : .boolFalse))
|
||||||
|
|> map(Optional.init)
|
||||||
|
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
|> mapToSignal { result -> Signal<Never, NoError> in
|
||||||
|
guard let result = result else {
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
account.stateManager.addUpdates(result)
|
||||||
|
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum LoadMessageHistoryThreadsError {
|
||||||
|
case generic
|
||||||
|
}
|
||||||
|
|
||||||
|
func _internal_loadMessageHistoryThreads(account: Account, peerId: PeerId) -> Signal<Never, LoadMessageHistoryThreadsError> {
|
||||||
|
let signal: Signal<Never, LoadMessageHistoryThreadsError> = account.postbox.transaction { transaction -> Api.InputChannel? in
|
||||||
|
return transaction.getPeer(peerId).flatMap(apiInputChannel)
|
||||||
|
}
|
||||||
|
|> castError(LoadMessageHistoryThreadsError.self)
|
||||||
|
|> mapToSignal { inputChannel -> Signal<Never, LoadMessageHistoryThreadsError> in
|
||||||
|
guard let inputChannel = inputChannel else {
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
|
let signal: Signal<Never, LoadMessageHistoryThreadsError> = account.network.request(Api.functions.channels.getForumTopics(
|
||||||
|
flags: 0,
|
||||||
|
channel: inputChannel,
|
||||||
|
q: nil,
|
||||||
|
offsetDate: 0,
|
||||||
|
offsetId: 0,
|
||||||
|
offsetTopic: 0,
|
||||||
|
limit: 100
|
||||||
|
))
|
||||||
|
|> mapError { _ -> LoadMessageHistoryThreadsError in
|
||||||
|
return .generic
|
||||||
|
}
|
||||||
|
|> mapToSignal { result -> Signal<Never, LoadMessageHistoryThreadsError> in
|
||||||
|
return account.postbox.transaction { transaction -> Void in
|
||||||
|
switch result {
|
||||||
|
case let .forumTopics(flags, count, topics, messages, chats, users, pts):
|
||||||
|
var peers: [Peer] = []
|
||||||
|
var peerPresences: [PeerId: Api.User] = [:]
|
||||||
|
for chat in chats {
|
||||||
|
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
|
peers.append(groupOrChannel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for user in users {
|
||||||
|
let telegramUser = TelegramUser(user: user)
|
||||||
|
peers.append(telegramUser)
|
||||||
|
peerPresences[telegramUser.id] = user
|
||||||
|
}
|
||||||
|
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
|
||||||
|
return updated
|
||||||
|
})
|
||||||
|
|
||||||
|
updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences)
|
||||||
|
|
||||||
|
let _ = transaction.addMessages(messages.compactMap { message -> StoreMessage? in
|
||||||
|
return StoreMessage(apiMessage: message)
|
||||||
|
}, location: .Random)
|
||||||
|
|
||||||
|
let _ = flags
|
||||||
|
let _ = count
|
||||||
|
let _ = topics
|
||||||
|
let _ = messages
|
||||||
|
let _ = chats
|
||||||
|
let _ = users
|
||||||
|
let _ = pts
|
||||||
|
|
||||||
|
for topic in topics {
|
||||||
|
switch topic {
|
||||||
|
case let .forumTopic(_, id, _, title, iconEmojiId, _, _, _, _):
|
||||||
|
guard let info = CodableEntry(EngineMessageHistoryThreads.Info(title: title, icon: iconEmojiId)) else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: Int64(id), info: info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> castError(LoadMessageHistoryThreadsError.self)
|
||||||
|
|> ignoreValues
|
||||||
|
}
|
||||||
|
return signal
|
||||||
|
}
|
||||||
|
|
||||||
|
return signal
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class ForumChannelTopics {
|
||||||
|
private final class Impl {
|
||||||
|
private let queue: Queue
|
||||||
|
|
||||||
|
private let account: Account
|
||||||
|
private let peerId: PeerId
|
||||||
|
|
||||||
|
private let statePromise = Promise<State>()
|
||||||
|
var state: Signal<State, NoError> {
|
||||||
|
return self.statePromise.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
private let loadMoreDisposable = MetaDisposable()
|
||||||
|
private let createTopicDisposable = MetaDisposable()
|
||||||
|
|
||||||
|
init(queue: Queue, account: Account, peerId: PeerId) {
|
||||||
|
self.queue = queue
|
||||||
|
self.account = account
|
||||||
|
self.peerId = peerId
|
||||||
|
|
||||||
|
let _ = _internal_loadMessageHistoryThreads(account: self.account, peerId: peerId).start()
|
||||||
|
|
||||||
|
let viewKey: PostboxViewKey = .messageHistoryThreadIndex(id: self.peerId)
|
||||||
|
self.statePromise.set(self.account.postbox.combinedView(keys: [viewKey])
|
||||||
|
|> map { views -> State in
|
||||||
|
guard let view = views.views[viewKey] as? MessageHistoryThreadIndexView else {
|
||||||
|
preconditionFailure()
|
||||||
|
}
|
||||||
|
return State(items: view.items.compactMap { item -> ForumChannelTopics.Item? in
|
||||||
|
guard let info = item.info.get(EngineMessageHistoryThreads.Info.self) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ForumChannelTopics.Item(
|
||||||
|
id: item.id,
|
||||||
|
info: info,
|
||||||
|
index: item.index,
|
||||||
|
topMessage: item.topMessage.flatMap(EngineMessage.init)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
assert(self.queue.isCurrent())
|
||||||
|
|
||||||
|
self.loadMoreDisposable.dispose()
|
||||||
|
self.createTopicDisposable.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTopic(title: String) {
|
||||||
|
let peerId = self.peerId
|
||||||
|
let account = self.account
|
||||||
|
let signal: Signal<Int32?, NoError> = self.account.postbox.transaction { transaction -> (Api.InputChannel?, Int64?) in
|
||||||
|
var fileId: Int64? = nil
|
||||||
|
|
||||||
|
var filteredFiles: [TelegramMediaFile] = []
|
||||||
|
for featuredEmojiPack in transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudFeaturedEmojiPacks) {
|
||||||
|
guard let featuredEmojiPack = featuredEmojiPack.contents.get(FeaturedStickerPackItem.self) else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for item in featuredEmojiPack.topItems {
|
||||||
|
for attribute in item.file.attributes {
|
||||||
|
switch attribute {
|
||||||
|
case .CustomEmoji:
|
||||||
|
filteredFiles.append(item.file)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileId = filteredFiles.randomElement()?.fileId.id
|
||||||
|
|
||||||
|
return (transaction.getPeer(peerId).flatMap(apiInputChannel), fileId)
|
||||||
|
}
|
||||||
|
|> mapToSignal { inputChannel, fileId -> Signal<Int32?, NoError> in
|
||||||
|
guard let inputChannel = inputChannel else {
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
var flags: Int32 = 0
|
||||||
|
if fileId != nil {
|
||||||
|
flags |= (1 << 3)
|
||||||
|
}
|
||||||
|
return account.network.request(Api.functions.channels.createForumTopic(
|
||||||
|
flags: flags,
|
||||||
|
channel: inputChannel,
|
||||||
|
title: title,
|
||||||
|
iconEmojiId: fileId,
|
||||||
|
randomId: Int64.random(in: Int64.min ..< Int64.max),
|
||||||
|
sendAs: nil
|
||||||
|
))
|
||||||
|
|> map(Optional.init)
|
||||||
|
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
|> mapToSignal { result -> Signal<Int32?, NoError> in
|
||||||
|
guard let result = result else {
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
account.stateManager.addUpdates(result)
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.createTopicDisposable.set((signal |> deliverOnMainQueue).start(next: { [weak self] _ in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let _ = _internal_loadMessageHistoryThreads(account: strongSelf.account, peerId: strongSelf.peerId).start()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Item: Equatable {
|
||||||
|
public var id: Int64
|
||||||
|
public var info: EngineMessageHistoryThreads.Info
|
||||||
|
public var index: MessageIndex
|
||||||
|
public var topMessage: EngineMessage?
|
||||||
|
|
||||||
|
init(
|
||||||
|
id: Int64,
|
||||||
|
info: EngineMessageHistoryThreads.Info,
|
||||||
|
index: MessageIndex,
|
||||||
|
topMessage: EngineMessage?
|
||||||
|
) {
|
||||||
|
self.id = id
|
||||||
|
self.info = info
|
||||||
|
self.index = index
|
||||||
|
self.topMessage = topMessage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct State: Equatable {
|
||||||
|
public var items: [Item]
|
||||||
|
|
||||||
|
init(items: [Item]) {
|
||||||
|
self.items = items
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private let queue: Queue
|
||||||
|
private let impl: QueueLocalObject<Impl>
|
||||||
|
|
||||||
|
public var state: Signal<State, NoError> {
|
||||||
|
return Signal { subscriber in
|
||||||
|
let disposable = MetaDisposable()
|
||||||
|
self.impl.with { impl in
|
||||||
|
disposable.set(impl.state.start(next: { value in
|
||||||
|
subscriber.putNext(value)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
return disposable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(account: Account, peerId: PeerId) {
|
||||||
|
let queue = Queue()
|
||||||
|
self.queue = queue
|
||||||
|
self.impl = QueueLocalObject(queue: queue, generate: {
|
||||||
|
return Impl(queue: queue, account: account, peerId: peerId)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public func createTopic(title: String) {
|
||||||
|
self.impl.with { impl in
|
||||||
|
impl.createTopic(title: title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
|
|||||||
|
|
||||||
public class Serialization: NSObject, MTSerialization {
|
public class Serialization: NSObject, MTSerialization {
|
||||||
public func currentLayer() -> UInt {
|
public func currentLayer() -> UInt {
|
||||||
return 147
|
return 148
|
||||||
}
|
}
|
||||||
|
|
||||||
public func parseMessage(_ data: Data!) -> Any! {
|
public func parseMessage(_ data: Data!) -> Any! {
|
||||||
|
@ -147,6 +147,7 @@ public struct TelegramChannelFlags: OptionSet {
|
|||||||
public static let copyProtectionEnabled = TelegramChannelFlags(rawValue: 1 << 8)
|
public static let copyProtectionEnabled = TelegramChannelFlags(rawValue: 1 << 8)
|
||||||
public static let joinToSend = TelegramChannelFlags(rawValue: 1 << 9)
|
public static let joinToSend = TelegramChannelFlags(rawValue: 1 << 9)
|
||||||
public static let requestToJoin = TelegramChannelFlags(rawValue: 1 << 10)
|
public static let requestToJoin = TelegramChannelFlags(rawValue: 1 << 10)
|
||||||
|
public static let isForum = TelegramChannelFlags(rawValue: 1 << 11)
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class TelegramChannel: Peer, Equatable {
|
public final class TelegramChannel: Peer, Equatable {
|
||||||
|
@ -52,226 +52,253 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
|||||||
case joinedByRequest
|
case joinedByRequest
|
||||||
case webViewData(String)
|
case webViewData(String)
|
||||||
case giftPremium(currency: String, amount: Int64, months: Int32)
|
case giftPremium(currency: String, amount: Int64, months: Int32)
|
||||||
|
case topicCreated(title: String, iconFileId: Int64?)
|
||||||
|
case topicEditTitle(title: String)
|
||||||
|
case topicEditIcon(fileId: Int64?)
|
||||||
|
|
||||||
public init(decoder: PostboxDecoder) {
|
public init(decoder: PostboxDecoder) {
|
||||||
let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0)
|
let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0)
|
||||||
switch rawValue {
|
switch rawValue {
|
||||||
case 1:
|
case 1:
|
||||||
self = .groupCreated(title: decoder.decodeStringForKey("title", orElse: ""))
|
self = .groupCreated(title: decoder.decodeStringForKey("title", orElse: ""))
|
||||||
case 2:
|
case 2:
|
||||||
self = .addedMembers(peerIds: PeerId.decodeArrayFromBuffer(decoder.decodeBytesForKeyNoCopy("peerIds")!))
|
self = .addedMembers(peerIds: PeerId.decodeArrayFromBuffer(decoder.decodeBytesForKeyNoCopy("peerIds")!))
|
||||||
case 3:
|
case 3:
|
||||||
self = .removedMembers(peerIds: PeerId.decodeArrayFromBuffer(decoder.decodeBytesForKeyNoCopy("peerIds")!))
|
self = .removedMembers(peerIds: PeerId.decodeArrayFromBuffer(decoder.decodeBytesForKeyNoCopy("peerIds")!))
|
||||||
case 4:
|
case 4:
|
||||||
self = .photoUpdated(image: decoder.decodeObjectForKey("image") as? TelegramMediaImage)
|
self = .photoUpdated(image: decoder.decodeObjectForKey("image") as? TelegramMediaImage)
|
||||||
case 5:
|
case 5:
|
||||||
self = .titleUpdated(title: decoder.decodeStringForKey("title", orElse: ""))
|
self = .titleUpdated(title: decoder.decodeStringForKey("title", orElse: ""))
|
||||||
case 6:
|
case 6:
|
||||||
self = .pinnedMessageUpdated
|
self = .pinnedMessageUpdated
|
||||||
case 7:
|
case 7:
|
||||||
self = .joinedByLink(inviter: PeerId(decoder.decodeInt64ForKey("inviter", orElse: 0)))
|
self = .joinedByLink(inviter: PeerId(decoder.decodeInt64ForKey("inviter", orElse: 0)))
|
||||||
case 8:
|
case 8:
|
||||||
self = .channelMigratedFromGroup(title: decoder.decodeStringForKey("title", orElse: ""), groupId: PeerId(decoder.decodeInt64ForKey("groupId", orElse: 0)))
|
self = .channelMigratedFromGroup(title: decoder.decodeStringForKey("title", orElse: ""), groupId: PeerId(decoder.decodeInt64ForKey("groupId", orElse: 0)))
|
||||||
case 9:
|
case 9:
|
||||||
self = .groupMigratedToChannel(channelId: PeerId(decoder.decodeInt64ForKey("channelId", orElse: 0)))
|
self = .groupMigratedToChannel(channelId: PeerId(decoder.decodeInt64ForKey("channelId", orElse: 0)))
|
||||||
case 10:
|
case 10:
|
||||||
self = .historyCleared
|
self = .historyCleared
|
||||||
case 11:
|
case 11:
|
||||||
self = .historyScreenshot
|
self = .historyScreenshot
|
||||||
case 12:
|
case 12:
|
||||||
self = .messageAutoremoveTimeoutUpdated(decoder.decodeInt32ForKey("t", orElse: 0))
|
self = .messageAutoremoveTimeoutUpdated(decoder.decodeInt32ForKey("t", orElse: 0))
|
||||||
case 13:
|
case 13:
|
||||||
self = .gameScore(gameId: decoder.decodeInt64ForKey("i", orElse: 0), score: decoder.decodeInt32ForKey("s", orElse: 0))
|
self = .gameScore(gameId: decoder.decodeInt64ForKey("i", orElse: 0), score: decoder.decodeInt32ForKey("s", orElse: 0))
|
||||||
case 14:
|
case 14:
|
||||||
var discardReason: PhoneCallDiscardReason?
|
var discardReason: PhoneCallDiscardReason?
|
||||||
if let value = decoder.decodeOptionalInt32ForKey("dr") {
|
if let value = decoder.decodeOptionalInt32ForKey("dr") {
|
||||||
discardReason = PhoneCallDiscardReason(rawValue: value)
|
discardReason = PhoneCallDiscardReason(rawValue: value)
|
||||||
}
|
}
|
||||||
self = .phoneCall(callId: decoder.decodeInt64ForKey("i", orElse: 0), discardReason: discardReason, duration: decoder.decodeInt32ForKey("d", orElse: 0), isVideo: decoder.decodeInt32ForKey("vc", orElse: 0) != 0)
|
self = .phoneCall(callId: decoder.decodeInt64ForKey("i", orElse: 0), discardReason: discardReason, duration: decoder.decodeInt32ForKey("d", orElse: 0), isVideo: decoder.decodeInt32ForKey("vc", orElse: 0) != 0)
|
||||||
case 15:
|
case 15:
|
||||||
self = .paymentSent(currency: decoder.decodeStringForKey("currency", orElse: ""), totalAmount: decoder.decodeInt64ForKey("ta", orElse: 0), invoiceSlug: decoder.decodeOptionalStringForKey("invoiceSlug"), isRecurringInit: decoder.decodeBoolForKey("isRecurringInit", orElse: false), isRecurringUsed: decoder.decodeBoolForKey("isRecurringUsed", orElse: false))
|
self = .paymentSent(currency: decoder.decodeStringForKey("currency", orElse: ""), totalAmount: decoder.decodeInt64ForKey("ta", orElse: 0), invoiceSlug: decoder.decodeOptionalStringForKey("invoiceSlug"), isRecurringInit: decoder.decodeBoolForKey("isRecurringInit", orElse: false), isRecurringUsed: decoder.decodeBoolForKey("isRecurringUsed", orElse: false))
|
||||||
case 16:
|
case 16:
|
||||||
self = .customText(text: decoder.decodeStringForKey("text", orElse: ""), entities: decoder.decodeObjectArrayWithDecoderForKey("ent"))
|
self = .customText(text: decoder.decodeStringForKey("text", orElse: ""), entities: decoder.decodeObjectArrayWithDecoderForKey("ent"))
|
||||||
case 17:
|
case 17:
|
||||||
self = .botDomainAccessGranted(domain: decoder.decodeStringForKey("do", orElse: ""))
|
self = .botDomainAccessGranted(domain: decoder.decodeStringForKey("do", orElse: ""))
|
||||||
case 18:
|
case 18:
|
||||||
self = .botSentSecureValues(types: decoder.decodeInt32ArrayForKey("ty").map { value -> SentSecureValueType in
|
self = .botSentSecureValues(types: decoder.decodeInt32ArrayForKey("ty").map { value -> SentSecureValueType in
|
||||||
return SentSecureValueType(rawValue: value) ?? .personalDetails
|
return SentSecureValueType(rawValue: value) ?? .personalDetails
|
||||||
})
|
})
|
||||||
case 19:
|
case 19:
|
||||||
self = .peerJoined
|
self = .peerJoined
|
||||||
case 20:
|
case 20:
|
||||||
self = .phoneNumberRequest
|
self = .phoneNumberRequest
|
||||||
case 21:
|
case 21:
|
||||||
self = .geoProximityReached(from: PeerId(decoder.decodeInt64ForKey("fromId", orElse: 0)), to: PeerId(decoder.decodeInt64ForKey("toId", orElse: 0)), distance: (decoder.decodeInt32ForKey("dst", orElse: 0)))
|
self = .geoProximityReached(from: PeerId(decoder.decodeInt64ForKey("fromId", orElse: 0)), to: PeerId(decoder.decodeInt64ForKey("toId", orElse: 0)), distance: (decoder.decodeInt32ForKey("dst", orElse: 0)))
|
||||||
case 22:
|
case 22:
|
||||||
self = .groupPhoneCall(callId: decoder.decodeInt64ForKey("callId", orElse: 0), accessHash: decoder.decodeInt64ForKey("accessHash", orElse: 0), scheduleDate: decoder.decodeOptionalInt32ForKey("scheduleDate"), duration: decoder.decodeOptionalInt32ForKey("duration"))
|
self = .groupPhoneCall(callId: decoder.decodeInt64ForKey("callId", orElse: 0), accessHash: decoder.decodeInt64ForKey("accessHash", orElse: 0), scheduleDate: decoder.decodeOptionalInt32ForKey("scheduleDate"), duration: decoder.decodeOptionalInt32ForKey("duration"))
|
||||||
case 23:
|
case 23:
|
||||||
var peerIds: [PeerId] = []
|
var peerIds: [PeerId] = []
|
||||||
if let peerId = decoder.decodeOptionalInt64ForKey("peerId") {
|
if let peerId = decoder.decodeOptionalInt64ForKey("peerId") {
|
||||||
peerIds.append(PeerId(peerId))
|
peerIds.append(PeerId(peerId))
|
||||||
} else {
|
} else {
|
||||||
peerIds = decoder.decodeInt64ArrayForKey("peerIds").map(PeerId.init)
|
peerIds = decoder.decodeInt64ArrayForKey("peerIds").map(PeerId.init)
|
||||||
}
|
}
|
||||||
self = .inviteToGroupPhoneCall(callId: decoder.decodeInt64ForKey("callId", orElse: 0), accessHash: decoder.decodeInt64ForKey("accessHash", orElse: 0), peerIds: peerIds)
|
self = .inviteToGroupPhoneCall(callId: decoder.decodeInt64ForKey("callId", orElse: 0), accessHash: decoder.decodeInt64ForKey("accessHash", orElse: 0), peerIds: peerIds)
|
||||||
case 24:
|
case 24:
|
||||||
self = .setChatTheme(emoji: decoder.decodeStringForKey("emoji", orElse: ""))
|
self = .setChatTheme(emoji: decoder.decodeStringForKey("emoji", orElse: ""))
|
||||||
case 25:
|
case 25:
|
||||||
self = .joinedByRequest
|
self = .joinedByRequest
|
||||||
case 26:
|
case 26:
|
||||||
self = .webViewData(decoder.decodeStringForKey("t", orElse: ""))
|
self = .webViewData(decoder.decodeStringForKey("t", orElse: ""))
|
||||||
case 27:
|
case 27:
|
||||||
self = .giftPremium(currency: decoder.decodeStringForKey("currency", orElse: ""), amount: decoder.decodeInt64ForKey("amount", orElse: 0), months: decoder.decodeInt32ForKey("months", orElse: 0))
|
self = .giftPremium(currency: decoder.decodeStringForKey("currency", orElse: ""), amount: decoder.decodeInt64ForKey("amount", orElse: 0), months: decoder.decodeInt32ForKey("months", orElse: 0))
|
||||||
default:
|
case 28:
|
||||||
self = .unknown
|
self = .topicCreated(title: decoder.decodeStringForKey("t", orElse: ""), iconFileId: decoder.decodeOptionalInt64ForKey("fid"))
|
||||||
|
case 29:
|
||||||
|
self = .topicEditTitle(title: decoder.decodeStringForKey("t", orElse: ""))
|
||||||
|
case 30:
|
||||||
|
self = .topicEditIcon(fileId: decoder.decodeOptionalInt64ForKey("fid"))
|
||||||
|
default:
|
||||||
|
self = .unknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(_ encoder: PostboxEncoder) {
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
switch self {
|
switch self {
|
||||||
case .unknown:
|
case .unknown:
|
||||||
break
|
break
|
||||||
case let .groupCreated(title):
|
case let .groupCreated(title):
|
||||||
encoder.encodeInt32(1, forKey: "_rawValue")
|
encoder.encodeInt32(1, forKey: "_rawValue")
|
||||||
encoder.encodeString(title, forKey: "title")
|
encoder.encodeString(title, forKey: "title")
|
||||||
case let .addedMembers(peerIds):
|
case let .addedMembers(peerIds):
|
||||||
encoder.encodeInt32(2, forKey: "_rawValue")
|
encoder.encodeInt32(2, forKey: "_rawValue")
|
||||||
let buffer = WriteBuffer()
|
let buffer = WriteBuffer()
|
||||||
PeerId.encodeArrayToBuffer(peerIds, buffer: buffer)
|
PeerId.encodeArrayToBuffer(peerIds, buffer: buffer)
|
||||||
encoder.encodeBytes(buffer, forKey: "peerIds")
|
encoder.encodeBytes(buffer, forKey: "peerIds")
|
||||||
case let .removedMembers(peerIds):
|
case let .removedMembers(peerIds):
|
||||||
encoder.encodeInt32(3, forKey: "_rawValue")
|
encoder.encodeInt32(3, forKey: "_rawValue")
|
||||||
let buffer = WriteBuffer()
|
let buffer = WriteBuffer()
|
||||||
PeerId.encodeArrayToBuffer(peerIds, buffer: buffer)
|
PeerId.encodeArrayToBuffer(peerIds, buffer: buffer)
|
||||||
encoder.encodeBytes(buffer, forKey: "peerIds")
|
encoder.encodeBytes(buffer, forKey: "peerIds")
|
||||||
case let .photoUpdated(image):
|
case let .photoUpdated(image):
|
||||||
encoder.encodeInt32(4, forKey: "_rawValue")
|
encoder.encodeInt32(4, forKey: "_rawValue")
|
||||||
if let image = image {
|
if let image = image {
|
||||||
encoder.encodeObject(image, forKey: "image")
|
encoder.encodeObject(image, forKey: "image")
|
||||||
}
|
}
|
||||||
case let .titleUpdated(title):
|
case let .titleUpdated(title):
|
||||||
encoder.encodeInt32(5, forKey: "_rawValue")
|
encoder.encodeInt32(5, forKey: "_rawValue")
|
||||||
encoder.encodeString(title, forKey: "title")
|
encoder.encodeString(title, forKey: "title")
|
||||||
case .pinnedMessageUpdated:
|
case .pinnedMessageUpdated:
|
||||||
encoder.encodeInt32(6, forKey: "_rawValue")
|
encoder.encodeInt32(6, forKey: "_rawValue")
|
||||||
case let .joinedByLink(inviter):
|
case let .joinedByLink(inviter):
|
||||||
encoder.encodeInt32(7, forKey: "_rawValue")
|
encoder.encodeInt32(7, forKey: "_rawValue")
|
||||||
encoder.encodeInt64(inviter.toInt64(), forKey: "inviter")
|
encoder.encodeInt64(inviter.toInt64(), forKey: "inviter")
|
||||||
case let .channelMigratedFromGroup(title, groupId):
|
case let .channelMigratedFromGroup(title, groupId):
|
||||||
encoder.encodeInt32(8, forKey: "_rawValue")
|
encoder.encodeInt32(8, forKey: "_rawValue")
|
||||||
encoder.encodeString(title, forKey: "title")
|
encoder.encodeString(title, forKey: "title")
|
||||||
encoder.encodeInt64(groupId.toInt64(), forKey: "groupId")
|
encoder.encodeInt64(groupId.toInt64(), forKey: "groupId")
|
||||||
case let .groupMigratedToChannel(channelId):
|
case let .groupMigratedToChannel(channelId):
|
||||||
encoder.encodeInt32(9, forKey: "_rawValue")
|
encoder.encodeInt32(9, forKey: "_rawValue")
|
||||||
encoder.encodeInt64(channelId.toInt64(), forKey: "channelId")
|
encoder.encodeInt64(channelId.toInt64(), forKey: "channelId")
|
||||||
case .historyCleared:
|
case .historyCleared:
|
||||||
encoder.encodeInt32(10, forKey: "_rawValue")
|
encoder.encodeInt32(10, forKey: "_rawValue")
|
||||||
case .historyScreenshot:
|
case .historyScreenshot:
|
||||||
encoder.encodeInt32(11, forKey: "_rawValue")
|
encoder.encodeInt32(11, forKey: "_rawValue")
|
||||||
case let .messageAutoremoveTimeoutUpdated(timeout):
|
case let .messageAutoremoveTimeoutUpdated(timeout):
|
||||||
encoder.encodeInt32(12, forKey: "_rawValue")
|
encoder.encodeInt32(12, forKey: "_rawValue")
|
||||||
encoder.encodeInt32(timeout, forKey: "t")
|
encoder.encodeInt32(timeout, forKey: "t")
|
||||||
case let .gameScore(gameId, score):
|
case let .gameScore(gameId, score):
|
||||||
encoder.encodeInt32(13, forKey: "_rawValue")
|
encoder.encodeInt32(13, forKey: "_rawValue")
|
||||||
encoder.encodeInt64(gameId, forKey: "i")
|
encoder.encodeInt64(gameId, forKey: "i")
|
||||||
encoder.encodeInt32(score, forKey: "s")
|
encoder.encodeInt32(score, forKey: "s")
|
||||||
case let .paymentSent(currency, totalAmount, invoiceSlug, isRecurringInit, isRecurringUsed):
|
case let .paymentSent(currency, totalAmount, invoiceSlug, isRecurringInit, isRecurringUsed):
|
||||||
encoder.encodeInt32(15, forKey: "_rawValue")
|
encoder.encodeInt32(15, forKey: "_rawValue")
|
||||||
encoder.encodeString(currency, forKey: "currency")
|
encoder.encodeString(currency, forKey: "currency")
|
||||||
encoder.encodeInt64(totalAmount, forKey: "ta")
|
encoder.encodeInt64(totalAmount, forKey: "ta")
|
||||||
if let invoiceSlug = invoiceSlug {
|
if let invoiceSlug = invoiceSlug {
|
||||||
encoder.encodeString(invoiceSlug, forKey: "invoiceSlug")
|
encoder.encodeString(invoiceSlug, forKey: "invoiceSlug")
|
||||||
} else {
|
} else {
|
||||||
encoder.encodeNil(forKey: "invoiceSlug")
|
encoder.encodeNil(forKey: "invoiceSlug")
|
||||||
}
|
}
|
||||||
encoder.encodeBool(isRecurringInit, forKey: "isRecurringInit")
|
encoder.encodeBool(isRecurringInit, forKey: "isRecurringInit")
|
||||||
encoder.encodeBool(isRecurringUsed, forKey: "isRecurringUsed")
|
encoder.encodeBool(isRecurringUsed, forKey: "isRecurringUsed")
|
||||||
case let .phoneCall(callId, discardReason, duration, isVideo):
|
case let .phoneCall(callId, discardReason, duration, isVideo):
|
||||||
encoder.encodeInt32(14, forKey: "_rawValue")
|
encoder.encodeInt32(14, forKey: "_rawValue")
|
||||||
encoder.encodeInt64(callId, forKey: "i")
|
encoder.encodeInt64(callId, forKey: "i")
|
||||||
if let discardReason = discardReason {
|
if let discardReason = discardReason {
|
||||||
encoder.encodeInt32(discardReason.rawValue, forKey: "dr")
|
encoder.encodeInt32(discardReason.rawValue, forKey: "dr")
|
||||||
} else {
|
} else {
|
||||||
encoder.encodeNil(forKey: "dr")
|
encoder.encodeNil(forKey: "dr")
|
||||||
}
|
}
|
||||||
if let duration = duration {
|
if let duration = duration {
|
||||||
encoder.encodeInt32(duration, forKey: "d")
|
encoder.encodeInt32(duration, forKey: "d")
|
||||||
} else {
|
} else {
|
||||||
encoder.encodeNil(forKey: "d")
|
encoder.encodeNil(forKey: "d")
|
||||||
}
|
}
|
||||||
encoder.encodeInt32(isVideo ? 1 : 0, forKey: "vc")
|
encoder.encodeInt32(isVideo ? 1 : 0, forKey: "vc")
|
||||||
case let .customText(text, entities):
|
case let .customText(text, entities):
|
||||||
encoder.encodeInt32(16, forKey: "_rawValue")
|
encoder.encodeInt32(16, forKey: "_rawValue")
|
||||||
encoder.encodeString(text, forKey: "text")
|
encoder.encodeString(text, forKey: "text")
|
||||||
encoder.encodeObjectArray(entities, forKey: "ent")
|
encoder.encodeObjectArray(entities, forKey: "ent")
|
||||||
case let .botDomainAccessGranted(domain):
|
case let .botDomainAccessGranted(domain):
|
||||||
encoder.encodeInt32(17, forKey: "_rawValue")
|
encoder.encodeInt32(17, forKey: "_rawValue")
|
||||||
encoder.encodeString(domain, forKey: "do")
|
encoder.encodeString(domain, forKey: "do")
|
||||||
case let .botSentSecureValues(types):
|
case let .botSentSecureValues(types):
|
||||||
encoder.encodeInt32(18, forKey: "_rawValue")
|
encoder.encodeInt32(18, forKey: "_rawValue")
|
||||||
encoder.encodeInt32Array(types.map { $0.rawValue }, forKey: "ty")
|
encoder.encodeInt32Array(types.map { $0.rawValue }, forKey: "ty")
|
||||||
case .peerJoined:
|
case .peerJoined:
|
||||||
encoder.encodeInt32(19, forKey: "_rawValue")
|
encoder.encodeInt32(19, forKey: "_rawValue")
|
||||||
case .phoneNumberRequest:
|
case .phoneNumberRequest:
|
||||||
encoder.encodeInt32(20, forKey: "_rawValue")
|
encoder.encodeInt32(20, forKey: "_rawValue")
|
||||||
case let .geoProximityReached(from, to, distance):
|
case let .geoProximityReached(from, to, distance):
|
||||||
encoder.encodeInt32(21, forKey: "_rawValue")
|
encoder.encodeInt32(21, forKey: "_rawValue")
|
||||||
encoder.encodeInt64(from.toInt64(), forKey: "fromId")
|
encoder.encodeInt64(from.toInt64(), forKey: "fromId")
|
||||||
encoder.encodeInt64(to.toInt64(), forKey: "toId")
|
encoder.encodeInt64(to.toInt64(), forKey: "toId")
|
||||||
encoder.encodeInt32(distance, forKey: "dst")
|
encoder.encodeInt32(distance, forKey: "dst")
|
||||||
case let .groupPhoneCall(callId, accessHash, scheduleDate, duration):
|
case let .groupPhoneCall(callId, accessHash, scheduleDate, duration):
|
||||||
encoder.encodeInt32(22, forKey: "_rawValue")
|
encoder.encodeInt32(22, forKey: "_rawValue")
|
||||||
encoder.encodeInt64(callId, forKey: "callId")
|
encoder.encodeInt64(callId, forKey: "callId")
|
||||||
encoder.encodeInt64(accessHash, forKey: "accessHash")
|
encoder.encodeInt64(accessHash, forKey: "accessHash")
|
||||||
if let scheduleDate = scheduleDate {
|
if let scheduleDate = scheduleDate {
|
||||||
encoder.encodeInt32(scheduleDate, forKey: "scheduleDate")
|
encoder.encodeInt32(scheduleDate, forKey: "scheduleDate")
|
||||||
} else {
|
} else {
|
||||||
encoder.encodeNil(forKey: "scheduleDate")
|
encoder.encodeNil(forKey: "scheduleDate")
|
||||||
}
|
}
|
||||||
if let duration = duration {
|
if let duration = duration {
|
||||||
encoder.encodeInt32(duration, forKey: "duration")
|
encoder.encodeInt32(duration, forKey: "duration")
|
||||||
} else {
|
} else {
|
||||||
encoder.encodeNil(forKey: "duration")
|
encoder.encodeNil(forKey: "duration")
|
||||||
}
|
}
|
||||||
case let .inviteToGroupPhoneCall(callId, accessHash, peerIds):
|
case let .inviteToGroupPhoneCall(callId, accessHash, peerIds):
|
||||||
encoder.encodeInt32(23, forKey: "_rawValue")
|
encoder.encodeInt32(23, forKey: "_rawValue")
|
||||||
encoder.encodeInt64(callId, forKey: "callId")
|
encoder.encodeInt64(callId, forKey: "callId")
|
||||||
encoder.encodeInt64(accessHash, forKey: "accessHash")
|
encoder.encodeInt64(accessHash, forKey: "accessHash")
|
||||||
encoder.encodeInt64Array(peerIds.map { $0.toInt64() }, forKey: "peerIds")
|
encoder.encodeInt64Array(peerIds.map { $0.toInt64() }, forKey: "peerIds")
|
||||||
case let .setChatTheme(emoji):
|
case let .setChatTheme(emoji):
|
||||||
encoder.encodeInt32(24, forKey: "_rawValue")
|
encoder.encodeInt32(24, forKey: "_rawValue")
|
||||||
encoder.encodeString(emoji, forKey: "emoji")
|
encoder.encodeString(emoji, forKey: "emoji")
|
||||||
case .joinedByRequest:
|
case .joinedByRequest:
|
||||||
encoder.encodeInt32(25, forKey: "_rawValue")
|
encoder.encodeInt32(25, forKey: "_rawValue")
|
||||||
case let .webViewData(text):
|
case let .webViewData(text):
|
||||||
encoder.encodeInt32(26, forKey: "_rawValue")
|
encoder.encodeInt32(26, forKey: "_rawValue")
|
||||||
encoder.encodeString(text, forKey: "t")
|
encoder.encodeString(text, forKey: "t")
|
||||||
case let .giftPremium(currency, amount, months):
|
case let .giftPremium(currency, amount, months):
|
||||||
encoder.encodeInt32(27, forKey: "_rawValue")
|
encoder.encodeInt32(27, forKey: "_rawValue")
|
||||||
encoder.encodeString(currency, forKey: "currency")
|
encoder.encodeString(currency, forKey: "currency")
|
||||||
encoder.encodeInt64(amount, forKey: "amount")
|
encoder.encodeInt64(amount, forKey: "amount")
|
||||||
encoder.encodeInt32(months, forKey: "months")
|
encoder.encodeInt32(months, forKey: "months")
|
||||||
|
case let .topicCreated(title, iconFileId):
|
||||||
|
encoder.encodeInt32(28, forKey: "_rawValue")
|
||||||
|
encoder.encodeString(title, forKey: "t")
|
||||||
|
if let fileId = iconFileId {
|
||||||
|
encoder.encodeInt64(fileId, forKey: "fid")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "fid")
|
||||||
|
}
|
||||||
|
case let .topicEditTitle(title):
|
||||||
|
encoder.encodeInt32(29, forKey: "_rawValue")
|
||||||
|
encoder.encodeString(title, forKey: "t")
|
||||||
|
case let .topicEditIcon(fileId):
|
||||||
|
encoder.encodeInt32(30, forKey: "_rawValue")
|
||||||
|
if let fileId = fileId {
|
||||||
|
encoder.encodeInt64(fileId, forKey: "fid")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "fid")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var peerIds: [PeerId] {
|
public var peerIds: [PeerId] {
|
||||||
switch self {
|
switch self {
|
||||||
case let .addedMembers(peerIds):
|
case let .addedMembers(peerIds):
|
||||||
return peerIds
|
return peerIds
|
||||||
case let .removedMembers(peerIds):
|
case let .removedMembers(peerIds):
|
||||||
return peerIds
|
return peerIds
|
||||||
case let .joinedByLink(inviter):
|
case let .joinedByLink(inviter):
|
||||||
return [inviter]
|
return [inviter]
|
||||||
case let .channelMigratedFromGroup(_, groupId):
|
case let .channelMigratedFromGroup(_, groupId):
|
||||||
return [groupId]
|
return [groupId]
|
||||||
case let .groupMigratedToChannel(channelId):
|
case let .groupMigratedToChannel(channelId):
|
||||||
return [channelId]
|
return [channelId]
|
||||||
case let .geoProximityReached(from, to, _):
|
case let .geoProximityReached(from, to, _):
|
||||||
return [from, to]
|
return [from, to]
|
||||||
case let .inviteToGroupPhoneCall(_, _, peerIds):
|
case let .inviteToGroupPhoneCall(_, _, peerIds):
|
||||||
return peerIds
|
return peerIds
|
||||||
default:
|
default:
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,7 +243,7 @@ public extension TelegramEngine.EngineData.Item {
|
|||||||
guard let view = view as? ChatListIndexView else {
|
guard let view = view as? ChatListIndexView else {
|
||||||
preconditionFailure()
|
preconditionFailure()
|
||||||
}
|
}
|
||||||
return view.chatListIndex
|
return view.chatListIndex.flatMap(EngineChatList.Item.Index.chatList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Postbox
|
import Postbox
|
||||||
|
|
||||||
public final class EngineChatList {
|
public final class EngineChatList: Equatable {
|
||||||
public enum Group {
|
public enum Group {
|
||||||
case root
|
case root
|
||||||
case archive
|
case archive
|
||||||
@ -17,7 +17,7 @@ public final class EngineChatList {
|
|||||||
case earlier(than: EngineChatList.Item.Index?)
|
case earlier(than: EngineChatList.Item.Index?)
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct Draft {
|
public struct Draft: Equatable {
|
||||||
public var text: String
|
public var text: String
|
||||||
public var entities: [MessageTextEntity]
|
public var entities: [MessageTextEntity]
|
||||||
|
|
||||||
@ -27,14 +27,52 @@ public final class EngineChatList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class Item {
|
public final class Item: Equatable {
|
||||||
public typealias Index = ChatListIndex
|
public enum Id: Hashable {
|
||||||
|
case chatList(EnginePeer.Id)
|
||||||
|
case forum(Int64)
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Index: Equatable, Comparable {
|
||||||
|
public typealias ChatList = ChatListIndex
|
||||||
|
|
||||||
|
case chatList(ChatListIndex)
|
||||||
|
case forum(timestamp: Int32, threadId: Int64, namespace: EngineMessage.Id.Namespace, id: EngineMessage.Id.Id)
|
||||||
|
|
||||||
|
public static func <(lhs: Index, rhs: Index) -> Bool {
|
||||||
|
switch lhs {
|
||||||
|
case let .chatList(lhsIndex):
|
||||||
|
if case let .chatList(rhsIndex) = rhs {
|
||||||
|
return lhsIndex < rhsIndex
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case let .forum(lhsTimestamp, lhsThreadId, lhsNamespace, lhsId):
|
||||||
|
if case let .forum(rhsTimestamp, rhsThreadId, rhsNamespace, rhsId) = rhs {
|
||||||
|
if lhsTimestamp != rhsTimestamp {
|
||||||
|
return lhsTimestamp < rhsTimestamp
|
||||||
|
}
|
||||||
|
if lhsThreadId != rhsThreadId {
|
||||||
|
return lhsThreadId < rhsThreadId
|
||||||
|
}
|
||||||
|
if lhsNamespace != rhsNamespace {
|
||||||
|
return lhsNamespace < rhsNamespace
|
||||||
|
}
|
||||||
|
return lhsId < rhsId
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public let id: Id
|
||||||
public let index: Index
|
public let index: Index
|
||||||
public let messages: [EngineMessage]
|
public let messages: [EngineMessage]
|
||||||
public let readCounters: EnginePeerReadCounters?
|
public let readCounters: EnginePeerReadCounters?
|
||||||
public let isMuted: Bool
|
public let isMuted: Bool
|
||||||
public let draft: Draft?
|
public let draft: Draft?
|
||||||
|
public let threadInfo: EngineMessageHistoryThreads.Info?
|
||||||
public let renderedPeer: EngineRenderedPeer
|
public let renderedPeer: EngineRenderedPeer
|
||||||
public let presence: EnginePeer.Presence?
|
public let presence: EnginePeer.Presence?
|
||||||
public let hasUnseenMentions: Bool
|
public let hasUnseenMentions: Bool
|
||||||
@ -43,11 +81,13 @@ public final class EngineChatList {
|
|||||||
public let isContact: Bool
|
public let isContact: Bool
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
|
id: Id,
|
||||||
index: Index,
|
index: Index,
|
||||||
messages: [EngineMessage],
|
messages: [EngineMessage],
|
||||||
readCounters: EnginePeerReadCounters?,
|
readCounters: EnginePeerReadCounters?,
|
||||||
isMuted: Bool,
|
isMuted: Bool,
|
||||||
draft: Draft?,
|
draft: Draft?,
|
||||||
|
threadInfo: EngineMessageHistoryThreads.Info?,
|
||||||
renderedPeer: EngineRenderedPeer,
|
renderedPeer: EngineRenderedPeer,
|
||||||
presence: EnginePeer.Presence?,
|
presence: EnginePeer.Presence?,
|
||||||
hasUnseenMentions: Bool,
|
hasUnseenMentions: Bool,
|
||||||
@ -55,11 +95,13 @@ public final class EngineChatList {
|
|||||||
hasFailed: Bool,
|
hasFailed: Bool,
|
||||||
isContact: Bool
|
isContact: Bool
|
||||||
) {
|
) {
|
||||||
|
self.id = id
|
||||||
self.index = index
|
self.index = index
|
||||||
self.messages = messages
|
self.messages = messages
|
||||||
self.readCounters = readCounters
|
self.readCounters = readCounters
|
||||||
self.isMuted = isMuted
|
self.isMuted = isMuted
|
||||||
self.draft = draft
|
self.draft = draft
|
||||||
|
self.threadInfo = threadInfo
|
||||||
self.renderedPeer = renderedPeer
|
self.renderedPeer = renderedPeer
|
||||||
self.presence = presence
|
self.presence = presence
|
||||||
self.hasUnseenMentions = hasUnseenMentions
|
self.hasUnseenMentions = hasUnseenMentions
|
||||||
@ -67,6 +109,49 @@ public final class EngineChatList {
|
|||||||
self.hasFailed = hasFailed
|
self.hasFailed = hasFailed
|
||||||
self.isContact = isContact
|
self.isContact = isContact
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: Item, rhs: Item) -> Bool {
|
||||||
|
if lhs.id != rhs.id {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.index != rhs.index {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.messages != rhs.messages {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.readCounters != rhs.readCounters {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.isMuted != rhs.isMuted {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.draft != rhs.draft {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.threadInfo != rhs.threadInfo {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.renderedPeer != rhs.renderedPeer {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.presence != rhs.presence {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.hasUnseenMentions != rhs.hasUnseenMentions {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.hasUnseenReactions != rhs.hasUnseenReactions {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.hasFailed != rhs.hasFailed {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.isContact != rhs.isContact {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class GroupItem: Equatable {
|
public final class GroupItem: Equatable {
|
||||||
@ -127,9 +212,9 @@ public final class EngineChatList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class AdditionalItem {
|
public final class AdditionalItem: Equatable {
|
||||||
public final class PromoInfo {
|
public final class PromoInfo: Equatable {
|
||||||
public enum Content {
|
public enum Content: Equatable {
|
||||||
case proxy
|
case proxy
|
||||||
case psa(type: String, message: String?)
|
case psa(type: String, message: String?)
|
||||||
}
|
}
|
||||||
@ -139,6 +224,14 @@ public final class EngineChatList {
|
|||||||
public init(content: Content) {
|
public init(content: Content) {
|
||||||
self.content = content
|
self.content = content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: PromoInfo, rhs: PromoInfo) -> Bool {
|
||||||
|
if lhs.content != rhs.content {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public let item: Item
|
public let item: Item
|
||||||
@ -148,6 +241,17 @@ public final class EngineChatList {
|
|||||||
self.item = item
|
self.item = item
|
||||||
self.promoInfo = promoInfo
|
self.promoInfo = promoInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: AdditionalItem, rhs: AdditionalItem) -> Bool {
|
||||||
|
if lhs.item != rhs.item {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.promoInfo != rhs.promoInfo {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public let items: [Item]
|
public let items: [Item]
|
||||||
@ -157,7 +261,7 @@ public final class EngineChatList {
|
|||||||
public let hasLater: Bool
|
public let hasLater: Bool
|
||||||
public let isLoading: Bool
|
public let isLoading: Bool
|
||||||
|
|
||||||
init(
|
public init(
|
||||||
items: [Item],
|
items: [Item],
|
||||||
groupItems: [GroupItem],
|
groupItems: [GroupItem],
|
||||||
additionalItems: [AdditionalItem],
|
additionalItems: [AdditionalItem],
|
||||||
@ -172,6 +276,29 @@ public final class EngineChatList {
|
|||||||
self.hasLater = hasLater
|
self.hasLater = hasLater
|
||||||
self.isLoading = isLoading
|
self.isLoading = isLoading
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: EngineChatList, rhs: EngineChatList) -> Bool {
|
||||||
|
if lhs.items != rhs.items {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.groupItems != rhs.groupItems {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.additionalItems != rhs.additionalItems {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.hasEarlier != rhs.hasEarlier {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.hasLater != rhs.hasLater {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.isLoading != rhs.isLoading {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension EngineChatList.Group {
|
public extension EngineChatList.Group {
|
||||||
@ -199,17 +326,23 @@ public extension EngineChatList.RelativePosition {
|
|||||||
init(_ position: ChatListRelativePosition) {
|
init(_ position: ChatListRelativePosition) {
|
||||||
switch position {
|
switch position {
|
||||||
case let .earlier(than):
|
case let .earlier(than):
|
||||||
self = .earlier(than: than)
|
self = .earlier(than: than.flatMap(EngineChatList.Item.Index.chatList))
|
||||||
case let .later(than):
|
case let .later(than):
|
||||||
self = .later(than: than)
|
self = .later(than: than.flatMap(EngineChatList.Item.Index.chatList))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func _asPosition() -> ChatListRelativePosition {
|
func _asPosition() -> ChatListRelativePosition? {
|
||||||
switch self {
|
switch self {
|
||||||
case let .earlier(than):
|
case let .earlier(than):
|
||||||
|
guard case let .chatList(than) = than else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return .earlier(than: than)
|
return .earlier(than: than)
|
||||||
case let .later(than):
|
case let .later(than):
|
||||||
|
guard case let .chatList(than) = than else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return .later(than: than)
|
return .later(than: than)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -245,11 +378,13 @@ extension EngineChatList.Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.init(
|
self.init(
|
||||||
index: index,
|
id: .chatList(index.messageIndex.id.peerId),
|
||||||
|
index: .chatList(index),
|
||||||
messages: messages.map(EngineMessage.init),
|
messages: messages.map(EngineMessage.init),
|
||||||
readCounters: readState.flatMap(EnginePeerReadCounters.init),
|
readCounters: readState.flatMap(EnginePeerReadCounters.init),
|
||||||
isMuted: isRemovedFromTotalUnreadCount,
|
isMuted: isRemovedFromTotalUnreadCount,
|
||||||
draft: draft,
|
draft: draft,
|
||||||
|
threadInfo: nil,
|
||||||
renderedPeer: EngineRenderedPeer(renderedPeer),
|
renderedPeer: EngineRenderedPeer(renderedPeer),
|
||||||
presence: presence.flatMap(EnginePeer.Presence.init),
|
presence: presence.flatMap(EnginePeer.Presence.init),
|
||||||
hasUnseenMentions: hasUnseenMentions,
|
hasUnseenMentions: hasUnseenMentions,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Postbox
|
import Postbox
|
||||||
|
|
||||||
public final class EngineMessage {
|
public final class EngineMessage: Equatable {
|
||||||
public typealias Id = MessageId
|
public typealias Id = MessageId
|
||||||
public typealias Index = MessageIndex
|
public typealias Index = MessageIndex
|
||||||
public typealias Tags = MessageTags
|
public typealias Tags = MessageTags
|
||||||
@ -148,4 +148,50 @@ public final class EngineMessage {
|
|||||||
public func _asMessage() -> Message {
|
public func _asMessage() -> Message {
|
||||||
return self.impl
|
return self.impl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: EngineMessage, rhs: EngineMessage) -> Bool {
|
||||||
|
if lhs.id != rhs.id {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.globallyUniqueId != rhs.globallyUniqueId {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.groupingKey != rhs.groupingKey {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.groupInfo != rhs.groupInfo {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.threadId != rhs.threadId {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.timestamp != rhs.timestamp {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.flags != rhs.flags {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.tags != rhs.tags {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.globalTags != rhs.globalTags {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.localTags != rhs.localTags {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.forwardInfo != rhs.forwardInfo {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.author != rhs.author {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.text != rhs.text {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !areMediaArraysEqual(lhs.media, rhs.media) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -440,8 +440,11 @@ public extension TelegramEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func getRelativeUnreadChatListIndex(filtered: Bool, position: EngineChatList.RelativePosition, groupId: EngineChatList.Group) -> Signal<EngineChatList.Item.Index?, NoError> {
|
public func getRelativeUnreadChatListIndex(filtered: Bool, position: EngineChatList.RelativePosition, groupId: EngineChatList.Group) -> Signal<EngineChatList.Item.Index?, NoError> {
|
||||||
|
guard let position = position._asPosition() else {
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
return self.account.postbox.transaction { transaction -> EngineChatList.Item.Index? in
|
return self.account.postbox.transaction { transaction -> EngineChatList.Item.Index? in
|
||||||
return transaction.getRelativeUnreadChatListIndex(filtered: filtered, position: position._asPosition(), groupId: groupId._asGroup())
|
return transaction.getRelativeUnreadChatListIndex(filtered: filtered, position: position, groupId: groupId._asGroup()).flatMap(EngineChatList.Item.Index.chatList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +61,17 @@ private func createChannel(account: Account, title: String, description: String?
|
|||||||
}
|
}
|
||||||
|> castError(CreateChannelError.self)
|
|> castError(CreateChannelError.self)
|
||||||
|> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.generic))
|
|> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.generic))
|
||||||
|
|> mapToSignal { peerId -> Signal<PeerId, CreateChannelError> in
|
||||||
|
if title.contains("*forum") {
|
||||||
|
return _internal_setChannelForumMode(account: account, peerId: peerId, isForum: true)
|
||||||
|
|> castError(CreateChannelError.self)
|
||||||
|
|> map { _ -> PeerId in
|
||||||
|
}
|
||||||
|
|> then(.single(peerId))
|
||||||
|
} else {
|
||||||
|
return .single(peerId)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return .fail(.generic)
|
return .fail(.generic)
|
||||||
}
|
}
|
||||||
|
@ -776,6 +776,10 @@ public extension TelegramEngine {
|
|||||||
}
|
}
|
||||||
|> ignoreValues
|
|> ignoreValues
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func setChannelForumMode(id: EnginePeer.Id, isForum: Bool) -> Signal<Never, NoError> {
|
||||||
|
return _internal_setChannelForumMode(account: self.account, peerId: id, isForum: isForum)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -679,6 +679,16 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
attributes[1] = boldAttributes
|
attributes[1] = boldAttributes
|
||||||
attributedString = addAttributesToStringWithRanges(strings.Notification_PremiumGift_Sent(authorName, price)._tuple, body: bodyAttributes, argumentAttributes: attributes)
|
attributedString = addAttributesToStringWithRanges(strings.Notification_PremiumGift_Sent(authorName, price)._tuple, body: bodyAttributes, argumentAttributes: attributes)
|
||||||
}
|
}
|
||||||
|
case .topicCreated:
|
||||||
|
//TODO:localize
|
||||||
|
attributedString = NSAttributedString(string: "Topic created", font: titleFont, textColor: primaryTextColor)
|
||||||
|
case let .topicEditTitle(title):
|
||||||
|
//TODO:localize
|
||||||
|
attributedString = NSAttributedString(string: "Topic renamed to \"\(title)\"", font: titleFont, textColor: primaryTextColor)
|
||||||
|
case let .topicEditIcon(fileId):
|
||||||
|
let _ = fileId
|
||||||
|
//TODO:localize
|
||||||
|
attributedString = NSAttributedString(string: "Topic icon changed", font: titleFont, textColor: primaryTextColor)
|
||||||
case .unknown:
|
case .unknown:
|
||||||
attributedString = nil
|
attributedString = nil
|
||||||
}
|
}
|
||||||
|
@ -297,6 +297,7 @@ swift_library(
|
|||||||
"//submodules/Media/LocalAudioTranscription:LocalAudioTranscription",
|
"//submodules/Media/LocalAudioTranscription:LocalAudioTranscription",
|
||||||
"//submodules/Components/PagerComponent:PagerComponent",
|
"//submodules/Components/PagerComponent:PagerComponent",
|
||||||
"//submodules/Components/LottieAnimationComponent:LottieAnimationComponent",
|
"//submodules/Components/LottieAnimationComponent:LottieAnimationComponent",
|
||||||
|
"//submodules/TelegramUI/Components/ForumTopicListScreen:ForumTopicListScreen",
|
||||||
] + select({
|
] + select({
|
||||||
"@build_bazel_rules_apple//apple:ios_armv7": [],
|
"@build_bazel_rules_apple//apple:ios_armv7": [],
|
||||||
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
||||||
|
33
submodules/TelegramUI/Components/ForumTopicListScreen/BUILD
Normal file
33
submodules/TelegramUI/Components/ForumTopicListScreen/BUILD
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||||
|
|
||||||
|
swift_library(
|
||||||
|
name = "ForumTopicListScreen",
|
||||||
|
module_name = "ForumTopicListScreen",
|
||||||
|
srcs = glob([
|
||||||
|
"Sources/**/*.swift",
|
||||||
|
]),
|
||||||
|
copts = [
|
||||||
|
"-warnings-as-errors",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||||
|
"//submodules/Display:Display",
|
||||||
|
"//submodules/Postbox:Postbox",
|
||||||
|
"//submodules/TelegramCore:TelegramCore",
|
||||||
|
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||||
|
"//submodules/ComponentFlow:ComponentFlow",
|
||||||
|
"//submodules/TelegramUI/Components/AnimationCache:AnimationCache",
|
||||||
|
"//submodules/TelegramUI/Components/MultiAnimationRenderer:MultiAnimationRenderer",
|
||||||
|
"//submodules/TelegramUI/Components/EmojiTextAttachmentView:EmojiTextAttachmentView",
|
||||||
|
"//submodules/Components/ComponentDisplayAdapters:ComponentDisplayAdapters",
|
||||||
|
"//submodules/Components/MultilineTextComponent:MultilineTextComponent",
|
||||||
|
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||||
|
"//submodules/AccountContext:AccountContext",
|
||||||
|
"//submodules/AppBundle:AppBundle",
|
||||||
|
"//submodules/TelegramStringFormatting:TelegramStringFormatting",
|
||||||
|
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
],
|
||||||
|
)
|
@ -0,0 +1,495 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import Display
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import ComponentFlow
|
||||||
|
import SwiftSignalKit
|
||||||
|
import AnimationCache
|
||||||
|
import MultiAnimationRenderer
|
||||||
|
import ComponentDisplayAdapters
|
||||||
|
import TelegramPresentationData
|
||||||
|
import AccountContext
|
||||||
|
import Postbox
|
||||||
|
import TelegramCore
|
||||||
|
|
||||||
|
private final class ForumTopicListItemComponent: Component {
|
||||||
|
let context: AccountContext
|
||||||
|
let theme: PresentationTheme
|
||||||
|
let strings: PresentationStrings
|
||||||
|
let item: ForumChannelTopics.Item
|
||||||
|
let action: () -> Void
|
||||||
|
|
||||||
|
init(
|
||||||
|
context: AccountContext,
|
||||||
|
theme: PresentationTheme,
|
||||||
|
strings: PresentationStrings,
|
||||||
|
item: ForumChannelTopics.Item,
|
||||||
|
action: @escaping () -> Void
|
||||||
|
) {
|
||||||
|
self.context = context
|
||||||
|
self.theme = theme
|
||||||
|
self.strings = strings
|
||||||
|
self.item = item
|
||||||
|
self.action = action
|
||||||
|
}
|
||||||
|
|
||||||
|
static func ==(lhs: ForumTopicListItemComponent, rhs: ForumTopicListItemComponent) -> Bool {
|
||||||
|
if lhs.context !== rhs.context {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.theme !== rhs.theme {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.strings !== rhs.strings {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.item != rhs.item {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
final class View: HighlightTrackingButton {
|
||||||
|
private var highlightedBackgroundLayer: SimpleLayer?
|
||||||
|
private let title: ComponentView<Empty>
|
||||||
|
|
||||||
|
private var component: ForumTopicListItemComponent?
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
self.title = ComponentView()
|
||||||
|
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
self.addTarget(self, action: #selector(self.pressed), for: .touchUpInside)
|
||||||
|
|
||||||
|
self.highligthedChanged = { [weak self] highlighted in
|
||||||
|
if let self, let component = self.component {
|
||||||
|
if highlighted {
|
||||||
|
if let superview = self.superview {
|
||||||
|
superview.bringSubviewToFront(self)
|
||||||
|
}
|
||||||
|
let highlightedBackgroundLayer: SimpleLayer
|
||||||
|
if let current = self.highlightedBackgroundLayer {
|
||||||
|
highlightedBackgroundLayer = current
|
||||||
|
} else {
|
||||||
|
highlightedBackgroundLayer = SimpleLayer()
|
||||||
|
self.highlightedBackgroundLayer = highlightedBackgroundLayer
|
||||||
|
highlightedBackgroundLayer.backgroundColor = component.theme.list.itemHighlightedBackgroundColor.cgColor
|
||||||
|
highlightedBackgroundLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: self.bounds.width, height: self.bounds.height + UIScreenPixel))
|
||||||
|
self.layer.insertSublayer(highlightedBackgroundLayer, at: 0)
|
||||||
|
}
|
||||||
|
highlightedBackgroundLayer.removeAllAnimations()
|
||||||
|
highlightedBackgroundLayer.opacity = 1.0
|
||||||
|
} else {
|
||||||
|
if let highlightedBackgroundLayer = self.highlightedBackgroundLayer {
|
||||||
|
self.highlightedBackgroundLayer = nil
|
||||||
|
highlightedBackgroundLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak highlightedBackgroundLayer] _ in
|
||||||
|
highlightedBackgroundLayer?.removeFromSuperlayer()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
preconditionFailure()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func pressed() {
|
||||||
|
self.component?.action()
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(component: ForumTopicListItemComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
|
self.component = component
|
||||||
|
|
||||||
|
let titleSize = self.title.update(
|
||||||
|
transition: .immediate,
|
||||||
|
component: AnyComponent(Text(
|
||||||
|
text: component.item.info.title,
|
||||||
|
font: Font.regular(17.0),
|
||||||
|
color: component.theme.list.itemPrimaryTextColor
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: availableSize
|
||||||
|
)
|
||||||
|
if let titleView = self.title.view {
|
||||||
|
if titleView.superview == nil {
|
||||||
|
self.addSubview(titleView)
|
||||||
|
titleView.isUserInteractionEnabled = false
|
||||||
|
}
|
||||||
|
transition.setFrame(view: titleView, frame: CGRect(origin: CGPoint(x: 11.0, y: floor((availableSize.height - titleSize.height) / 2.0)), size: titleSize))
|
||||||
|
}
|
||||||
|
|
||||||
|
return availableSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeView() -> View {
|
||||||
|
return View(frame: CGRect())
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
|
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class ForumTopicListComponent: Component {
|
||||||
|
let context: AccountContext
|
||||||
|
let theme: PresentationTheme
|
||||||
|
let strings: PresentationStrings
|
||||||
|
let items: [ForumChannelTopics.Item]
|
||||||
|
let navigationHeight: CGFloat
|
||||||
|
let action: (ForumChannelTopics.Item) -> Void
|
||||||
|
|
||||||
|
init(
|
||||||
|
context: AccountContext,
|
||||||
|
theme: PresentationTheme,
|
||||||
|
strings: PresentationStrings,
|
||||||
|
items: [ForumChannelTopics.Item],
|
||||||
|
navigationHeight: CGFloat,
|
||||||
|
action: @escaping (ForumChannelTopics.Item) -> Void
|
||||||
|
) {
|
||||||
|
self.context = context
|
||||||
|
self.theme = theme
|
||||||
|
self.strings = strings
|
||||||
|
self.items = items
|
||||||
|
self.navigationHeight = navigationHeight
|
||||||
|
self.action = action
|
||||||
|
}
|
||||||
|
|
||||||
|
static func ==(lhs: ForumTopicListComponent, rhs: ForumTopicListComponent) -> Bool {
|
||||||
|
if lhs.context !== rhs.context {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.theme !== rhs.theme {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.strings !== rhs.strings {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.items != rhs.items {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.navigationHeight != rhs.navigationHeight {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
final class View: UIView, UIScrollViewDelegate {
|
||||||
|
private struct ItemLayout {
|
||||||
|
let containerSize: CGSize
|
||||||
|
let itemHeight: CGFloat
|
||||||
|
let contentSize: CGSize
|
||||||
|
let itemsInsets: UIEdgeInsets
|
||||||
|
|
||||||
|
init(containerSize: CGSize, navigationHeight: CGFloat, itemCount: Int) {
|
||||||
|
self.itemHeight = 44.0
|
||||||
|
self.containerSize = containerSize
|
||||||
|
self.itemsInsets = UIEdgeInsets(top: navigationHeight, left: 0.0, bottom: 0.0, right: 0.0)
|
||||||
|
self.contentSize = CGSize(width: containerSize.width, height: self.itemsInsets.top + self.itemsInsets.bottom + CGFloat(itemCount) * self.itemHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
func frame(at index: Int) -> CGRect {
|
||||||
|
return CGRect(origin: CGPoint(x: 0.0, y: self.itemsInsets.top + CGFloat(index) * self.itemHeight), size: CGSize(width: self.containerSize.width, height: self.itemHeight))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class ItemView {
|
||||||
|
let host: ComponentView<Empty>
|
||||||
|
let separatorLayer: SimpleLayer
|
||||||
|
|
||||||
|
init() {
|
||||||
|
self.host = ComponentView()
|
||||||
|
self.separatorLayer = SimpleLayer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private let scrollView: UIScrollView
|
||||||
|
|
||||||
|
private var component: ForumTopicListComponent?
|
||||||
|
private var itemLayout: ItemLayout?
|
||||||
|
|
||||||
|
private var ignoreScrolling: Bool = false
|
||||||
|
private var visibleItemViews: [Int64: ItemView] = [:]
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
self.scrollView = UIScrollView()
|
||||||
|
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
self.scrollView.layer.anchorPoint = CGPoint()
|
||||||
|
self.scrollView.delaysContentTouches = true
|
||||||
|
self.scrollView.clipsToBounds = false
|
||||||
|
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
|
||||||
|
self.scrollView.contentInsetAdjustmentBehavior = .never
|
||||||
|
}
|
||||||
|
if #available(iOS 13.0, *) {
|
||||||
|
self.scrollView.automaticallyAdjustsScrollIndicatorInsets = false
|
||||||
|
}
|
||||||
|
self.scrollView.showsVerticalScrollIndicator = true
|
||||||
|
self.scrollView.showsHorizontalScrollIndicator = false
|
||||||
|
self.scrollView.alwaysBounceHorizontal = false
|
||||||
|
self.scrollView.alwaysBounceVertical = true
|
||||||
|
self.scrollView.scrollsToTop = false
|
||||||
|
self.scrollView.delegate = self
|
||||||
|
self.scrollView.clipsToBounds = true
|
||||||
|
self.scrollView.canCancelContentTouches = true
|
||||||
|
|
||||||
|
self.addSubview(self.scrollView)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
preconditionFailure()
|
||||||
|
}
|
||||||
|
|
||||||
|
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||||
|
if !self.ignoreScrolling {
|
||||||
|
self.updateVisibleItems(transition: .immediate, synchronous: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateVisibleItems(transition: Transition, synchronous: Bool) {
|
||||||
|
guard let component = self.component, let itemLayout = self.itemLayout else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var validIds = Set<Int64>()
|
||||||
|
let visibleBounds = self.scrollView.bounds
|
||||||
|
for index in 0 ..< component.items.count {
|
||||||
|
let itemFrame = itemLayout.frame(at: index)
|
||||||
|
if !visibleBounds.intersects(itemFrame) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let item = component.items[index]
|
||||||
|
validIds.insert(item.id)
|
||||||
|
|
||||||
|
let itemView: ItemView
|
||||||
|
var itemTransition = transition
|
||||||
|
if let current = self.visibleItemViews[item.id] {
|
||||||
|
itemView = current
|
||||||
|
} else {
|
||||||
|
itemTransition = .immediate
|
||||||
|
itemView = ItemView()
|
||||||
|
self.visibleItemViews[item.id] = itemView
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = item.id
|
||||||
|
let _ = itemView.host.update(
|
||||||
|
transition: itemTransition,
|
||||||
|
component: AnyComponent(ForumTopicListItemComponent(
|
||||||
|
context: component.context,
|
||||||
|
theme: component.theme,
|
||||||
|
strings: component.strings,
|
||||||
|
item: item,
|
||||||
|
action: { [weak self] in
|
||||||
|
guard let strongSelf = self, let component = strongSelf.component else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for item in component.items {
|
||||||
|
if item.id == id {
|
||||||
|
component.action(item)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: itemFrame.size
|
||||||
|
)
|
||||||
|
if let itemComponentView = itemView.host.view {
|
||||||
|
if itemComponentView.superview == nil {
|
||||||
|
self.scrollView.addSubview(itemComponentView)
|
||||||
|
self.scrollView.layer.addSublayer(itemView.separatorLayer)
|
||||||
|
}
|
||||||
|
itemTransition.setFrame(view: itemComponentView, frame: itemFrame)
|
||||||
|
|
||||||
|
let separatorInset: CGFloat
|
||||||
|
if index == component.items.count - 1 {
|
||||||
|
separatorInset = 0.0
|
||||||
|
} else {
|
||||||
|
separatorInset = 16.0
|
||||||
|
}
|
||||||
|
itemView.separatorLayer.backgroundColor = component.theme.list.itemPlainSeparatorColor.cgColor
|
||||||
|
itemTransition.setFrame(layer: itemView.separatorLayer, frame: CGRect(origin: CGPoint(x: separatorInset, y: itemFrame.maxY - UIScreenPixel), size: CGSize(width: itemLayout.contentSize.width - separatorInset, height: UIScreenPixel)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var removedIds: [Int64] = []
|
||||||
|
for (id, itemView) in self.visibleItemViews {
|
||||||
|
if !validIds.contains(id) {
|
||||||
|
itemView.host.view?.removeFromSuperview()
|
||||||
|
itemView.separatorLayer.removeFromSuperlayer()
|
||||||
|
removedIds.append(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for id in removedIds {
|
||||||
|
self.visibleItemViews.removeValue(forKey: id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(component: ForumTopicListComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
|
self.component = component
|
||||||
|
|
||||||
|
let itemLayout = ItemLayout(containerSize: availableSize, navigationHeight: component.navigationHeight, itemCount: component.items.count)
|
||||||
|
self.itemLayout = itemLayout
|
||||||
|
|
||||||
|
self.ignoreScrolling = true
|
||||||
|
self.scrollView.frame = CGRect(origin: CGPoint(), size: availableSize)
|
||||||
|
if self.scrollView.contentSize != itemLayout.contentSize {
|
||||||
|
self.scrollView.contentSize = itemLayout.contentSize
|
||||||
|
}
|
||||||
|
if self.scrollView.scrollIndicatorInsets != itemLayout.itemsInsets {
|
||||||
|
self.scrollView.scrollIndicatorInsets = itemLayout.itemsInsets
|
||||||
|
}
|
||||||
|
self.ignoreScrolling = false
|
||||||
|
|
||||||
|
self.updateVisibleItems(transition: transition, synchronous: false)
|
||||||
|
|
||||||
|
return availableSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeView() -> View {
|
||||||
|
return View(frame: CGRect())
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
|
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class ForumTopicListScreen: ViewController {
|
||||||
|
private final class Node: ViewControllerTracingNode {
|
||||||
|
private weak var controller: ForumTopicListScreen?
|
||||||
|
|
||||||
|
private let context: AccountContext
|
||||||
|
private let id: EnginePeer.Id
|
||||||
|
private var presentationData: PresentationData
|
||||||
|
|
||||||
|
private let topicList: ComponentView<Empty>
|
||||||
|
|
||||||
|
private let forumChannelContext: ForumChannelTopics
|
||||||
|
private var stateDisposable: Disposable?
|
||||||
|
private var currentState: ForumChannelTopics.State?
|
||||||
|
|
||||||
|
private var currentLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
|
||||||
|
|
||||||
|
init(controller: ForumTopicListScreen, context: AccountContext, id: EnginePeer.Id) {
|
||||||
|
self.controller = controller
|
||||||
|
|
||||||
|
self.context = context
|
||||||
|
self.id = id
|
||||||
|
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
|
self.topicList = ComponentView()
|
||||||
|
|
||||||
|
self.forumChannelContext = ForumChannelTopics(account: self.context.account, peerId: self.id)
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||||
|
|
||||||
|
self.stateDisposable = (self.forumChannelContext.state
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.currentState = state
|
||||||
|
strongSelf.update(transition: .immediate)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.stateDisposable?.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
func createPressed() {
|
||||||
|
self.forumChannelContext.createTopic(title: "Topic#\(Int.random(in: 0 ..< 100000))")
|
||||||
|
}
|
||||||
|
|
||||||
|
private func update(transition: Transition) {
|
||||||
|
if let currentLayout = self.currentLayout {
|
||||||
|
self.containerLayoutUpdated(layout: currentLayout.layout, navigationHeight: currentLayout.navigationHeight, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: Transition) {
|
||||||
|
self.currentLayout = (layout, navigationHeight)
|
||||||
|
|
||||||
|
let _ = self.topicList.update(
|
||||||
|
transition: transition,
|
||||||
|
component: AnyComponent(ForumTopicListComponent(
|
||||||
|
context: self.context,
|
||||||
|
theme: self.presentationData.theme,
|
||||||
|
strings: self.presentationData.strings,
|
||||||
|
items: self.currentState?.items ?? [],
|
||||||
|
navigationHeight: navigationHeight,
|
||||||
|
action: { [weak self] item in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.controller?.openTopic(item)
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: layout.size
|
||||||
|
)
|
||||||
|
if let topicListView = self.topicList.view {
|
||||||
|
if topicListView.superview == nil {
|
||||||
|
if let navigationBar = self.controller?.navigationBar {
|
||||||
|
self.view.insertSubview(topicListView, belowSubview: navigationBar.view)
|
||||||
|
} else {
|
||||||
|
self.view.addSubview(topicListView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transition.setFrame(view: topicListView, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var node: Node {
|
||||||
|
return self.displayNode as! Node
|
||||||
|
}
|
||||||
|
|
||||||
|
private let context: AccountContext
|
||||||
|
private let id: EnginePeer.Id
|
||||||
|
private var presentationData: PresentationData
|
||||||
|
private let openTopic: (ForumChannelTopics.Item) -> Void
|
||||||
|
|
||||||
|
public init(context: AccountContext, id: EnginePeer.Id, openTopic: @escaping (ForumChannelTopics.Item) -> Void) {
|
||||||
|
self.context = context
|
||||||
|
self.id = id
|
||||||
|
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
self.openTopic = openTopic
|
||||||
|
|
||||||
|
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
|
self.title = "Forum"
|
||||||
|
|
||||||
|
self.navigationItem.setRightBarButton(UIBarButtonItem(title: "Create", style: .plain, target: self, action: #selector(self.createPressed)), animated: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
public required init(coder aDecoder: NSCoder) {
|
||||||
|
preconditionFailure()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func createPressed() {
|
||||||
|
self.node.createPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func loadDisplayNode() {
|
||||||
|
self.displayNode = Node(controller: self, context: self.context, id: self.id)
|
||||||
|
|
||||||
|
self.displayNodeDidLoad()
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
|
super.containerLayoutUpdated(layout, transition: transition)
|
||||||
|
|
||||||
|
self.node.containerLayoutUpdated(layout: layout, navigationHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: Transition(transition))
|
||||||
|
}
|
||||||
|
}
|
@ -82,12 +82,13 @@ private enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
return ChatListItem(
|
return ChatListItem(
|
||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
context: context,
|
context: context,
|
||||||
peerGroupId: .root,
|
chatListLocation: .chatList(groupId: .root),
|
||||||
filterData: nil,
|
filterData: nil,
|
||||||
index: EngineChatList.Item.Index(pinningIndex: nil, messageIndex: message.index),
|
index: .chatList(EngineChatList.Item.Index.ChatList(pinningIndex: nil, messageIndex: message.index)),
|
||||||
content: .peer(
|
content: .peer(
|
||||||
messages: [EngineMessage(message)],
|
messages: [EngineMessage(message)],
|
||||||
peer: EngineRenderedPeer(peer),
|
peer: EngineRenderedPeer(peer),
|
||||||
|
threadInfo: nil,
|
||||||
combinedReadState: readState.flatMap(EnginePeerReadCounters.init),
|
combinedReadState: readState.flatMap(EnginePeerReadCounters.init),
|
||||||
isRemovedFromTotalUnreadCount: false,
|
isRemovedFromTotalUnreadCount: false,
|
||||||
presence: nil,
|
presence: nil,
|
||||||
@ -206,12 +207,12 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
|
|||||||
}
|
}
|
||||||
|
|
||||||
let interaction = ChatListNodeInteraction(context: context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, activateSearch: {
|
let interaction = ChatListNodeInteraction(context: context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, activateSearch: {
|
||||||
}, peerSelected: { _, _, _ in
|
}, peerSelected: { _, _, _, _ in
|
||||||
}, disabledPeerSelected: { _ in
|
}, disabledPeerSelected: { _ in
|
||||||
}, togglePeerSelected: { _ in
|
}, togglePeerSelected: { _ in
|
||||||
}, togglePeersSelection: { _, _ in
|
}, togglePeersSelection: { _, _ in
|
||||||
}, additionalCategorySelected: { _ in
|
}, additionalCategorySelected: { _ in
|
||||||
}, messageSelected: { [weak self] peer, message, _ in
|
}, messageSelected: { [weak self] peer, _, message, _ in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let index = strongSelf.searchResult.messages.firstIndex(where: { $0.index == message.index }) {
|
if let index = strongSelf.searchResult.messages.firstIndex(where: { $0.index == message.index }) {
|
||||||
if message.id.peerId.namespace == Namespaces.Peer.SecretChat {
|
if message.id.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||||
@ -238,7 +239,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(messages, peer, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(messages, peer, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
if let message = messages.first {
|
if let message = messages.first {
|
||||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(id: peer.peerId), subject: .message(id: .id(message.id), highlight: true, timecode: nil), botStart: nil, mode: .standard(previewing: true))
|
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(id: peer.peerId), subject: .message(id: .id(message.id), highlight: true, timecode: nil), botStart: nil, mode: .standard(previewing: true))
|
||||||
chatController.canReadHistory.set(false)
|
chatController.canReadHistory.set(false)
|
||||||
|
@ -96,7 +96,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
if case let .chatSelection(_, selectedChats, additionalCategories, chatListFilters) = mode {
|
if case let .chatSelection(_, selectedChats, additionalCategories, chatListFilters) = mode {
|
||||||
placeholder = self.presentationData.strings.ChatListFilter_AddChatsTitle
|
placeholder = self.presentationData.strings.ChatListFilter_AddChatsTitle
|
||||||
let chatListNode = ChatListNode(context: context, groupId: .root, previewing: false, fillPreloadItems: false, mode: .peers(filter: [.excludeSecretChats], isSelecting: true, additionalCategories: additionalCategories?.categories ?? [], chatListFilters: chatListFilters), theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, animationCache: self.animationCache, animationRenderer: self.animationRenderer, disableAnimations: true)
|
let chatListNode = ChatListNode(context: context, location: .chatList(groupId: .root), previewing: false, fillPreloadItems: false, mode: .peers(filter: [.excludeSecretChats], isSelecting: true, additionalCategories: additionalCategories?.categories ?? [], chatListFilters: chatListFilters), theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, animationCache: self.animationCache, animationRenderer: self.animationRenderer, disableAnimations: true)
|
||||||
if let limit = limit {
|
if let limit = limit {
|
||||||
chatListNode.selectionLimit = limit
|
chatListNode.selectionLimit = limit
|
||||||
chatListNode.reachedSelectionLimit = reachedSelectionLimit
|
chatListNode.reachedSelectionLimit = reachedSelectionLimit
|
||||||
@ -140,7 +140,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
|||||||
self?.openPeer?(peer)
|
self?.openPeer?(peer)
|
||||||
}
|
}
|
||||||
case let .chats(chatsNode):
|
case let .chats(chatsNode):
|
||||||
chatsNode.peerSelected = { [weak self] peer, _, _, _ in
|
chatsNode.peerSelected = { [weak self] peer, _, _, _, _ in
|
||||||
self?.openPeer?(.peer(peer: peer._asPeer(), isGlobal: false, participantCount: nil))
|
self?.openPeer?(.peer(peer: peer._asPeer(), isGlobal: false, participantCount: nil))
|
||||||
}
|
}
|
||||||
chatsNode.additionalCategorySelected = { [weak self] id in
|
chatsNode.additionalCategorySelected = { [weak self] id in
|
||||||
|
@ -425,7 +425,26 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
|||||||
let createSignal: Signal<PeerId?, CreateGroupError>
|
let createSignal: Signal<PeerId?, CreateGroupError>
|
||||||
switch mode {
|
switch mode {
|
||||||
case .generic:
|
case .generic:
|
||||||
createSignal = context.engine.peers.createGroup(title: title, peerIds: peerIds)
|
if title.contains("*forum") {
|
||||||
|
createSignal = context.engine.peers.createSupergroup(title: title, description: nil)
|
||||||
|
|> map(Optional.init)
|
||||||
|
|> mapError { error -> CreateGroupError in
|
||||||
|
switch error {
|
||||||
|
case .generic:
|
||||||
|
return .generic
|
||||||
|
case .restricted:
|
||||||
|
return .restricted
|
||||||
|
case .tooMuchJoined:
|
||||||
|
return .tooMuchJoined
|
||||||
|
case .tooMuchLocationBasedGroups:
|
||||||
|
return .tooMuchLocationBasedGroups
|
||||||
|
case let .serverProvided(error):
|
||||||
|
return .serverProvided(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
createSignal = context.engine.peers.createGroup(title: title, peerIds: peerIds)
|
||||||
|
}
|
||||||
case .supergroup:
|
case .supergroup:
|
||||||
createSignal = context.engine.peers.createSupergroup(title: title, description: nil)
|
createSignal = context.engine.peers.createSupergroup(title: title, description: nil)
|
||||||
|> map(Optional.init)
|
|> map(Optional.init)
|
||||||
|
@ -12,6 +12,7 @@ import PeerAvatarGalleryUI
|
|||||||
import SettingsUI
|
import SettingsUI
|
||||||
import ChatPresentationInterfaceState
|
import ChatPresentationInterfaceState
|
||||||
import AttachmentUI
|
import AttachmentUI
|
||||||
|
import ForumTopicListScreen
|
||||||
|
|
||||||
public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParams) {
|
public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParams) {
|
||||||
var found = false
|
var found = false
|
||||||
@ -222,3 +223,28 @@ public func isOverlayControllerForChatNotificationOverlayPresentation(_ controll
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func navigateToForumThreadImpl(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64, navigationController: NavigationController) -> Signal<Never, NoError> {
|
||||||
|
return fetchAndPreloadReplyThreadInfo(context: context, subject: .groupMessage(MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId))), atMessageId: nil)
|
||||||
|
|> deliverOnMainQueue
|
||||||
|
|> beforeNext { [weak context, weak navigationController] result in
|
||||||
|
guard let context = context, let navigationController = navigationController else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let chatLocation: ChatLocation = .replyThread(message: result.message)
|
||||||
|
|
||||||
|
let subject: ChatControllerSubject?
|
||||||
|
subject = nil
|
||||||
|
|
||||||
|
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: chatLocation, chatLocationContextHolder: result.contextHolder, subject: subject, activateInput: result.isEmpty ? .text : nil, keepStack: .always))
|
||||||
|
}
|
||||||
|
|> ignoreValues
|
||||||
|
|> `catch` { _ -> Signal<Never, NoError> in
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func navigateToForumChannelImpl(context: AccountContext, peerId: EnginePeer.Id, navigationController: NavigationController) {
|
||||||
|
navigationController.pushViewController(ChatListControllerImpl(context: context, location: .forum(peerId: peerId), controlsHistoryPreload: false, enableDebugActions: false))
|
||||||
|
}
|
||||||
|
@ -128,7 +128,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
chatListCategories.append(ChatListNodeAdditionalCategory(id: 0, icon: PresentationResourcesItemList.createGroupIcon(self.presentationData.theme), title: self.presentationData.strings.PeerSelection_ImportIntoNewGroup, appearance: .action))
|
chatListCategories.append(ChatListNodeAdditionalCategory(id: 0, icon: PresentationResourcesItemList.createGroupIcon(self.presentationData.theme), title: self.presentationData.strings.PeerSelection_ImportIntoNewGroup, appearance: .action))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.chatListNode = ChatListNode(context: context, groupId: .root, previewing: false, fillPreloadItems: false, mode: .peers(filter: filter, isSelecting: false, additionalCategories: chatListCategories, chatListFilters: nil), theme: self.presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, animationCache: self.animationCache, animationRenderer: self.animationRenderer, disableAnimations: true)
|
self.chatListNode = ChatListNode(context: context, location: .chatList(groupId: .root), previewing: false, fillPreloadItems: false, mode: .peers(filter: filter, isSelecting: false, additionalCategories: chatListCategories, chatListFilters: nil), theme: self.presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, animationCache: self.animationCache, animationRenderer: self.animationRenderer, disableAnimations: true)
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
self?.requestActivateSearch?()
|
self?.requestActivateSearch?()
|
||||||
}
|
}
|
||||||
|
|
||||||
self.chatListNode.peerSelected = { [weak self] peer, _, _, _ in
|
self.chatListNode.peerSelected = { [weak self] peer, _, _, _, _ in
|
||||||
self?.chatListNode.clearHighlightAnimated(true)
|
self?.chatListNode.clearHighlightAnimated(true)
|
||||||
self?.requestOpenPeer?(peer._asPeer())
|
self?.requestOpenPeer?(peer._asPeer())
|
||||||
}
|
}
|
||||||
|
@ -1155,6 +1155,14 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
navigateToChatControllerImpl(params)
|
navigateToChatControllerImpl(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func navigateToForumChannel(context: AccountContext, peerId: EnginePeer.Id, navigationController: NavigationController) {
|
||||||
|
navigateToForumChannelImpl(context: context, peerId: peerId, navigationController: navigationController)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func navigateToForumThread(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64, navigationController: NavigationController) -> Signal<Never, NoError> {
|
||||||
|
return navigateToForumThreadImpl(context: context, peerId: peerId, threadId: threadId, navigationController: navigationController)
|
||||||
|
}
|
||||||
|
|
||||||
public func openStorageUsage(context: AccountContext) {
|
public func openStorageUsage(context: AccountContext) {
|
||||||
guard let navigationController = self.mainWindow?.viewController as? NavigationController else {
|
guard let navigationController = self.mainWindow?.viewController as? NavigationController else {
|
||||||
return
|
return
|
||||||
@ -1263,7 +1271,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func makeChatListController(context: AccountContext, groupId: PeerGroupId, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool, previewing: Bool, enableDebugActions: Bool) -> ChatListController {
|
public func makeChatListController(context: AccountContext, groupId: PeerGroupId, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool, previewing: Bool, enableDebugActions: Bool) -> ChatListController {
|
||||||
return ChatListControllerImpl(context: context, groupId: groupId, controlsHistoryPreload: controlsHistoryPreload, hideNetworkActivityStatus: hideNetworkActivityStatus, previewing: previewing, enableDebugActions: enableDebugActions)
|
return ChatListControllerImpl(context: context, location: .chatList(groupId: EngineChatList.Group(groupId)), controlsHistoryPreload: controlsHistoryPreload, hideNetworkActivityStatus: hideNetworkActivityStatus, previewing: previewing, enableDebugActions: enableDebugActions)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makePeerSelectionController(_ params: PeerSelectionControllerParams) -> PeerSelectionController {
|
public func makePeerSelectionController(_ params: PeerSelectionControllerParams) -> PeerSelectionController {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user