mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-03 05:03:45 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
e2388c072d
@ -38,7 +38,7 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi
|
||||
|
||||
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
|
||||
|
||||
self.impl = NotificationViewControllerImpl(initializationData: NotificationViewControllerInitializationData(appBundleId: baseAppBundleId, appGroupPath: appGroupUrl.path, apiId: buildConfig.apiId, apiHash: buildConfig.apiHash, languagesCategory: languagesCategory, encryptionParameters: encryptionParameters, appVersion: appVersion, bundleData: buildConfig.bundleData(withAppToken: nil, signatureDict: nil)), setPreferredContentSize: { [weak self] size in
|
||||
self.impl = NotificationViewControllerImpl(initializationData: NotificationViewControllerInitializationData(appBundleId: baseAppBundleId, appBuildType: buildConfig.isAppStoreBuild ? .public : .internal, appGroupPath: appGroupUrl.path, apiId: buildConfig.apiId, apiHash: buildConfig.apiHash, languagesCategory: languagesCategory, encryptionParameters: encryptionParameters, appVersion: appVersion, bundleData: buildConfig.bundleData(withAppToken: nil, signatureDict: nil)), setPreferredContentSize: { [weak self] size in
|
||||
self?.preferredContentSize = size
|
||||
})
|
||||
}
|
||||
|
||||
@ -577,6 +577,31 @@ private struct NotificationContent: CustomStringConvertible {
|
||||
}
|
||||
}
|
||||
|
||||
private func getCurrentRenderedTotalUnreadCount(accountManager: AccountManager<TelegramAccountManagerTypes>, postbox: Postbox) -> Signal<(Int32, RenderedTotalUnreadCountType), NoError> {
|
||||
let counters = postbox.transaction { transaction -> ChatListTotalUnreadState in
|
||||
return transaction.getTotalUnreadState(groupId: .root)
|
||||
}
|
||||
return combineLatest(
|
||||
accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.inAppNotificationSettings])
|
||||
|> take(1),
|
||||
counters
|
||||
)
|
||||
|> map { sharedData, totalReadCounters -> (Int32, RenderedTotalUnreadCountType) in
|
||||
let inAppSettings: InAppNotificationSettings
|
||||
if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings]?.get(InAppNotificationSettings.self) {
|
||||
inAppSettings = value
|
||||
} else {
|
||||
inAppSettings = .defaultSettings
|
||||
}
|
||||
let type: RenderedTotalUnreadCountType
|
||||
switch inAppSettings.totalUnreadCountDisplayStyle {
|
||||
case .filtered:
|
||||
type = .filtered
|
||||
}
|
||||
return (totalReadCounters.count(for: inAppSettings.totalUnreadCountDisplayStyle.category, in: inAppSettings.totalUnreadCountDisplayCategory.statsType, with: inAppSettings.totalUnreadCountIncludeTags), type)
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension 10.0, iOS 10.0, *)
|
||||
private final class NotificationServiceHandler {
|
||||
private let queue: Queue
|
||||
|
||||
@ -45,7 +45,7 @@ class ShareRootController: UIViewController {
|
||||
|
||||
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
|
||||
|
||||
self.impl = ShareRootControllerImpl(initializationData: ShareRootControllerInitializationData(appBundleId: baseAppBundleId, appGroupPath: appGroupUrl.path, apiId: buildConfig.apiId, apiHash: buildConfig.apiHash, languagesCategory: languagesCategory, encryptionParameters: encryptionParameters, appVersion: appVersion, bundleData: buildConfig.bundleData(withAppToken: nil, signatureDict: nil)), getExtensionContext: { [weak self] in
|
||||
self.impl = ShareRootControllerImpl(initializationData: ShareRootControllerInitializationData(appBundleId: baseAppBundleId, appBuildType: buildConfig.isAppStoreBuild ? .public : .internal, appGroupPath: appGroupUrl.path, apiId: buildConfig.apiId, apiHash: buildConfig.apiHash, languagesCategory: languagesCategory, encryptionParameters: encryptionParameters, appVersion: appVersion, bundleData: buildConfig.bundleData(withAppToken: nil, signatureDict: nil)), getExtensionContext: { [weak self] in
|
||||
return self?.extensionContext
|
||||
})
|
||||
}
|
||||
|
||||
@ -29,9 +29,15 @@ public enum AccessType {
|
||||
case unreachable
|
||||
}
|
||||
|
||||
public enum TelegramAppBuildType {
|
||||
case `internal`
|
||||
case `public`
|
||||
}
|
||||
|
||||
public final class TelegramApplicationBindings {
|
||||
public let isMainApp: Bool
|
||||
public let appBundleId: String
|
||||
public let appBuildType: TelegramAppBuildType
|
||||
public let containerPath: String
|
||||
public let appSpecificScheme: String
|
||||
public let openUrl: (String) -> Void
|
||||
@ -56,9 +62,10 @@ public final class TelegramApplicationBindings {
|
||||
public let requestSetAlternateIconName: (String?, @escaping (Bool) -> Void) -> Void
|
||||
public let forceOrientation: (UIInterfaceOrientation) -> Void
|
||||
|
||||
public init(isMainApp: Bool, appBundleId: String, containerPath: String, appSpecificScheme: String, openUrl: @escaping (String) -> Void, openUniversalUrl: @escaping (String, TelegramApplicationOpenUrlCompletion) -> Void, canOpenUrl: @escaping (String) -> Bool, getTopWindow: @escaping () -> UIWindow?, displayNotification: @escaping (String) -> Void, applicationInForeground: Signal<Bool, NoError>, applicationIsActive: Signal<Bool, NoError>, clearMessageNotifications: @escaping ([MessageId]) -> Void, pushIdleTimerExtension: @escaping () -> Disposable, openSettings: @escaping () -> Void, openAppStorePage: @escaping () -> Void, registerForNotifications: @escaping (@escaping (Bool) -> Void) -> Void, requestSiriAuthorization: @escaping (@escaping (Bool) -> Void) -> Void, siriAuthorization: @escaping () -> AccessType, getWindowHost: @escaping () -> WindowHost?, presentNativeController: @escaping (UIViewController) -> Void, dismissNativeController: @escaping () -> Void, getAvailableAlternateIcons: @escaping () -> [PresentationAppIcon], getAlternateIconName: @escaping () -> String?, requestSetAlternateIconName: @escaping (String?, @escaping (Bool) -> Void) -> Void, forceOrientation: @escaping (UIInterfaceOrientation) -> Void) {
|
||||
public init(isMainApp: Bool, appBundleId: String, appBuildType: TelegramAppBuildType, containerPath: String, appSpecificScheme: String, openUrl: @escaping (String) -> Void, openUniversalUrl: @escaping (String, TelegramApplicationOpenUrlCompletion) -> Void, canOpenUrl: @escaping (String) -> Bool, getTopWindow: @escaping () -> UIWindow?, displayNotification: @escaping (String) -> Void, applicationInForeground: Signal<Bool, NoError>, applicationIsActive: Signal<Bool, NoError>, clearMessageNotifications: @escaping ([MessageId]) -> Void, pushIdleTimerExtension: @escaping () -> Disposable, openSettings: @escaping () -> Void, openAppStorePage: @escaping () -> Void, registerForNotifications: @escaping (@escaping (Bool) -> Void) -> Void, requestSiriAuthorization: @escaping (@escaping (Bool) -> Void) -> Void, siriAuthorization: @escaping () -> AccessType, getWindowHost: @escaping () -> WindowHost?, presentNativeController: @escaping (UIViewController) -> Void, dismissNativeController: @escaping () -> Void, getAvailableAlternateIcons: @escaping () -> [PresentationAppIcon], getAlternateIconName: @escaping () -> String?, requestSetAlternateIconName: @escaping (String?, @escaping (Bool) -> Void) -> Void, forceOrientation: @escaping (UIInterfaceOrientation) -> Void) {
|
||||
self.isMainApp = isMainApp
|
||||
self.appBundleId = appBundleId
|
||||
self.appBuildType = appBuildType
|
||||
self.containerPath = containerPath
|
||||
self.appSpecificScheme = appSpecificScheme
|
||||
self.openUrl = openUrl
|
||||
|
||||
@ -94,9 +94,9 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
|
||||
return context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.IsContact(id: peer.id),
|
||||
TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: peer.id),
|
||||
TelegramEngine.EngineData.Item.Messages.ReadState(id: peer.id)
|
||||
TelegramEngine.EngineData.Item.Messages.PeerReadCounters(id: peer.id)
|
||||
)
|
||||
|> map { [weak chatListController] isContact, notificationSettings, readState -> [ContextMenuItem] in
|
||||
|> map { [weak chatListController] isContact, notificationSettings, readCounters -> [ContextMenuItem] in
|
||||
if promoInfo != nil {
|
||||
return []
|
||||
}
|
||||
@ -160,7 +160,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
|
||||
}
|
||||
|
||||
var isUnread = false
|
||||
if let readState = readState, readState.isUnread {
|
||||
if readCounters.isUnread {
|
||||
isUnread = true
|
||||
}
|
||||
|
||||
|
||||
@ -1954,29 +1954,14 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
|
||||
private var initializedFilters = false
|
||||
private func reloadFilters(firstUpdate: (() -> Void)? = nil) {
|
||||
let preferencesKey: PostboxViewKey = .preferences(keys: Set([
|
||||
ApplicationSpecificPreferencesKeys.chatListFilterSettings
|
||||
]))
|
||||
let experimentalUISettingsKey: ValueBoxKey = ApplicationSpecificSharedDataKeys.experimentalUISettings
|
||||
let displayTabsAtBottom = self.context.sharedContext.accountManager.sharedData(keys: Set([experimentalUISettingsKey]))
|
||||
|> map { sharedData -> Bool in
|
||||
let settings: ExperimentalUISettings = sharedData.entries[experimentalUISettingsKey]?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings
|
||||
return settings.foldersTabAtBottom
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
let filterItems = chatListFilterItems(context: self.context)
|
||||
var notifiedFirstUpdate = false
|
||||
self.filterDisposable.set((combineLatest(queue: .mainQueue(),
|
||||
self.context.account.postbox.combinedView(keys: [
|
||||
preferencesKey
|
||||
]),
|
||||
filterItems,
|
||||
displayTabsAtBottom,
|
||||
self.context.account.postbox.peerView(id: self.context.account.peerId),
|
||||
self.context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: false))
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] _, countAndFilterItems, displayTabsAtBottom, peerView, limits in
|
||||
|> deliverOnMainQueue).start(next: { [weak self] countAndFilterItems, peerView, limits in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -2044,7 +2029,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
}
|
||||
let filtersLimit = isPremium == false ? limits.maxFoldersCount : nil
|
||||
strongSelf.tabContainerData = (resolvedItems, displayTabsAtBottom, filtersLimit)
|
||||
strongSelf.tabContainerData = (resolvedItems, false, filtersLimit)
|
||||
var availableFilters: [ChatListContainerNodeFilter] = []
|
||||
var hasAllChats = false
|
||||
for item in items {
|
||||
@ -2080,7 +2065,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
strongSelf.initializedFilters = true
|
||||
}
|
||||
|
||||
let isEmpty = resolvedItems.count <= 1 || displayTabsAtBottom
|
||||
let isEmpty = resolvedItems.count <= 1
|
||||
|
||||
let animated = strongSelf.didSetupTabs
|
||||
strongSelf.didSetupTabs = true
|
||||
|
||||
@ -29,39 +29,26 @@ func chatListSelectionOptions(context: AccountContext, peerIds: Set<PeerId>, fil
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
} else {
|
||||
let key = PostboxViewKey.unreadCounts(items: [.total(nil)])
|
||||
return context.account.postbox.combinedView(keys: [key])
|
||||
|> map { view -> ChatListSelectionOptions in
|
||||
return context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.TotalReadCounters())
|
||||
|> map { readCounters -> ChatListSelectionOptions in
|
||||
var hasUnread = false
|
||||
if let unreadCounts = view.views[key] as? UnreadMessageCountsView, let total = unreadCounts.total() {
|
||||
for (_, counter) in total.1.absoluteCounters {
|
||||
if counter.messageCount != 0 {
|
||||
hasUnread = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if readCounters.count(for: .filtered, in: .chats, with: .all) != 0 {
|
||||
hasUnread = true
|
||||
}
|
||||
return ChatListSelectionOptions(read: .all(enabled: hasUnread), delete: false)
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
}
|
||||
} else {
|
||||
let items: [UnreadMessageCountsItem] = peerIds.map(UnreadMessageCountsItem.peer)
|
||||
let key = PostboxViewKey.unreadCounts(items: items)
|
||||
return context.account.postbox.combinedView(keys: [key])
|
||||
|> map { view -> ChatListSelectionOptions in
|
||||
return context.engine.data.subscribe(EngineDataList(
|
||||
peerIds.map(TelegramEngine.EngineData.Item.Messages.PeerReadCounters.init)
|
||||
))
|
||||
|> map { readCounters -> ChatListSelectionOptions in
|
||||
var hasUnread = false
|
||||
if let unreadCounts = view.views[key] as? UnreadMessageCountsView {
|
||||
loop: for entry in unreadCounts.entries {
|
||||
switch entry {
|
||||
case let .peer(_, state):
|
||||
if let state = state, state.isUnread {
|
||||
hasUnread = true
|
||||
break loop
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
for counters in readCounters {
|
||||
if counters.isUnread {
|
||||
hasUnread = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return ChatListSelectionOptions(read: .selective(enabled: hasUnread), delete: true)
|
||||
|
||||
@ -120,7 +120,10 @@ public func debugAccountsController(context: AccountContext, accountManager: Acc
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: "Production", color: .accent, action: {
|
||||
dismissAction()
|
||||
context.sharedContext.beginNewAuth(testingEnvironment: false)
|
||||
|
||||
if case .internal = context.sharedContext.applicationBindings.appBuildType {
|
||||
context.sharedContext.beginNewAuth(testingEnvironment: false)
|
||||
}
|
||||
}),
|
||||
ActionSheetButtonItem(title: "Test", color: .accent, action: {
|
||||
dismissAction()
|
||||
|
||||
@ -762,11 +762,10 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
transaction.clearNotices()
|
||||
}).start()
|
||||
if let context = arguments.context {
|
||||
let _ = (context.account.postbox.transaction { transaction -> Void in
|
||||
transaction.clearItemCacheCollection(collectionId: Namespaces.CachedItemCollection.cachedPollResults)
|
||||
|
||||
transaction.clearItemCacheCollection(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks)
|
||||
}).start()
|
||||
let _ = context.engine.itemCache.clear(collectionIds: [
|
||||
Namespaces.CachedItemCollection.cachedPollResults,
|
||||
Namespaces.CachedItemCollection.cachedStickerPacks
|
||||
]).start()
|
||||
|
||||
let _ = context.engine.peers.unmarkChatListFeaturedFiltersAsSeen()
|
||||
}
|
||||
@ -846,12 +845,10 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
let presentationData = arguments.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
|
||||
arguments.presentController(controller, nil)
|
||||
let _ = (context.account.postbox.transaction { transaction -> Void in
|
||||
transaction.addHolesEverywhere(peerNamespaces: [Namespaces.Peer.CloudUser, Namespaces.Peer.CloudGroup, Namespaces.Peer.CloudChannel], holeNamespace: Namespaces.Message.Cloud)
|
||||
}
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
controller.dismiss()
|
||||
})
|
||||
let _ = (context.engine.messages.debugAddHoles()
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
controller.dismiss()
|
||||
})
|
||||
})
|
||||
case .reindexUnread:
|
||||
return ItemListActionItem(presentationData: presentationData, title: "Reindex Unread Counters", kind: .destructive, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||
@ -861,9 +858,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
let presentationData = arguments.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
|
||||
arguments.presentController(controller, nil)
|
||||
let _ = (context.account.postbox.transaction { transaction -> Void in
|
||||
transaction.reindexUnreadCounters()
|
||||
}
|
||||
let _ = (context.engine.messages.debugReindexUnreadCounters()
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
controller.dismiss()
|
||||
})
|
||||
|
||||
@ -608,14 +608,13 @@ private final class PictureInPictureContentImpl: NSObject, PictureInPictureConte
|
||||
}
|
||||
|
||||
if let (messageId, _) = hiddenMedia {
|
||||
self.messageRemovedDisposable = (context.account.postbox.combinedView(keys: [PostboxViewKey.messages([messageId])])
|
||||
|> map { views -> Bool in
|
||||
if let view = views.views[PostboxViewKey.messages([messageId])] as? MessagesView {
|
||||
if view.messages[messageId] == nil {
|
||||
return true
|
||||
}
|
||||
self.messageRemovedDisposable = (context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.Message(id: messageId))
|
||||
|> map { message -> Bool in
|
||||
if let _ = message {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|> filter { $0 }
|
||||
|> take(1)
|
||||
@ -2247,16 +2246,12 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
|
||||
let shouldBeDismissed: Signal<Bool, NoError>
|
||||
if let contentInfo = item.contentInfo, case let .message(message) = contentInfo {
|
||||
let viewKey = PostboxViewKey.messages(Set([message.id]))
|
||||
shouldBeDismissed = context.account.postbox.combinedView(keys: [viewKey])
|
||||
|> map { views -> Bool in
|
||||
guard let view = views.views[viewKey] as? MessagesView else {
|
||||
shouldBeDismissed = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.Message(id: message.id))
|
||||
|> map { message -> Bool in
|
||||
if let _ = message {
|
||||
return false
|
||||
}
|
||||
if view.messages.isEmpty {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
@ -21,13 +21,13 @@ public enum AvatarGalleryEntryId: Hashable {
|
||||
case resource(String)
|
||||
}
|
||||
|
||||
public func peerInfoProfilePhotos(context: AccountContext, peerId: PeerId) -> Signal<Any, NoError> {
|
||||
return context.account.postbox.combinedView(keys: [.basicPeer(peerId)])
|
||||
|> mapToSignal { view -> Signal<[AvatarGalleryEntry]?, NoError> in
|
||||
guard let peer = (view.views[.basicPeer(peerId)] as? BasicPeerView)?.peer else {
|
||||
public func peerInfoProfilePhotos(context: AccountContext, peerId: EnginePeer.Id) -> Signal<Any, NoError> {
|
||||
return context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
|> mapToSignal { peer -> Signal<[AvatarGalleryEntry]?, NoError> in
|
||||
guard let peer = peer else {
|
||||
return .single(nil)
|
||||
}
|
||||
return initialAvatarGalleryEntries(account: context.account, engine: context.engine, peer: peer)
|
||||
return initialAvatarGalleryEntries(account: context.account, engine: context.engine, peer: peer._asPeer())
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|> mapToSignal { entries -> Signal<(Bool, [AvatarGalleryEntry])?, NoError> in
|
||||
|
||||
@ -78,7 +78,7 @@ private enum ChannelAdminEntryStableId: Hashable {
|
||||
}
|
||||
|
||||
private enum ChannelAdminEntry: ItemListNodeEntry {
|
||||
case info(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer, TelegramUserPresence?)
|
||||
case info(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, EnginePeer, EnginePeer.Presence?)
|
||||
case rankTitle(PresentationTheme, String, Int32?, Int32)
|
||||
case rank(PresentationTheme, PresentationStrings, String, String, Bool)
|
||||
case rankInfo(PresentationTheme, String, Bool)
|
||||
@ -144,7 +144,7 @@ private enum ChannelAdminEntry: ItemListNodeEntry {
|
||||
if lhsDateTimeFormat != rhsDateTimeFormat {
|
||||
return false
|
||||
}
|
||||
if !arePeersEqual(lhsPeer, rhsPeer) {
|
||||
if lhsPeer != rhsPeer {
|
||||
return false
|
||||
}
|
||||
if lhsPresence != rhsPresence {
|
||||
@ -309,7 +309,7 @@ private enum ChannelAdminEntry: ItemListNodeEntry {
|
||||
let arguments = arguments as! ChannelAdminControllerArguments
|
||||
switch self {
|
||||
case let .info(_, _, dateTimeFormat, peer, presence):
|
||||
return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .generic, peer: EnginePeer(peer), presence: presence.flatMap(EnginePeer.Presence.init), memberCount: nil, state: ItemListAvatarAndNameInfoItemState(), sectionId: self.section, style: .blocks(withTopInset: true, withExtendedBottomInset: false), editingNameUpdated: { _ in
|
||||
return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .generic, peer: peer, presence: presence, memberCount: nil, state: ItemListAvatarAndNameInfoItemState(), sectionId: self.section, style: .blocks(withTopInset: true, withExtendedBottomInset: false), editingNameUpdated: { _ in
|
||||
}, avatarTapped: {
|
||||
})
|
||||
case let .rankTitle(_, text, count, limit):
|
||||
@ -534,11 +534,11 @@ private func areAllAdminRightsEnabled(_ flags: TelegramChatAdminRightsFlags, gro
|
||||
}
|
||||
}
|
||||
|
||||
private func channelAdminControllerEntries(presentationData: PresentationData, state: ChannelAdminControllerState, accountPeerId: PeerId, channelView: PeerView, adminView: PeerView, initialParticipant: ChannelParticipant?, invite: Bool, canEdit: Bool) -> [ChannelAdminEntry] {
|
||||
private func channelAdminControllerEntries(presentationData: PresentationData, state: ChannelAdminControllerState, accountPeerId: PeerId, channelPeer: EnginePeer?, adminPeer: EnginePeer?, adminPresence: EnginePeer.Presence?, initialParticipant: ChannelParticipant?, invite: Bool, canEdit: Bool) -> [ChannelAdminEntry] {
|
||||
var entries: [ChannelAdminEntry] = []
|
||||
|
||||
if let channel = channelView.peers[channelView.peerId] as? TelegramChannel, let admin = adminView.peers[adminView.peerId] {
|
||||
entries.append(.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, admin, adminView.peerPresences[admin.id] as? TelegramUserPresence))
|
||||
if case let .channel(channel) = channelPeer, let admin = adminPeer {
|
||||
entries.append(.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, admin, adminPresence))
|
||||
|
||||
var isChannel = false
|
||||
if case .broadcast = channel.info {
|
||||
@ -618,7 +618,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let adminPeer = adminView.peers[adminView.peerId] as? TelegramUser, adminPeer.botInfo != nil, case .group = channel.info, invite, let channelPeer = channelView.peers[channelView.peerId], canEditAdminRights(accountPeerId: accountPeerId, channelPeer: channelPeer, initialParticipant: initialParticipant) {
|
||||
if case let .user(adminPeer) = adminPeer, adminPeer.botInfo != nil, case .group = channel.info, invite, let channelPeer = channelPeer, canEditAdminRights(accountPeerId: accountPeerId, channelPeer: channelPeer._asPeer(), initialParticipant: initialParticipant) {
|
||||
if let initialParticipant = initialParticipant, case let .member(_, _, adminInfo, _, _) = initialParticipant, adminInfo != nil {
|
||||
|
||||
} else {
|
||||
@ -629,7 +629,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
if !invite || state.adminRights {
|
||||
entries.append(.rightsTitle(presentationData.theme, presentationData.strings.Channel_EditAdmin_PermissionsHeader))
|
||||
|
||||
if let channelPeer = channelView.peers[channelView.peerId], canEditAdminRights(accountPeerId: accountPeerId, channelPeer: channelPeer, initialParticipant: initialParticipant) {
|
||||
if let channelPeer = channelPeer, canEditAdminRights(accountPeerId: accountPeerId, channelPeer: channelPeer._asPeer(), initialParticipant: initialParticipant) {
|
||||
let accountUserRightsFlags: TelegramChatAdminRightsFlags
|
||||
if channel.flags.contains(.isCreator) {
|
||||
accountUserRightsFlags = maskRightsFlags
|
||||
@ -660,7 +660,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
entries.append(.addAdminsInfo(presentationData.theme, currentRightsFlags.contains(.canAddAdmins) ? presentationData.strings.Channel_EditAdmin_PermissinAddAdminOn : presentationData.strings.Channel_EditAdmin_PermissinAddAdminOff))
|
||||
}
|
||||
|
||||
if let admin = admin as? TelegramUser, admin.botInfo == nil && !admin.isDeleted && channel.flags.contains(.isCreator) && areAllAdminRightsEnabled(currentRightsFlags, group: isGroup, except: .canBeAnonymous) {
|
||||
if case let .user(admin) = admin, admin.botInfo == nil && !admin.isDeleted && channel.flags.contains(.isCreator) && areAllAdminRightsEnabled(currentRightsFlags, group: isGroup, except: .canBeAnonymous) {
|
||||
canTransfer = true
|
||||
}
|
||||
|
||||
@ -717,8 +717,8 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
if canDismiss {
|
||||
entries.append(.dismiss(presentationData.theme, presentationData.strings.Channel_Moderator_AccessLevelRevoke))
|
||||
}
|
||||
} else if let group = channelView.peers[channelView.peerId] as? TelegramGroup, let admin = adminView.peers[adminView.peerId] {
|
||||
entries.append(.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, admin, adminView.peerPresences[admin.id] as? TelegramUserPresence))
|
||||
} else if case let .legacyGroup(group) = channelPeer, let admin = adminPeer {
|
||||
entries.append(.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, admin, adminPresence))
|
||||
|
||||
var isCreator = false
|
||||
if let initialParticipant = initialParticipant, case .creator = initialParticipant {
|
||||
@ -738,7 +738,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
entries.append(.rankTitle(presentationData.theme, presentationData.strings.Group_EditAdmin_RankTitle.uppercased(), rankEnabled && state.focusedOnRank ? Int32(currentRank?.count ?? 0) : nil, rankMaxLength))
|
||||
entries.append(.rank(presentationData.theme, presentationData.strings, isCreator ? presentationData.strings.Group_EditAdmin_RankOwnerPlaceholder : presentationData.strings.Group_EditAdmin_RankAdminPlaceholder, currentRank ?? "", rankEnabled))
|
||||
} else {
|
||||
if let adminPeer = adminView.peers[adminView.peerId] as? TelegramUser, adminPeer.botInfo != nil, invite {
|
||||
if case let .user(adminPeer) = adminPeer, adminPeer.botInfo != nil, invite {
|
||||
if let initialParticipant = initialParticipant, case let .member(_, _, adminRights, _, _) = initialParticipant, adminRights != nil {
|
||||
|
||||
} else {
|
||||
@ -791,7 +791,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
||||
entries.append(.addAdminsInfo(presentationData.theme, currentRightsFlags.contains(.canAddAdmins) ? presentationData.strings.Channel_EditAdmin_PermissinAddAdminOn : presentationData.strings.Channel_EditAdmin_PermissinAddAdminOff))
|
||||
}
|
||||
|
||||
if let admin = admin as? TelegramUser, case .creator = group.role, admin.botInfo == nil && !admin.isDeleted && areAllAdminRightsEnabled(currentRightsFlags, group: true, except: .canBeAnonymous) {
|
||||
if case let .user(admin) = admin, case .creator = group.role, admin.botInfo == nil && !admin.isDeleted && areAllAdminRightsEnabled(currentRightsFlags, group: true, except: .canBeAnonymous) {
|
||||
entries.append(.transfer(presentationData.theme, presentationData.strings.Group_EditAdmin_TransferOwnership))
|
||||
}
|
||||
|
||||
@ -955,15 +955,23 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
|
||||
errorImpl?()
|
||||
})
|
||||
|
||||
let combinedView = context.account.postbox.combinedView(keys: [.peer(peerId: peerId, components: .all), .peer(peerId: adminId, components: .all)])
|
||||
|
||||
let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData
|
||||
let signal = combineLatest(presentationData, statePromise.get(), combinedView)
|
||||
let signal = combineLatest(
|
||||
queue: .mainQueue(),
|
||||
presentationData,
|
||||
statePromise.get(),
|
||||
context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId),
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: adminId),
|
||||
TelegramEngine.EngineData.Item.Peer.Presence(id: adminId)
|
||||
)
|
||||
)
|
||||
|> deliverOnMainQueue
|
||||
|> map { presentationData, state, combinedView -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
let channelView = combinedView.views[.peer(peerId: peerId, components: .all)] as! PeerView
|
||||
let adminView = combinedView.views[.peer(peerId: adminId, components: .all)] as! PeerView
|
||||
let canEdit = canEditAdminRights(accountPeerId: context.account.peerId, channelPeer: channelView.peers[channelView.peerId]!, initialParticipant: initialParticipant)
|
||||
|> map { presentationData, state, peerInfoData -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
let channelPeer = peerInfoData.0.flatMap { $0 }
|
||||
let adminPeer = peerInfoData.1.flatMap { $0 }
|
||||
let adminPresence = peerInfoData.2
|
||||
let canEdit = canEditAdminRights(accountPeerId: context.account.peerId, channelPeer: channelPeer!._asPeer(), initialParticipant: initialParticipant)
|
||||
|
||||
let leftNavigationButton: ItemListNavigationButton
|
||||
if canEdit {
|
||||
@ -986,8 +994,9 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
|
||||
updateState { current in
|
||||
return current.withUpdatedUpdating(true)
|
||||
}
|
||||
if let channel = channelView.peers[channelView.peerId] as? TelegramChannel {
|
||||
updateRightsDisposable.set((context.engine.peers.addChannelMember(peerId: peerId, memberId: adminId) |> deliverOnMainQueue).start(error: { error in
|
||||
if case let .channel(channel) = channelPeer {
|
||||
updateRightsDisposable.set((context.engine.peers.addChannelMember(peerId: peerId, memberId: adminId)
|
||||
|> deliverOnMainQueue).start(error: { error in
|
||||
updateState { current in
|
||||
return current.withUpdatedUpdating(false)
|
||||
}
|
||||
@ -998,12 +1007,12 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
|
||||
case .tooMuchJoined:
|
||||
text = presentationData.strings.Group_ErrorSupergroupConversionNotPossible
|
||||
case .restricted:
|
||||
if let admin = adminView.peers[adminView.peerId] {
|
||||
if let admin = adminPeer {
|
||||
switch channel.info {
|
||||
case .broadcast:
|
||||
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToChannelError(EnginePeer(admin).compactDisplayTitle, EnginePeer(admin).compactDisplayTitle).string
|
||||
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToChannelError(admin.compactDisplayTitle, admin.compactDisplayTitle).string
|
||||
case .group:
|
||||
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(admin).compactDisplayTitle, EnginePeer(admin).compactDisplayTitle).string
|
||||
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(admin.compactDisplayTitle, admin.compactDisplayTitle).string
|
||||
}
|
||||
}
|
||||
case .notMutualContact:
|
||||
@ -1020,20 +1029,20 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
|
||||
updated(nil)
|
||||
dismissImpl?()
|
||||
}))
|
||||
} else if let _ = channelView.peers[channelView.peerId] as? TelegramGroup {
|
||||
} else if case .legacyGroup = channelPeer {
|
||||
updateRightsDisposable.set((context.engine.peers.addGroupMember(peerId: peerId, memberId: adminId) |> deliverOnMainQueue).start(error: { error in
|
||||
updateState { current in
|
||||
return current.withUpdatedUpdating(false)
|
||||
}
|
||||
if case .privacy = error, let admin = adminView.peers[adminView.peerId] {
|
||||
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(admin).compactDisplayTitle, EnginePeer(admin).compactDisplayTitle).string, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
if case .privacy = error, let admin = adminPeer {
|
||||
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(admin.compactDisplayTitle, admin.compactDisplayTitle).string, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
}
|
||||
}, completed: {
|
||||
updated(nil)
|
||||
dismissImpl?()
|
||||
}))
|
||||
}
|
||||
} else if let channel = channelView.peers[channelView.peerId] as? TelegramChannel {
|
||||
} else if case let .channel(channel) = channelPeer {
|
||||
if let initialParticipant = initialParticipant {
|
||||
var updateFlags: TelegramChatAdminRightsFlags?
|
||||
var updateRank: String?
|
||||
@ -1105,12 +1114,12 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
|
||||
case .tooMuchJoined:
|
||||
text = presentationData.strings.Group_ErrorSupergroupConversionNotPossible
|
||||
case .restricted:
|
||||
if let admin = adminView.peers[adminView.peerId] {
|
||||
if let admin = adminPeer {
|
||||
switch channel.info {
|
||||
case .broadcast:
|
||||
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToChannelError(EnginePeer(admin).compactDisplayTitle, EnginePeer(admin).compactDisplayTitle).string
|
||||
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToChannelError(admin.compactDisplayTitle, admin.compactDisplayTitle).string
|
||||
case .group:
|
||||
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(admin).compactDisplayTitle, EnginePeer(admin).compactDisplayTitle).string
|
||||
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(admin.compactDisplayTitle, admin.compactDisplayTitle).string
|
||||
}
|
||||
}
|
||||
case .notMutualContact:
|
||||
@ -1184,7 +1193,7 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
|
||||
return current.withUpdatedUpdating(true)
|
||||
}
|
||||
updateRightsDisposable.set((context.peerChannelMemberCategoriesContextsManager.updateMemberAdminRights(engine: context.engine, peerId: peerId, memberId: adminId, adminRights: TelegramChatAdminRights(rights: updateFlags), rank: updateRank) |> deliverOnMainQueue).start(error: { error in
|
||||
if case let .addMemberError(addMemberError) = error, let admin = adminView.peers[adminView.peerId] {
|
||||
if case let .addMemberError(addMemberError) = error, let admin = adminPeer {
|
||||
var text = presentationData.strings.Login_UnknownError
|
||||
switch addMemberError {
|
||||
case .tooMuchJoined:
|
||||
@ -1192,9 +1201,9 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
|
||||
case .restricted:
|
||||
switch channel.info {
|
||||
case .broadcast:
|
||||
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToChannelError(EnginePeer(admin).compactDisplayTitle, EnginePeer(admin).compactDisplayTitle).string
|
||||
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToChannelError(admin.compactDisplayTitle, admin.compactDisplayTitle).string
|
||||
case .group:
|
||||
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(admin).compactDisplayTitle, EnginePeer(admin).compactDisplayTitle).string
|
||||
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(admin.compactDisplayTitle, admin.compactDisplayTitle).string
|
||||
}
|
||||
case .notMutualContact:
|
||||
if case .broadcast = channel.info {
|
||||
@ -1222,7 +1231,7 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
|
||||
}))
|
||||
}
|
||||
}
|
||||
} else if let _ = channelView.peers[channelView.peerId] as? TelegramGroup {
|
||||
} else if case .legacyGroup = channelPeer {
|
||||
var updateFlags: TelegramChatAdminRightsFlags?
|
||||
var updateRank: String?
|
||||
updateState { current in
|
||||
@ -1252,8 +1261,8 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
|
||||
}
|
||||
updateRightsDisposable.set((context.engine.peers.addGroupAdmin(peerId: peerId, adminId: adminId)
|
||||
|> deliverOnMainQueue).start(error: { error in
|
||||
if case let .addMemberError(error) = error, case .privacy = error, let admin = adminView.peers[adminView.peerId] {
|
||||
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(admin).compactDisplayTitle, EnginePeer(admin).compactDisplayTitle).string, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
if case let .addMemberError(error) = error, case .privacy = error, let admin = adminPeer {
|
||||
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(admin.compactDisplayTitle, admin.compactDisplayTitle).string, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
} else if case .adminsTooMuch = error {
|
||||
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Group_ErrorAdminsTooMuch, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
}
|
||||
@ -1312,8 +1321,8 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
|
||||
case let .direct(error):
|
||||
if case let .addMemberError(error) = error {
|
||||
var text = presentationData.strings.Login_UnknownError
|
||||
if case .restricted = error, let admin = adminView.peers[adminView.peerId] {
|
||||
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(admin).compactDisplayTitle, EnginePeer(admin).compactDisplayTitle).string
|
||||
if case .restricted = error, let admin = adminPeer {
|
||||
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(admin.compactDisplayTitle, admin.compactDisplayTitle).string
|
||||
} else if case .tooMuchJoined = error {
|
||||
text = presentationData.strings.Invite_ChannelsTooMuch
|
||||
} else if case .kicked = error {
|
||||
@ -1353,17 +1362,17 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
|
||||
if initialParticipant?.adminInfo == nil {
|
||||
var isGroup: Bool = false
|
||||
var peerTitle: String = ""
|
||||
if let peer = channelView.peers[channelView.peerId] as? TelegramGroup {
|
||||
if case let .legacyGroup(peer) = channelPeer {
|
||||
isGroup = true
|
||||
peerTitle = peer.title
|
||||
} else if let peer = channelView.peers[channelView.peerId] as? TelegramChannel {
|
||||
} else if case let .channel(peer) = channelPeer {
|
||||
if case .group = peer.info {
|
||||
isGroup = true
|
||||
}
|
||||
peerTitle = peer.title
|
||||
}
|
||||
|
||||
if let admin = adminView.peers[adminView.peerId] as? TelegramUser, admin.botInfo != nil && invite {
|
||||
if case let .user(admin) = adminPeer, admin.botInfo != nil && invite {
|
||||
title = presentationData.strings.Bot_AddToChat_Add_Title
|
||||
rightNavigationButton = nil
|
||||
footerItem = ChannelAdminAddBotFooterItem(theme: presentationData.theme, title: state.adminRights ? presentationData.strings.Bot_AddToChat_Add_AddAsAdmin : presentationData.strings.Bot_AddToChat_Add_AddAsMember, action: {
|
||||
@ -1395,7 +1404,7 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
|
||||
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
|
||||
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: channelAdminControllerEntries(presentationData: presentationData, state: state, accountPeerId: context.account.peerId, channelView: channelView, adminView: adminView, initialParticipant: initialParticipant, invite: invite, canEdit: canEdit), style: .blocks, focusItemTag: focusItemTag, ensureVisibleItemTag: nil, emptyStateItem: nil, footerItem: footerItem, animateChanges: true)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: channelAdminControllerEntries(presentationData: presentationData, state: state, accountPeerId: context.account.peerId, channelPeer: channelPeer, adminPeer: adminPeer, adminPresence: adminPresence, initialParticipant: initialParticipant, invite: invite, canEdit: canEdit), style: .blocks, focusItemTag: focusItemTag, ensureVisibleItemTag: nil, emptyStateItem: nil, footerItem: footerItem, animateChanges: true)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ private enum ChannelBannedMemberEntryStableId: Hashable {
|
||||
}
|
||||
|
||||
private enum ChannelBannedMemberEntry: ItemListNodeEntry {
|
||||
case info(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer, TelegramUserPresence?)
|
||||
case info(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, EnginePeer, EnginePeer.Presence?)
|
||||
case rightsHeader(PresentationTheme, String)
|
||||
case rightItem(PresentationTheme, Int, String, TelegramChatBannedRightsFlags, Bool, Bool)
|
||||
case timeout(PresentationTheme, String, String)
|
||||
@ -97,7 +97,7 @@ private enum ChannelBannedMemberEntry: ItemListNodeEntry {
|
||||
if lhsDateTimeFormat != rhsDateTimeFormat {
|
||||
return false
|
||||
}
|
||||
if !arePeersEqual(lhsPeer, rhsPeer) {
|
||||
if lhsPeer != rhsPeer {
|
||||
return false
|
||||
}
|
||||
if lhsPresence != rhsPresence {
|
||||
@ -207,7 +207,7 @@ private enum ChannelBannedMemberEntry: ItemListNodeEntry {
|
||||
let arguments = arguments as! ChannelBannedMemberControllerArguments
|
||||
switch self {
|
||||
case let .info(_, _, dateTimeFormat, peer, presence):
|
||||
return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .generic, peer: EnginePeer(peer), presence: presence.flatMap(EnginePeer.Presence.init), memberCount: nil, state: ItemListAvatarAndNameInfoItemState(), sectionId: self.section, style: .blocks(withTopInset: true, withExtendedBottomInset: false), editingNameUpdated: { _ in
|
||||
return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .generic, peer: peer, presence: presence, memberCount: nil, state: ItemListAvatarAndNameInfoItemState(), sectionId: self.section, style: .blocks(withTopInset: true, withExtendedBottomInset: false), editingNameUpdated: { _ in
|
||||
}, avatarTapped: {
|
||||
})
|
||||
case let .rightsHeader(_, text):
|
||||
@ -256,11 +256,11 @@ func completeRights(_ flags: TelegramChatBannedRightsFlags) -> TelegramChatBanne
|
||||
return result
|
||||
}
|
||||
|
||||
private func channelBannedMemberControllerEntries(presentationData: PresentationData, state: ChannelBannedMemberControllerState, accountPeerId: PeerId, channelView: PeerView, memberView: PeerView, initialParticipant: ChannelParticipant?, initialBannedBy: Peer?) -> [ChannelBannedMemberEntry] {
|
||||
private func channelBannedMemberControllerEntries(presentationData: PresentationData, state: ChannelBannedMemberControllerState, accountPeerId: PeerId, channelPeer: EnginePeer?, memberPeer: EnginePeer?, memberPresence: EnginePeer.Presence?, initialParticipant: ChannelParticipant?, initialBannedBy: EnginePeer?) -> [ChannelBannedMemberEntry] {
|
||||
var entries: [ChannelBannedMemberEntry] = []
|
||||
|
||||
if let channel = channelView.peers[channelView.peerId] as? TelegramChannel, let _ = channelView.cachedData as? CachedChannelData, let defaultBannedRights = channel.defaultBannedRights, let member = memberView.peers[memberView.peerId] {
|
||||
entries.append(.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, member, memberView.peerPresences[member.id] as? TelegramUserPresence))
|
||||
if case let .channel(channel) = channelPeer, let defaultBannedRights = channel.defaultBannedRights, let member = memberPeer {
|
||||
entries.append(.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, member, memberPresence))
|
||||
|
||||
let currentRightsFlags: TelegramChatBannedRightsFlags
|
||||
if let updatedFlags = state.updatedFlags {
|
||||
@ -300,13 +300,13 @@ private func channelBannedMemberControllerEntries(presentationData: Presentation
|
||||
entries.append(.timeout(presentationData.theme, presentationData.strings.GroupPermission_Duration, currentTimeoutString))
|
||||
|
||||
if let initialParticipant = initialParticipant, case let .member(_, _, _, banInfo?, _) = initialParticipant, let initialBannedBy = initialBannedBy {
|
||||
entries.append(.exceptionInfo(presentationData.theme, presentationData.strings.GroupPermission_AddedInfo(EnginePeer(initialBannedBy).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), stringForRelativeSymbolicTimestamp(strings: presentationData.strings, relativeTimestamp: banInfo.timestamp, relativeTo: state.referenceTimestamp, dateTimeFormat: presentationData.dateTimeFormat)).string))
|
||||
entries.append(.exceptionInfo(presentationData.theme, presentationData.strings.GroupPermission_AddedInfo(initialBannedBy.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), stringForRelativeSymbolicTimestamp(strings: presentationData.strings, relativeTimestamp: banInfo.timestamp, relativeTo: state.referenceTimestamp, dateTimeFormat: presentationData.dateTimeFormat)).string))
|
||||
entries.append(.delete(presentationData.theme, presentationData.strings.GroupPermission_Delete))
|
||||
}
|
||||
} else if let group = channelView.peers[channelView.peerId] as? TelegramGroup, let member = memberView.peers[memberView.peerId] {
|
||||
} else if case let .legacyGroup(group) = channelPeer, let member = memberPeer {
|
||||
let defaultBannedRightsFlags = group.defaultBannedRights?.flags ?? []
|
||||
|
||||
entries.append(.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, member, memberView.peerPresences[member.id] as? TelegramUserPresence))
|
||||
entries.append(.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, member, memberPresence))
|
||||
|
||||
let currentRightsFlags: TelegramChatBannedRightsFlags
|
||||
if let updatedFlags = state.updatedFlags {
|
||||
@ -346,7 +346,7 @@ private func channelBannedMemberControllerEntries(presentationData: Presentation
|
||||
entries.append(.timeout(presentationData.theme, presentationData.strings.GroupPermission_Duration, currentTimeoutString))
|
||||
|
||||
if let initialParticipant = initialParticipant, case let .member(_, _, _, banInfo?, _) = initialParticipant, let initialBannedBy = initialBannedBy {
|
||||
entries.append(.exceptionInfo(presentationData.theme, presentationData.strings.GroupPermission_AddedInfo(EnginePeer(initialBannedBy).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), stringForRelativeSymbolicTimestamp(strings: presentationData.strings, relativeTimestamp: banInfo.timestamp, relativeTo: state.referenceTimestamp, dateTimeFormat: presentationData.dateTimeFormat)).string))
|
||||
entries.append(.exceptionInfo(presentationData.theme, presentationData.strings.GroupPermission_AddedInfo(initialBannedBy.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), stringForRelativeSymbolicTimestamp(strings: presentationData.strings, relativeTimestamp: banInfo.timestamp, relativeTo: state.referenceTimestamp, dateTimeFormat: presentationData.dateTimeFormat)).string))
|
||||
entries.append(.delete(presentationData.theme, presentationData.strings.GroupPermission_Delete))
|
||||
}
|
||||
}
|
||||
@ -504,24 +504,31 @@ public func channelBannedMemberController(context: AccountContext, updatedPresen
|
||||
presentControllerImpl?(actionSheet, nil)
|
||||
})
|
||||
|
||||
var keys: [PostboxViewKey] = [.peer(peerId: peerId, components: .all), .peer(peerId: memberId, components: .all)]
|
||||
var peerDataItems: [TelegramEngine.EngineData.Item.Peer.Peer] = []
|
||||
peerDataItems.append(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
peerDataItems.append(TelegramEngine.EngineData.Item.Peer.Peer(id: memberId))
|
||||
if let banInfo = initialParticipant?.banInfo {
|
||||
keys.append(.peer(peerId: banInfo.restrictedBy, components: []))
|
||||
peerDataItems.append(TelegramEngine.EngineData.Item.Peer.Peer(id: banInfo.restrictedBy))
|
||||
}
|
||||
let combinedView = context.account.postbox.combinedView(keys: keys)
|
||||
|
||||
let peersMap = context.engine.data.subscribe(
|
||||
EngineDataMap(peerDataItems),
|
||||
TelegramEngine.EngineData.Item.Peer.Presence(id: memberId)
|
||||
)
|
||||
|
||||
let canEdit = true
|
||||
|
||||
let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData
|
||||
let signal = combineLatest(presentationData, statePromise.get(), combinedView)
|
||||
let signal = combineLatest(presentationData, statePromise.get(), peersMap)
|
||||
|> deliverOnMainQueue
|
||||
|> map { presentationData, state, combinedView -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
let channelView = combinedView.views[.peer(peerId: peerId, components: .all)] as! PeerView
|
||||
let memberView = combinedView.views[.peer(peerId: memberId, components: .all)] as! PeerView
|
||||
var initialBannedByPeer: Peer?
|
||||
|> map { presentationData, state, peersMap -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
let channelPeer = peersMap.0[peerId].flatMap { $0 }
|
||||
let memberPeer = peersMap.0[memberId].flatMap { $0 }
|
||||
var initialBannedByPeer: EnginePeer?
|
||||
if let banInfo = initialParticipant?.banInfo {
|
||||
initialBannedByPeer = (combinedView.views[.peer(peerId: banInfo.restrictedBy, components: [])] as? PeerView)?.peers[banInfo.restrictedBy]
|
||||
initialBannedByPeer = peersMap.0[banInfo.restrictedBy].flatMap { $0 }
|
||||
}
|
||||
let memberPresence = peersMap.1
|
||||
|
||||
let leftNavigationButton: ItemListNavigationButton
|
||||
leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {
|
||||
@ -590,7 +597,7 @@ public func channelBannedMemberController(context: AccountContext, updatedPresen
|
||||
|
||||
resolvedRights = TelegramChatBannedRights(flags: completeRights(currentRightsFlags), untilDate: currentTimeout)
|
||||
}
|
||||
} else if canEdit, let _ = channelView.peers[channelView.peerId] as? TelegramChannel {
|
||||
} else if canEdit, case .channel = channelPeer {
|
||||
var updateFlags: TelegramChatBannedRightsFlags?
|
||||
var updateTimeout: Int32?
|
||||
updateState { state in
|
||||
@ -723,7 +730,7 @@ public func channelBannedMemberController(context: AccountContext, updatedPresen
|
||||
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
|
||||
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: channelBannedMemberControllerEntries(presentationData: presentationData, state: state, accountPeerId: context.account.peerId, channelView: channelView, memberView: memberView, initialParticipant: initialParticipant, initialBannedBy: initialBannedByPeer), style: .blocks, emptyStateItem: nil, animateChanges: true)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: channelBannedMemberControllerEntries(presentationData: presentationData, state: state, accountPeerId: context.account.peerId, channelPeer: channelPeer, memberPeer: memberPeer, memberPresence: memberPresence, initialParticipant: initialParticipant, initialBannedBy: initialBannedByPeer), style: .blocks, emptyStateItem: nil, animateChanges: true)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
|
||||
@ -389,11 +389,12 @@ final class LocalizationListControllerNode: ViewControllerTracingNode {
|
||||
}
|
||||
|
||||
let removeItem: (String) -> Void = { id in
|
||||
let _ = (context.account.postbox.transaction { transaction -> Signal<LocalizationInfo?, NoError> in
|
||||
removeSavedLocalization(transaction: transaction, languageCode: id)
|
||||
let state = transaction.getPreferencesEntry(key: PreferencesKeys.localizationListState)?.get(LocalizationListState.self)
|
||||
let _ = context.engine.localization.removeSavedLocalization(languageCode: id).start()
|
||||
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.LocalizationList())
|
||||
|> mapToSignal { state -> Signal<LocalizationInfo?, NoError> in
|
||||
return context.sharedContext.accountManager.transaction { transaction -> LocalizationInfo? in
|
||||
if let settings = transaction.getSharedData(SharedDataKeys.localizationSettings)?.get(LocalizationSettings.self), let state = state {
|
||||
if let settings = transaction.getSharedData(SharedDataKeys.localizationSettings)?.get(LocalizationSettings.self) {
|
||||
if settings.primaryComponent.languageCode == id {
|
||||
for item in state.availableOfficialLocalizations {
|
||||
if item.languageCode == "en" {
|
||||
@ -405,7 +406,6 @@ final class LocalizationListControllerNode: ViewControllerTracingNode {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|> switchToLatest
|
||||
|> deliverOnMainQueue).start(next: { [weak self] info in
|
||||
if revealedCodeValue == id {
|
||||
revealedCodeValue = nil
|
||||
@ -417,10 +417,17 @@ final class LocalizationListControllerNode: ViewControllerTracingNode {
|
||||
})
|
||||
}
|
||||
|
||||
let preferencesKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.localizationListState]))
|
||||
let previousState = Atomic<LocalizationListState?>(value: nil)
|
||||
let previousEntriesHolder = Atomic<([LanguageListEntry], PresentationTheme, PresentationStrings)?>(value: nil)
|
||||
self.listDisposable = combineLatest(queue: .mainQueue(), context.account.postbox.combinedView(keys: [preferencesKey]), context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.localizationSettings, ApplicationSpecificSharedDataKeys.translationSettings]), self.presentationDataValue.get(), self.applyingCode.get(), revealedCode.get(), self.isEditing.get()).start(next: { [weak self] view, sharedData, presentationData, applyingCode, revealedCode, isEditing in
|
||||
self.listDisposable = combineLatest(
|
||||
queue: .mainQueue(),
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Configuration.LocalizationList()),
|
||||
context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.localizationSettings, ApplicationSpecificSharedDataKeys.translationSettings]),
|
||||
self.presentationDataValue.get(),
|
||||
self.applyingCode.get(),
|
||||
revealedCode.get(),
|
||||
self.isEditing.get()
|
||||
).start(next: { [weak self] localizationListState, sharedData, presentationData, applyingCode, revealedCode, isEditing in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -449,8 +456,7 @@ final class LocalizationListControllerNode: ViewControllerTracingNode {
|
||||
}
|
||||
}
|
||||
|
||||
let localizationListState = (view.views[preferencesKey] as? PreferencesView)?.values[PreferencesKeys.localizationListState]?.get(LocalizationListState.self)
|
||||
if let localizationListState = localizationListState, !localizationListState.availableOfficialLocalizations.isEmpty {
|
||||
if !localizationListState.availableOfficialLocalizations.isEmpty {
|
||||
strongSelf.currentListState = localizationListState
|
||||
|
||||
if #available(iOS 12.0, *) {
|
||||
@ -520,7 +526,7 @@ final class LocalizationListControllerNode: ViewControllerTracingNode {
|
||||
if let strongSelf = self {
|
||||
strongSelf.push(translationSettingsController(context: strongSelf.context))
|
||||
}
|
||||
}, selectLocalization: { [weak self] info in self?.selectLocalization(info) }, setItemWithRevealedOptions: setItemWithRevealedOptions, removeItem: removeItem, firstTime: previousEntriesAndPresentationData == nil, isLoading: entries.isEmpty, forceUpdate: previousEntriesAndPresentationData?.1 !== presentationData.theme || previousEntriesAndPresentationData?.2 !== presentationData.strings, animated: (previousEntriesAndPresentationData?.0.count ?? 0) != entries.count, crossfade: (previousState == nil) != (localizationListState == nil))
|
||||
}, selectLocalization: { [weak self] info in self?.selectLocalization(info) }, setItemWithRevealedOptions: setItemWithRevealedOptions, removeItem: removeItem, firstTime: previousEntriesAndPresentationData == nil, isLoading: entries.isEmpty, forceUpdate: previousEntriesAndPresentationData?.1 !== presentationData.theme || previousEntriesAndPresentationData?.2 !== presentationData.strings, animated: (previousEntriesAndPresentationData?.0.count ?? 0) != entries.count, crossfade: (previousState == nil || previousState!.availableOfficialLocalizations.isEmpty) != localizationListState.availableOfficialLocalizations.isEmpty)
|
||||
strongSelf.enqueueTransition(transition)
|
||||
})
|
||||
self.updatedDisposable = context.engine.localization.synchronizedLocalizationListState().start()
|
||||
|
||||
@ -740,39 +740,34 @@ final class NotificationExceptionsControllerNode: ViewControllerTracingNode {
|
||||
let updateNotificationsView: (@escaping () -> Void) -> Void = { completion in
|
||||
updateState { current in
|
||||
peerIds = peerIds.union(current.mode.peerIds)
|
||||
let key: PostboxViewKey = .peerNotificationSettings(peerIds: peerIds)
|
||||
updateNotificationsDisposable.set((context.account.postbox.combinedView(keys: [key])
|
||||
|> deliverOnMainQueue).start(next: { view in
|
||||
if let view = view.views[key] as? PeerNotificationSettingsView {
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataMap(view.notificationSettings.keys.map(TelegramEngine.EngineData.Item.Peer.Peer.init)),
|
||||
EngineDataMap(view.notificationSettings.keys.map(TelegramEngine.EngineData.Item.Peer.NotificationSettings.init))
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { peerMap, notificationSettingsMap in
|
||||
updateState { current in
|
||||
var current = current
|
||||
for (key, value) in view.notificationSettings {
|
||||
if let value = value as? TelegramPeerNotificationSettings {
|
||||
if let local = current.mode.settings[key] {
|
||||
if !value.isEqual(to: local.settings), let maybePeer = peerMap[key], let peer = maybePeer, let settings = notificationSettingsMap[key], !settings._asNotificationSettings().isEqual(to: local.settings) {
|
||||
current = current.withUpdatedPeerSound(peer._asPeer(), settings.messageSound._asMessageSound()).withUpdatedPeerMuteInterval(peer._asPeer(), settings.muteState.timeInterval).withUpdatedPeerDisplayPreviews(peer._asPeer(), settings.displayPreviews._asDisplayPreviews())
|
||||
}
|
||||
} else if let maybePeer = peerMap[key], let peer = maybePeer {
|
||||
if case .default = value.messageSound, case .unmuted = value.muteState, case .default = value.displayPreviews {
|
||||
} else {
|
||||
current = current.withUpdatedPeerSound(peer._asPeer(), value.messageSound).withUpdatedPeerMuteInterval(peer._asPeer(), EnginePeer.NotificationSettings.MuteState(value.muteState).timeInterval).withUpdatedPeerDisplayPreviews(peer._asPeer(), value.displayPreviews)
|
||||
}
|
||||
}
|
||||
updateNotificationsDisposable.set((context.engine.data.subscribe(EngineDataMap(
|
||||
peerIds.map(TelegramEngine.EngineData.Item.Peer.NotificationSettings.init)
|
||||
))
|
||||
|> deliverOnMainQueue).start(next: { notificationSettingsMap in
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataMap(notificationSettingsMap.keys.map(TelegramEngine.EngineData.Item.Peer.Peer.init)),
|
||||
EngineDataMap(notificationSettingsMap.keys.map(TelegramEngine.EngineData.Item.Peer.NotificationSettings.init))
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { peerMap, notificationSettingsMap in
|
||||
updateState { current in
|
||||
var current = current
|
||||
for (key, value) in notificationSettingsMap {
|
||||
if let local = current.mode.settings[key] {
|
||||
if !value._asNotificationSettings().isEqual(to: local.settings), let maybePeer = peerMap[key], let peer = maybePeer, let settings = notificationSettingsMap[key], !settings._asNotificationSettings().isEqual(to: local.settings) {
|
||||
current = current.withUpdatedPeerSound(peer._asPeer(), settings.messageSound._asMessageSound()).withUpdatedPeerMuteInterval(peer._asPeer(), settings.muteState.timeInterval).withUpdatedPeerDisplayPreviews(peer._asPeer(), settings.displayPreviews._asDisplayPreviews())
|
||||
}
|
||||
} else if let maybePeer = peerMap[key], let peer = maybePeer {
|
||||
if case .default = value.messageSound, case .unmuted = value.muteState, case .default = value.displayPreviews {
|
||||
} else {
|
||||
current = current.withUpdatedPeerSound(peer._asPeer(), value.messageSound._asMessageSound()).withUpdatedPeerMuteInterval(peer._asPeer(), value.muteState.timeInterval).withUpdatedPeerDisplayPreviews(peer._asPeer(), value.displayPreviews._asDisplayPreviews())
|
||||
}
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
completion()
|
||||
})
|
||||
} else {
|
||||
return current
|
||||
}
|
||||
|
||||
completion()
|
||||
}
|
||||
})
|
||||
}))
|
||||
return current
|
||||
}
|
||||
@ -1175,32 +1170,28 @@ private final class NotificationExceptionsSearchContainerNode: SearchDisplayCont
|
||||
let updateNotificationsDisposable = self.updateNotificationsDisposable
|
||||
|
||||
let updateNotificationsView: (@escaping () -> Void) -> Void = { completion in
|
||||
let key: PostboxViewKey = .peerNotificationSettings(peerIds: Set(mode.peerIds))
|
||||
|
||||
updateNotificationsDisposable.set(context.account.postbox.combinedView(keys: [key]).start(next: { view in
|
||||
if let view = view.views[key] as? PeerNotificationSettingsView {
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataMap(view.notificationSettings.keys.map(TelegramEngine.EngineData.Item.Peer.Peer.init)),
|
||||
EngineDataMap(view.notificationSettings.keys.map(TelegramEngine.EngineData.Item.Peer.NotificationSettings.init))
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { peerMap, notificationSettingsMap in
|
||||
updateState { current in
|
||||
var current = current
|
||||
for (key, value) in view.notificationSettings {
|
||||
if let value = value as? TelegramPeerNotificationSettings,let local = current.mode.settings[key] {
|
||||
if !value.isEqual(to: local.settings), let maybePeer = peerMap[key], let peer = maybePeer, let settings = notificationSettingsMap[key], !settings._asNotificationSettings().isEqual(to: local.settings) {
|
||||
current = current.withUpdatedPeerSound(peer._asPeer(), settings.messageSound._asMessageSound()).withUpdatedPeerMuteInterval(peer._asPeer(), settings.muteState.timeInterval)
|
||||
}
|
||||
updateNotificationsDisposable.set(context.engine.data.subscribe(EngineDataMap(
|
||||
mode.peerIds.map(TelegramEngine.EngineData.Item.Peer.NotificationSettings.init)
|
||||
)).start(next: { notificationSettingsMap in
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataMap(notificationSettingsMap.keys.map(TelegramEngine.EngineData.Item.Peer.Peer.init)),
|
||||
EngineDataMap(notificationSettingsMap.keys.map(TelegramEngine.EngineData.Item.Peer.NotificationSettings.init))
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { peerMap, notificationSettingsMap in
|
||||
updateState { current in
|
||||
var current = current
|
||||
for (key, value) in notificationSettingsMap {
|
||||
if let local = current.mode.settings[key] {
|
||||
if !value._asNotificationSettings().isEqual(to: local.settings), let maybePeer = peerMap[key], let peer = maybePeer, let settings = notificationSettingsMap[key], !settings._asNotificationSettings().isEqual(to: local.settings) {
|
||||
current = current.withUpdatedPeerSound(peer._asPeer(), settings.messageSound._asMessageSound()).withUpdatedPeerMuteInterval(peer._asPeer(), settings.muteState.timeInterval)
|
||||
}
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
completion()
|
||||
})
|
||||
} else {
|
||||
return current
|
||||
}
|
||||
|
||||
completion()
|
||||
}
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@ -455,39 +455,36 @@ public func notificationsPeerCategoryController(context: AccountContext, categor
|
||||
let updateNotificationsView: (@escaping () -> Void) -> Void = { completion in
|
||||
updateState { current in
|
||||
peerIds = peerIds.union(current.mode.peerIds)
|
||||
let key: PostboxViewKey = .peerNotificationSettings(peerIds: peerIds)
|
||||
updateNotificationsDisposable.set((context.account.postbox.combinedView(keys: [key])
|
||||
|> deliverOnMainQueue).start(next: { view in
|
||||
if let view = view.views[key] as? PeerNotificationSettingsView {
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataMap(view.notificationSettings.keys.map(TelegramEngine.EngineData.Item.Peer.Peer.init)),
|
||||
EngineDataMap(view.notificationSettings.keys.map(TelegramEngine.EngineData.Item.Peer.NotificationSettings.init))
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { peerMap, notificationSettingsMap in
|
||||
updateState { current in
|
||||
var current = current
|
||||
for (key, value) in view.notificationSettings {
|
||||
if let value = value as? TelegramPeerNotificationSettings {
|
||||
if let local = current.mode.settings[key] {
|
||||
if !value.isEqual(to: local.settings), let maybePeer = peerMap[key], let peer = maybePeer, let settings = notificationSettingsMap[key], !settings._asNotificationSettings().isEqual(to: local.settings) {
|
||||
current = current.withUpdatedPeerSound(peer._asPeer(), settings.messageSound._asMessageSound()).withUpdatedPeerMuteInterval(peer._asPeer(), settings.muteState.timeInterval).withUpdatedPeerDisplayPreviews(peer._asPeer(), settings.displayPreviews._asDisplayPreviews())
|
||||
}
|
||||
} else if let maybePeer = peerMap[key], let peer = maybePeer {
|
||||
if case .default = value.messageSound, case .unmuted = value.muteState, case .default = value.displayPreviews {
|
||||
} else {
|
||||
current = current.withUpdatedPeerSound(peer._asPeer(), value.messageSound).withUpdatedPeerMuteInterval(peer._asPeer(), EnginePeer.NotificationSettings.MuteState(value.muteState).timeInterval).withUpdatedPeerDisplayPreviews(peer._asPeer(), value.displayPreviews)
|
||||
}
|
||||
}
|
||||
let combinedPeerNotificationSettings = context.engine.data.subscribe(EngineDataMap(
|
||||
peerIds.map(TelegramEngine.EngineData.Item.Peer.NotificationSettings.init)
|
||||
))
|
||||
|
||||
updateNotificationsDisposable.set((combinedPeerNotificationSettings
|
||||
|> deliverOnMainQueue).start(next: { combinedPeerNotificationSettings in
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataMap(combinedPeerNotificationSettings.keys.map(TelegramEngine.EngineData.Item.Peer.Peer.init)),
|
||||
EngineDataMap(combinedPeerNotificationSettings.keys.map(TelegramEngine.EngineData.Item.Peer.NotificationSettings.init))
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { peerMap, notificationSettingsMap in
|
||||
updateState { current in
|
||||
var current = current
|
||||
for (key, value) in combinedPeerNotificationSettings {
|
||||
if let local = current.mode.settings[key] {
|
||||
if !value._asNotificationSettings().isEqual(to: local.settings), let maybePeer = peerMap[key], let peer = maybePeer, let settings = notificationSettingsMap[key], !settings._asNotificationSettings().isEqual(to: local.settings) {
|
||||
current = current.withUpdatedPeerSound(peer._asPeer(), settings.messageSound._asMessageSound()).withUpdatedPeerMuteInterval(peer._asPeer(), settings.muteState.timeInterval).withUpdatedPeerDisplayPreviews(peer._asPeer(), settings.displayPreviews._asDisplayPreviews())
|
||||
}
|
||||
} else if let maybePeer = peerMap[key], let peer = maybePeer {
|
||||
if case .default = value.messageSound, case .unmuted = value.muteState, case .default = value.displayPreviews {
|
||||
} else {
|
||||
current = current.withUpdatedPeerSound(peer._asPeer(), value.messageSound._asMessageSound()).withUpdatedPeerMuteInterval(peer._asPeer(), value.muteState.timeInterval).withUpdatedPeerDisplayPreviews(peer._asPeer(), value.displayPreviews._asDisplayPreviews())
|
||||
}
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
completion()
|
||||
})
|
||||
} else {
|
||||
return current
|
||||
}
|
||||
|
||||
completion()
|
||||
}
|
||||
})
|
||||
}))
|
||||
return current
|
||||
}
|
||||
|
||||
@ -851,12 +851,23 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting
|
||||
updatedBlockedPeers?(blockedPeersContext)
|
||||
}))
|
||||
|
||||
let preferencesKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.appConfiguration]))
|
||||
|
||||
let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, statePromise.get(), privacySettingsPromise.get(), context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.secretChatLinkPreviewsKey()), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]), context.engine.peers.recentPeers(), blockedPeersState.get(), webSessionsContext.state, context.sharedContext.accountManager.accessChallengeData(), combineLatest(twoStepAuth.get(), twoStepAuthDataValue.get()), context.account.postbox.combinedView(keys: [preferencesKey]))
|
||||
|> map { presentationData, state, privacySettings, noticeView, sharedData, recentPeers, blockedPeersState, activeWebsitesState, accessChallengeData, twoStepAuth, preferences -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
let signal = combineLatest(
|
||||
queue: .mainQueue(),
|
||||
context.sharedContext.presentationData,
|
||||
statePromise.get(),
|
||||
privacySettingsPromise.get(),
|
||||
context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.secretChatLinkPreviewsKey()),
|
||||
context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]),
|
||||
context.engine.peers.recentPeers(),
|
||||
blockedPeersState.get(),
|
||||
webSessionsContext.state,
|
||||
context.sharedContext.accountManager.accessChallengeData(),
|
||||
combineLatest(twoStepAuth.get(), twoStepAuthDataValue.get()),
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Configuration.App())
|
||||
)
|
||||
|> map { presentationData, state, privacySettings, noticeView, sharedData, recentPeers, blockedPeersState, activeWebsitesState, accessChallengeData, twoStepAuth, appConfiguration -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
var canAutoarchive = false
|
||||
if let view = preferences.views[preferencesKey] as? PreferencesView, let appConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self), let data = appConfiguration.data, let hasAutoarchive = data["autoarchive_setting_available"] as? Bool {
|
||||
if let data = appConfiguration.data, let hasAutoarchive = data["autoarchive_setting_available"] as? Bool {
|
||||
canAutoarchive = hasAutoarchive
|
||||
}
|
||||
|
||||
|
||||
@ -400,7 +400,7 @@ public final class SettingsSearchContainerNode: SearchDisplayControllerContentNo
|
||||
self.recentListNode.isHidden = false
|
||||
|
||||
let previousRecentlySearchedItemOrder = Atomic<[SettingsSearchableItemId]>(value: [])
|
||||
let fixedRecentlySearchedItems = settingsSearchRecentItems(postbox: context.account.postbox)
|
||||
let fixedRecentlySearchedItems = settingsSearchRecentItems(engine: context.engine)
|
||||
|> map { recentIds -> [SettingsSearchableItemId] in
|
||||
var result: [SettingsSearchableItemId] = []
|
||||
let _ = previousRecentlySearchedItemOrder.modify { current in
|
||||
|
||||
@ -52,16 +52,14 @@ func clearRecentSettingsSearchItems(engine: TelegramEngine) {
|
||||
let _ = engine.orderedLists.clear(collectionId: ApplicationSpecificOrderedItemListCollectionId.settingsSearchRecentItems).start()
|
||||
}
|
||||
|
||||
func settingsSearchRecentItems(postbox: Postbox) -> Signal<[SettingsSearchableItemId], NoError> {
|
||||
return postbox.combinedView(keys: [.orderedItemList(id: ApplicationSpecificOrderedItemListCollectionId.settingsSearchRecentItems)])
|
||||
|> map { view -> [SettingsSearchableItemId] in
|
||||
func settingsSearchRecentItems(engine: TelegramEngine) -> Signal<[SettingsSearchableItemId], NoError> {
|
||||
return engine.data.subscribe(TelegramEngine.EngineData.Item.OrderedLists.ListItems(collectionId: ApplicationSpecificOrderedItemListCollectionId.settingsSearchRecentItems))
|
||||
|> map { items -> [SettingsSearchableItemId] in
|
||||
var result: [SettingsSearchableItemId] = []
|
||||
if let view = view.views[.orderedItemList(id: ApplicationSpecificOrderedItemListCollectionId.settingsSearchRecentItems)] as? OrderedItemListView {
|
||||
for item in view.items {
|
||||
let index = SettingsSearchRecentQueryItemId(item.id).value
|
||||
if let itemId = SettingsSearchableItemId(index: index) {
|
||||
result.append(itemId)
|
||||
}
|
||||
for item in items {
|
||||
let index = SettingsSearchRecentQueryItemId(item.id).value
|
||||
if let itemId = SettingsSearchableItemId(index: index) {
|
||||
result.append(itemId)
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
||||
@ -775,11 +775,12 @@ func settingsSearchableItems(context: AccountContext, notificationExceptionsList
|
||||
return settings.servers
|
||||
}
|
||||
|
||||
let localizationPreferencesKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.localizationListState]))
|
||||
let localizations = combineLatest(context.account.postbox.combinedView(keys: [localizationPreferencesKey]), context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.localizationSettings]))
|
||||
|> map { view, sharedData -> [LocalizationInfo] in
|
||||
if let localizationListState = (view.views[localizationPreferencesKey] as? PreferencesView)?.values[PreferencesKeys.localizationListState]?.get(LocalizationListState.self), !localizationListState.availableOfficialLocalizations.isEmpty {
|
||||
|
||||
let localizations = combineLatest(
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Configuration.LocalizationList()),
|
||||
context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.localizationSettings])
|
||||
)
|
||||
|> map { localizationListState, sharedData -> [LocalizationInfo] in
|
||||
if !localizationListState.availableOfficialLocalizations.isEmpty {
|
||||
var existingIds = Set<String>()
|
||||
let availableSavedLocalizations = localizationListState.availableSavedLocalizations.filter({ info in !localizationListState.availableOfficialLocalizations.contains(where: { $0.languageCode == info.languageCode }) })
|
||||
|
||||
|
||||
@ -1148,26 +1148,7 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
|
||||
break
|
||||
}
|
||||
}
|
||||
let _ = (context.account.postbox.transaction { transaction -> Void in
|
||||
let infos = transaction.getItemCollectionsInfos(namespace: namespaceForMode(mode))
|
||||
|
||||
var packDict: [ItemCollectionId: Int] = [:]
|
||||
for i in 0 ..< infos.count {
|
||||
packDict[infos[i].0] = i
|
||||
}
|
||||
var tempSortedPacks: [(ItemCollectionId, ItemCollectionInfo)] = []
|
||||
var processedPacks = Set<ItemCollectionId>()
|
||||
for id in currentIds {
|
||||
if let index = packDict[id] {
|
||||
tempSortedPacks.append(infos[index])
|
||||
processedPacks.insert(id)
|
||||
}
|
||||
}
|
||||
let restPacks = infos.filter { !processedPacks.contains($0.0) }
|
||||
let sortedPacks = restPacks + tempSortedPacks
|
||||
addSynchronizeInstalledStickerPacksOperation(transaction: transaction, namespace: namespaceForMode(mode), content: .sync, noDelay: false)
|
||||
transaction.replaceItemCollectionInfos(namespace: namespaceForMode(mode), itemCollectionInfos: sortedPacks)
|
||||
}
|
||||
let _ = (context.engine.stickers.reorderStickerPacks(namespace: namespaceForMode(mode), itemIds: currentIds)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
temporaryPackOrder.set(.single(nil))
|
||||
})
|
||||
|
||||
@ -569,7 +569,7 @@ final class ThemeGridSearchContentNode: SearchDisplayControllerContentNode {
|
||||
}
|
||||
|
||||
let previousRecentItems = Atomic<[ThemeGridRecentEntry]?>(value: nil)
|
||||
self.recentDisposable = (combineLatest(wallpaperSearchRecentQueries(postbox: self.context.account.postbox), self.presentationDataPromise.get())
|
||||
self.recentDisposable = (combineLatest(wallpaperSearchRecentQueries(engine: self.context.engine), self.presentationDataPromise.get())
|
||||
|> deliverOnMainQueue).start(next: { [weak self] queries, presentationData in
|
||||
if let strongSelf = self {
|
||||
var entries: [ThemeGridRecentEntry] = []
|
||||
|
||||
@ -55,15 +55,13 @@ func clearRecentWallpaperSearchQueries(engine: TelegramEngine) -> Signal<Never,
|
||||
return engine.orderedLists.clear(collectionId: ApplicationSpecificOrderedItemListCollectionId.wallpaperSearchRecentQueries)
|
||||
}
|
||||
|
||||
func wallpaperSearchRecentQueries(postbox: Postbox) -> Signal<[String], NoError> {
|
||||
return postbox.combinedView(keys: [.orderedItemList(id: ApplicationSpecificOrderedItemListCollectionId.wallpaperSearchRecentQueries)])
|
||||
|> map { view -> [String] in
|
||||
func wallpaperSearchRecentQueries(engine: TelegramEngine) -> Signal<[String], NoError> {
|
||||
return engine.data.subscribe(TelegramEngine.EngineData.Item.OrderedLists.ListItems(collectionId: ApplicationSpecificOrderedItemListCollectionId.wallpaperSearchRecentQueries))
|
||||
|> map { items -> [String] in
|
||||
var result: [String] = []
|
||||
if let view = view.views[.orderedItemList(id: ApplicationSpecificOrderedItemListCollectionId.wallpaperSearchRecentQueries)] as? OrderedItemListView {
|
||||
for item in view.items {
|
||||
let value = WallpaperSearchRecentQueryItemId(item.id).value
|
||||
result.append(value)
|
||||
}
|
||||
for item in items {
|
||||
let value = WallpaperSearchRecentQueryItemId(item.id).value
|
||||
result.append(value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@ -313,7 +313,7 @@ public final class ShareController: ViewController {
|
||||
private let segmentedValues: [ShareControllerSegmentedValue]?
|
||||
private let fromForeignApp: Bool
|
||||
|
||||
private let peers = Promise<([(EngineRenderedPeer, PeerPresence?)], EnginePeer)>()
|
||||
private let peers = Promise<([(EngineRenderedPeer, EnginePeer.Presence?)], EnginePeer)>()
|
||||
private let peersDisposable = MetaDisposable()
|
||||
private let readyDisposable = MetaDisposable()
|
||||
private let accountActiveDisposable = MetaDisposable()
|
||||
@ -966,7 +966,7 @@ public final class ShareController: ViewController {
|
||||
self.currentAccount.viewTracker.tailChatListView(groupId: .root, count: 150)
|
||||
|> take(1)
|
||||
)
|
||||
|> mapToSignal { maybeAccountPeer, view -> Signal<([(EngineRenderedPeer, PeerPresence?)], EnginePeer), NoError> in
|
||||
|> mapToSignal { maybeAccountPeer, view -> Signal<([(EngineRenderedPeer, EnginePeer.Presence?)], EnginePeer), NoError> in
|
||||
let accountPeer = maybeAccountPeer!
|
||||
|
||||
var peers: [EngineRenderedPeer] = []
|
||||
@ -980,14 +980,14 @@ public final class ShareController: ViewController {
|
||||
break
|
||||
}
|
||||
}
|
||||
let key = PostboxViewKey.peerPresences(peerIds: Set(peers.map { $0.peerId }))
|
||||
return account.postbox.combinedView(keys: [key])
|
||||
|> map { views -> ([(EngineRenderedPeer, PeerPresence?)], EnginePeer) in
|
||||
var resultPeers: [(EngineRenderedPeer, PeerPresence?)] = []
|
||||
if let presencesView = views.views[key] as? PeerPresencesView {
|
||||
for peer in peers {
|
||||
resultPeers.append((peer, presencesView.presences[peer.peerId]))
|
||||
}
|
||||
|
||||
return TelegramEngine(account: account).data.subscribe(EngineDataMap(
|
||||
peers.map { TelegramEngine.EngineData.Item.Peer.Presence(id: $0.peerId) }
|
||||
))
|
||||
|> map { presenceMap -> ([(EngineRenderedPeer, EnginePeer.Presence?)], EnginePeer) in
|
||||
var resultPeers: [(EngineRenderedPeer, EnginePeer.Presence?)] = []
|
||||
for peer in peers {
|
||||
resultPeers.append((peer, presenceMap[peer.peerId].flatMap { $0 }))
|
||||
}
|
||||
return (resultPeers, accountPeer)
|
||||
}
|
||||
|
||||
@ -804,7 +804,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
func updatePeers(context: AccountContext, switchableAccounts: [AccountWithInfo], peers: [(EngineRenderedPeer, PeerPresence?)], accountPeer: EnginePeer, defaultAction: ShareControllerAction?) {
|
||||
func updatePeers(context: AccountContext, switchableAccounts: [AccountWithInfo], peers: [(EngineRenderedPeer, EnginePeer.Presence?)], accountPeer: EnginePeer, defaultAction: ShareControllerAction?) {
|
||||
self.context = context
|
||||
|
||||
if let peersContentNode = self.peersContentNode, peersContentNode.accountPeer.id == accountPeer.id {
|
||||
|
||||
@ -91,13 +91,13 @@ final class ShareControllerPeerGridItem: GridItem {
|
||||
let theme: PresentationTheme
|
||||
let strings: PresentationStrings
|
||||
let peer: EngineRenderedPeer?
|
||||
let presence: PeerPresence?
|
||||
let presence: EnginePeer.Presence?
|
||||
let controllerInteraction: ShareControllerInteraction
|
||||
let search: Bool
|
||||
|
||||
let section: GridSection?
|
||||
|
||||
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EngineRenderedPeer?, presence: PeerPresence?, controllerInteraction: ShareControllerInteraction, sectionTitle: String? = nil, search: Bool = false) {
|
||||
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EngineRenderedPeer?, presence: EnginePeer.Presence?, controllerInteraction: ShareControllerInteraction, sectionTitle: String? = nil, search: Bool = false) {
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
@ -131,7 +131,7 @@ final class ShareControllerPeerGridItem: GridItem {
|
||||
}
|
||||
|
||||
final class ShareControllerPeerGridItemNode: GridItemNode {
|
||||
private var currentState: (AccountContext, PresentationTheme, PresentationStrings, EngineRenderedPeer?, Bool, PeerPresence?)?
|
||||
private var currentState: (AccountContext, PresentationTheme, PresentationStrings, EngineRenderedPeer?, Bool, EnginePeer.Presence?)?
|
||||
private let peerNode: SelectablePeerNode
|
||||
private var presenceManager: PeerPresenceStatusManager?
|
||||
|
||||
@ -171,14 +171,14 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
|
||||
}
|
||||
}
|
||||
|
||||
func setup(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EngineRenderedPeer?, presence: PeerPresence?, search: Bool, synchronousLoad: Bool, force: Bool) {
|
||||
if force || self.currentState == nil || self.currentState!.0 !== context || self.currentState!.3 != peer || !arePeerPresencesEqual(self.currentState!.5, presence) {
|
||||
func setup(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EngineRenderedPeer?, presence: EnginePeer.Presence?, search: Bool, synchronousLoad: Bool, force: Bool) {
|
||||
if force || self.currentState == nil || self.currentState!.0 !== context || self.currentState!.3 != peer || self.currentState!.5 != presence {
|
||||
let itemTheme = SelectablePeerNodeTheme(textColor: theme.actionSheet.primaryTextColor, secretTextColor: theme.chatList.secretTitleColor, selectedTextColor: theme.actionSheet.controlAccentColor, checkBackgroundColor: theme.actionSheet.opaqueItemBackgroundColor, checkFillColor: theme.actionSheet.controlAccentColor, checkColor: theme.actionSheet.checkContentColor, avatarPlaceholderColor: theme.list.mediaPlaceholderColor)
|
||||
|
||||
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
||||
var online = false
|
||||
if case let .user(peer) = peer?.peer, let presence = presence as? TelegramUserPresence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != context.account.peerId {
|
||||
let relativeStatus = relativeUserPresenceStatus(EnginePeer.Presence(presence), relativeTo: timestamp)
|
||||
if case let .user(peer) = peer?.peer, let presence = presence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != context.account.peerId {
|
||||
let relativeStatus = relativeUserPresenceStatus(presence, relativeTo: timestamp)
|
||||
if case .online = relativeStatus {
|
||||
online = true
|
||||
}
|
||||
@ -220,8 +220,8 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
|
||||
}
|
||||
self.currentState = (context, theme, strings, peer, search, presence)
|
||||
self.setNeedsLayout()
|
||||
if let presence = presence as? TelegramUserPresence {
|
||||
self.presenceManager?.reset(presence: EnginePeer.Presence(presence))
|
||||
if let presence = presence {
|
||||
self.presenceManager?.reset(presence: presence)
|
||||
}
|
||||
}
|
||||
self.updateSelection(animated: false)
|
||||
|
||||
@ -20,7 +20,7 @@ private let subtitleFont = Font.regular(12.0)
|
||||
private struct SharePeerEntry: Comparable, Identifiable {
|
||||
let index: Int32
|
||||
let peer: EngineRenderedPeer
|
||||
let presence: PeerPresence?
|
||||
let presence: EnginePeer.Presence?
|
||||
let theme: PresentationTheme
|
||||
let strings: PresentationStrings
|
||||
|
||||
@ -35,13 +35,10 @@ private struct SharePeerEntry: Comparable, Identifiable {
|
||||
if lhs.peer != rhs.peer {
|
||||
return false
|
||||
}
|
||||
if let lhsPresence = lhs.presence, let rhsPresence = rhs.presence {
|
||||
if !lhsPresence.isEqual(to: rhsPresence) {
|
||||
return false
|
||||
}
|
||||
} else if (lhs.presence != nil) != (rhs.presence != nil) {
|
||||
if lhs.presence != rhs.presence {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@ -115,9 +112,9 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
|
||||
private var validLayout: (CGSize, CGFloat)?
|
||||
private var overrideGridOffsetTransition: ContainedViewLayoutTransition?
|
||||
|
||||
let peersValue = Promise<[(EngineRenderedPeer, PeerPresence?)]>()
|
||||
let peersValue = Promise<[(EngineRenderedPeer, EnginePeer.Presence?)]>()
|
||||
|
||||
init(sharedContext: SharedAccountContext, context: AccountContext, switchableAccounts: [AccountWithInfo], theme: PresentationTheme, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, peers: [(EngineRenderedPeer, PeerPresence?)], accountPeer: EnginePeer, controllerInteraction: ShareControllerInteraction, externalShare: Bool, switchToAnotherAccount: @escaping () -> Void, debugAction: @escaping () -> Void, extendedInitialReveal: Bool, segmentedValues: [ShareControllerSegmentedValue]?) {
|
||||
init(sharedContext: SharedAccountContext, context: AccountContext, switchableAccounts: [AccountWithInfo], theme: PresentationTheme, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, peers: [(EngineRenderedPeer, EnginePeer.Presence?)], accountPeer: EnginePeer, controllerInteraction: ShareControllerInteraction, externalShare: Bool, switchToAnotherAccount: @escaping () -> Void, debugAction: @escaping () -> Void, extendedInitialReveal: Bool, segmentedValues: [ShareControllerSegmentedValue]?) {
|
||||
self.sharedContext = sharedContext
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
|
||||
@ -36,7 +36,7 @@ private enum ShareSearchRecentEntryStableId: Hashable {
|
||||
|
||||
private enum ShareSearchRecentEntry: Comparable, Identifiable {
|
||||
case topPeers(PresentationTheme, PresentationStrings)
|
||||
case peer(index: Int, theme: PresentationTheme, peer: Peer, associatedPeer: Peer?, presence: PeerPresence?, PresentationStrings)
|
||||
case peer(index: Int, theme: PresentationTheme, peer: Peer, associatedPeer: Peer?, presence: EnginePeer.Presence?, PresentationStrings)
|
||||
|
||||
var stableId: ShareSearchRecentEntryStableId {
|
||||
switch self {
|
||||
@ -62,7 +62,7 @@ private enum ShareSearchRecentEntry: Comparable, Identifiable {
|
||||
return false
|
||||
}
|
||||
case let .peer(lhsIndex, lhsTheme, lhsPeer, lhsAssociatedPeer, lhsPresence, lhsStrings):
|
||||
if case let .peer(rhsIndex, rhsTheme, rhsPeer, rhsAssociatedPeer, rhsPresence, rhsStrings) = rhs, lhsPeer.isEqual(rhsPeer) && arePeersEqual(lhsAssociatedPeer, rhsAssociatedPeer) && lhsIndex == rhsIndex && lhsStrings === rhsStrings && lhsTheme === rhsTheme && arePeerPresencesEqual(lhsPresence, rhsPresence) {
|
||||
if case let .peer(rhsIndex, rhsTheme, rhsPeer, rhsAssociatedPeer, rhsPresence, rhsStrings) = rhs, lhsPeer.isEqual(rhsPeer) && arePeersEqual(lhsAssociatedPeer, rhsAssociatedPeer) && lhsIndex == rhsIndex && lhsStrings === rhsStrings && lhsTheme === rhsTheme && lhsPresence == rhsPresence {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -102,7 +102,7 @@ private enum ShareSearchRecentEntry: Comparable, Identifiable {
|
||||
private struct ShareSearchPeerEntry: Comparable, Identifiable {
|
||||
let index: Int32
|
||||
let peer: EngineRenderedPeer?
|
||||
let presence: PeerPresence?
|
||||
let presence: EnginePeer.Presence?
|
||||
let theme: PresentationTheme
|
||||
let strings: PresentationStrings
|
||||
|
||||
|
||||
@ -464,15 +464,14 @@ public func sentShareItems(account: Account, to peerIds: [PeerId], items: [Prepa
|
||||
return enqueueMessagesToMultiplePeers(account: account, peerIds: peerIds, messages: messages)
|
||||
|> castError(Void.self)
|
||||
|> mapToSignal { messageIds -> Signal<Float, Void> in
|
||||
let key: PostboxViewKey = .messages(Set(messageIds))
|
||||
return account.postbox.combinedView(keys: [key])
|
||||
return TelegramEngine(account: account).data.subscribe(EngineDataMap(
|
||||
messageIds.map(TelegramEngine.EngineData.Item.Messages.Message.init)
|
||||
))
|
||||
|> castError(Void.self)
|
||||
|> mapToSignal { view -> Signal<Float, Void> in
|
||||
if let messagesView = view.views[key] as? MessagesView {
|
||||
for (_, message) in messagesView.messages {
|
||||
if message.flags.contains(.Unsent) {
|
||||
return .complete()
|
||||
}
|
||||
|> mapToSignal { messages -> Signal<Float, Void> in
|
||||
for (_, message) in messages {
|
||||
if let message = message, message.flags.contains(.Unsent) {
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
return .single(1.0)
|
||||
|
||||
@ -1391,15 +1391,14 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
|> distinctUntilChanged
|
||||
|> runOn(.mainQueue())
|
||||
} else {
|
||||
rawAdminIds = accountContext.account.postbox.combinedView(keys: [.cachedPeerData(peerId: peerId)])
|
||||
|> map { views -> Set<PeerId> in
|
||||
guard let view = views.views[.cachedPeerData(peerId: peerId)] as? CachedPeerDataView else {
|
||||
rawAdminIds = accountContext.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.LegacyGroupParticipants(id: peerId)
|
||||
)
|
||||
|> map { participants -> Set<PeerId> in
|
||||
guard case let .known(participants) = participants else {
|
||||
return Set()
|
||||
}
|
||||
guard let cachedData = view.cachedPeerData as? CachedGroupData, let participants = cachedData.participants else {
|
||||
return Set()
|
||||
}
|
||||
return Set(participants.participants.compactMap { item -> PeerId? in
|
||||
return Set(participants.compactMap { item -> PeerId? in
|
||||
switch item {
|
||||
case .creator, .admin:
|
||||
return item.peerId
|
||||
@ -1413,11 +1412,11 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
|
||||
let adminIds = combineLatest(queue: .mainQueue(),
|
||||
rawAdminIds,
|
||||
accountContext.account.postbox.combinedView(keys: [.basicPeer(peerId)])
|
||||
accountContext.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
)
|
||||
|> map { rawAdminIds, view -> Set<PeerId> in
|
||||
|> map { rawAdminIds, peer -> Set<PeerId> in
|
||||
var rawAdminIds = rawAdminIds
|
||||
if let peerView = view.views[.basicPeer(peerId)] as? BasicPeerView, let peer = peerView.peer as? TelegramChannel {
|
||||
if case let .channel(peer) = peer {
|
||||
if peer.hasPermission(.manageCalls) {
|
||||
rawAdminIds.insert(accountContext.account.peerId)
|
||||
} else {
|
||||
@ -1969,15 +1968,14 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
|> distinctUntilChanged
|
||||
|> runOn(.mainQueue())
|
||||
} else {
|
||||
rawAdminIds = accountContext.account.postbox.combinedView(keys: [.cachedPeerData(peerId: peerId)])
|
||||
|> map { views -> Set<PeerId> in
|
||||
guard let view = views.views[.cachedPeerData(peerId: peerId)] as? CachedPeerDataView else {
|
||||
rawAdminIds = accountContext.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.LegacyGroupParticipants(id: peerId)
|
||||
)
|
||||
|> map { participants -> Set<PeerId> in
|
||||
guard case let .known(participants) = participants else {
|
||||
return Set()
|
||||
}
|
||||
guard let cachedData = view.cachedPeerData as? CachedGroupData, let participants = cachedData.participants else {
|
||||
return Set()
|
||||
}
|
||||
return Set(participants.participants.compactMap { item -> PeerId? in
|
||||
return Set(participants.compactMap { item -> PeerId? in
|
||||
switch item {
|
||||
case .creator, .admin:
|
||||
return item.peerId
|
||||
@ -1991,11 +1989,11 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
|
||||
let adminIds = combineLatest(queue: .mainQueue(),
|
||||
rawAdminIds,
|
||||
accountContext.account.postbox.combinedView(keys: [.basicPeer(peerId)])
|
||||
accountContext.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
)
|
||||
|> map { rawAdminIds, view -> Set<PeerId> in
|
||||
|> map { rawAdminIds, peer -> Set<PeerId> in
|
||||
var rawAdminIds = rawAdminIds
|
||||
if let peerView = view.views[.basicPeer(peerId)] as? BasicPeerView, let peer = peerView.peer as? TelegramChannel {
|
||||
if case let .channel(peer) = peer {
|
||||
if peer.hasPermission(.manageCalls) {
|
||||
rawAdminIds.insert(accountContext.account.peerId)
|
||||
} else {
|
||||
|
||||
@ -3,6 +3,11 @@ import Postbox
|
||||
import TelegramApi
|
||||
import MtProtoKit
|
||||
|
||||
public enum TelegramEngineAuthorizationState {
|
||||
case unauthorized(UnauthorizedAccountState)
|
||||
case authorized
|
||||
}
|
||||
|
||||
public extension TelegramEngineUnauthorized {
|
||||
final class Auth {
|
||||
private let account: UnauthorizedAccount
|
||||
@ -42,6 +47,26 @@ public extension TelegramEngineUnauthorized {
|
||||
public func uploadedPeerVideo(resource: MediaResource) -> Signal<UploadedPeerPhotoData, NoError> {
|
||||
return _internal_uploadedPeerVideo(postbox: self.account.postbox, network: self.account.network, messageMediaPreuploadManager: nil, resource: resource)
|
||||
}
|
||||
|
||||
public func state() -> Signal<TelegramEngineAuthorizationState?, NoError> {
|
||||
return self.account.postbox.stateView()
|
||||
|> map { view -> TelegramEngineAuthorizationState? in
|
||||
if let state = view.state as? UnauthorizedAccountState {
|
||||
return .unauthorized(state)
|
||||
} else if let _ = view.state as? AuthorizedAccountState {
|
||||
return .authorized
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func setState(state: UnauthorizedAccountState) -> Signal<Never, NoError> {
|
||||
return self.account.postbox.transaction { transaction -> Void in
|
||||
transaction.setState(state)
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
|
||||
public extension TelegramEngine.EngineData.Item {
|
||||
enum ChatList {
|
||||
|
||||
}
|
||||
}
|
||||
@ -333,5 +333,26 @@ public extension TelegramEngine.EngineData.Item {
|
||||
return EngineContentSettings(appConfiguration: appConfiguration)
|
||||
}
|
||||
}
|
||||
|
||||
public struct LocalizationList: TelegramEngineDataItem, PostboxViewDataItem {
|
||||
public typealias Result = LocalizationListState
|
||||
|
||||
public init() {
|
||||
}
|
||||
|
||||
var key: PostboxViewKey {
|
||||
return .preferences(keys: Set([PreferencesKeys.localizationListState]))
|
||||
}
|
||||
|
||||
func extract(view: PostboxView) -> Result {
|
||||
guard let view = view as? PreferencesView else {
|
||||
preconditionFailure()
|
||||
}
|
||||
guard let localizationListState = view.values[PreferencesKeys.localizationListState]?.get(LocalizationListState.self) else {
|
||||
return LocalizationListState.defaultSettings
|
||||
}
|
||||
return localizationListState
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,7 @@ import SwiftSignalKit
|
||||
import Postbox
|
||||
|
||||
public final class EngineTotalReadCounters {
|
||||
private let state: ChatListTotalUnreadState
|
||||
fileprivate let state: ChatListTotalUnreadState
|
||||
|
||||
public init(state: ChatListTotalUnreadState) {
|
||||
self.state = state
|
||||
@ -13,10 +13,16 @@ public final class EngineTotalReadCounters {
|
||||
}
|
||||
}
|
||||
|
||||
public struct EnginePeerReadCounters: Equatable {
|
||||
private let state: CombinedPeerReadState
|
||||
public extension EngineTotalReadCounters {
|
||||
func _asCounters() -> ChatListTotalUnreadState {
|
||||
return self.state
|
||||
}
|
||||
}
|
||||
|
||||
public init(state: CombinedPeerReadState) {
|
||||
public struct EnginePeerReadCounters: Equatable {
|
||||
fileprivate let state: CombinedPeerReadState?
|
||||
|
||||
public init(state: CombinedPeerReadState?) {
|
||||
self.state = state
|
||||
}
|
||||
|
||||
@ -25,24 +31,38 @@ public struct EnginePeerReadCounters: Equatable {
|
||||
}
|
||||
|
||||
public var count: Int32 {
|
||||
return self.state.count
|
||||
guard let state = self.state else {
|
||||
return 0
|
||||
}
|
||||
return state.count
|
||||
}
|
||||
|
||||
public var markedUnread: Bool {
|
||||
return self.state.markedUnread
|
||||
guard let state = self.state else {
|
||||
return false
|
||||
}
|
||||
return state.markedUnread
|
||||
}
|
||||
|
||||
|
||||
public var isUnread: Bool {
|
||||
return self.state.isUnread
|
||||
guard let state = self.state else {
|
||||
return false
|
||||
}
|
||||
return state.isUnread
|
||||
}
|
||||
|
||||
public func isOutgoingMessageIndexRead(_ index: EngineMessage.Index) -> Bool {
|
||||
return self.state.isOutgoingMessageIndexRead(index)
|
||||
guard let state = self.state else {
|
||||
return false
|
||||
}
|
||||
return state.isOutgoingMessageIndexRead(index)
|
||||
}
|
||||
|
||||
public func isIncomingMessageIndexRead(_ index: EngineMessage.Index) -> Bool {
|
||||
return self.state.isIncomingMessageIndexRead(index)
|
||||
guard let state = self.state else {
|
||||
return false
|
||||
}
|
||||
return state.isIncomingMessageIndexRead(index)
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,6 +70,10 @@ public extension EnginePeerReadCounters {
|
||||
init(incomingReadId: EngineMessage.Id.Id, outgoingReadId: EngineMessage.Id.Id, count: Int32, markedUnread: Bool) {
|
||||
self.init(state: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, .idBased(maxIncomingReadId: incomingReadId, maxOutgoingReadId: outgoingReadId, maxKnownId: max(incomingReadId, outgoingReadId), count: count, markedUnread: markedUnread))]))
|
||||
}
|
||||
|
||||
func _asReadCounters() -> CombinedPeerReadState? {
|
||||
return self.state
|
||||
}
|
||||
}
|
||||
|
||||
public extension TelegramEngine.EngineData.Item {
|
||||
@ -128,8 +152,8 @@ public extension TelegramEngine.EngineData.Item {
|
||||
}
|
||||
}
|
||||
|
||||
public struct ReadState: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||
public typealias Result = CombinedPeerReadState?
|
||||
public struct PeerReadCounters: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||
public typealias Result = EnginePeerReadCounters
|
||||
|
||||
fileprivate let id: EnginePeer.Id
|
||||
public var mapKey: EnginePeer.Id {
|
||||
@ -149,7 +173,7 @@ public extension TelegramEngine.EngineData.Item {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
return view.state
|
||||
return EnginePeerReadCounters(state: view.state)
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,5 +270,63 @@ public extension TelegramEngine.EngineData.Item {
|
||||
return view.inclusion.groupId.flatMap(EngineChatList.Group.init)
|
||||
}
|
||||
}
|
||||
|
||||
public struct MessageCount: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||
public struct ItemKey: Hashable {
|
||||
public var peerId: EnginePeer.Id
|
||||
public var tag: MessageTags
|
||||
}
|
||||
|
||||
public typealias Result = Int?
|
||||
|
||||
fileprivate var peerId: EnginePeer.Id
|
||||
fileprivate var tag: MessageTags
|
||||
public var mapKey: ItemKey {
|
||||
return ItemKey(peerId: self.peerId, tag: self.tag)
|
||||
}
|
||||
|
||||
public init(peerId: EnginePeer.Id, tag: MessageTags) {
|
||||
self.peerId = peerId
|
||||
self.tag = tag
|
||||
}
|
||||
|
||||
var key: PostboxViewKey {
|
||||
return .historyTagSummaryView(tag: tag, peerId: peerId, namespace: Namespaces.Message.Cloud)
|
||||
}
|
||||
|
||||
func extract(view: PostboxView) -> Result {
|
||||
guard let view = view as? MessageHistoryTagSummaryView else {
|
||||
preconditionFailure()
|
||||
}
|
||||
return view.count.flatMap(Int.init)
|
||||
}
|
||||
}
|
||||
|
||||
public struct TopMessage: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||
public typealias Result = EngineMessage?
|
||||
|
||||
fileprivate var id: EnginePeer.Id
|
||||
public var mapKey: EnginePeer.Id {
|
||||
return self.id
|
||||
}
|
||||
|
||||
public init(id: EnginePeer.Id) {
|
||||
self.id = id
|
||||
}
|
||||
|
||||
var key: PostboxViewKey {
|
||||
return .topChatMessage(peerIds: [self.id])
|
||||
}
|
||||
|
||||
func extract(view: PostboxView) -> Result {
|
||||
guard let view = view as? TopChatMessageView else {
|
||||
preconditionFailure()
|
||||
}
|
||||
guard let message = view.messages[self.id] else {
|
||||
return nil
|
||||
}
|
||||
return EngineMessage(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
|
||||
public extension TelegramEngine.EngineData.Item {
|
||||
enum OrderedLists {
|
||||
public struct ListItems: TelegramEngineDataItem, PostboxViewDataItem {
|
||||
public typealias Result = [OrderedItemListEntry]
|
||||
|
||||
private let collectionId: Int32
|
||||
|
||||
public init(collectionId: Int32) {
|
||||
self.collectionId = collectionId
|
||||
}
|
||||
|
||||
var key: PostboxViewKey {
|
||||
return .orderedItemList(id: self.collectionId)
|
||||
}
|
||||
|
||||
func extract(view: PostboxView) -> Result {
|
||||
guard let view = view as? OrderedItemListView else {
|
||||
preconditionFailure()
|
||||
}
|
||||
return view.items
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,7 @@ import SwiftSignalKit
|
||||
import Postbox
|
||||
|
||||
public typealias EngineExportedPeerInvitation = ExportedInvitation
|
||||
public typealias EngineSecretChatKeyFingerprint = SecretChatKeyFingerprint
|
||||
|
||||
public enum EnginePeerCachedInfoItem<T> {
|
||||
case known(T)
|
||||
@ -782,5 +783,34 @@ public extension TelegramEngine.EngineData.Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct SecretChatKeyFingerprint: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||
public typealias Result = EngineSecretChatKeyFingerprint?
|
||||
|
||||
fileprivate var id: EnginePeer.Id
|
||||
public var mapKey: EnginePeer.Id {
|
||||
return self.id
|
||||
}
|
||||
|
||||
public init(id: EnginePeer.Id) {
|
||||
self.id = id
|
||||
}
|
||||
|
||||
var key: PostboxViewKey {
|
||||
return .peerChatState(peerId: self.id)
|
||||
}
|
||||
|
||||
func extract(view: PostboxView) -> Result {
|
||||
guard let view = view as? PeerChatStateView else {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
if let peerChatState = view.chatState?.getLegacy() as? SecretChatState {
|
||||
return peerChatState.keyFingerprint
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -95,6 +95,37 @@ public final class EngineDataList<Item: TelegramEngineDataItem & TelegramEngineM
|
||||
}
|
||||
}
|
||||
|
||||
public final class EngineDataOptional<Item: TelegramEngineDataItem>: TelegramEngineDataItem, AnyPostboxViewDataItem {
|
||||
public typealias Result = Item.Result?
|
||||
|
||||
private let item: Item?
|
||||
|
||||
public init(_ item: Item?) {
|
||||
self.item = item
|
||||
}
|
||||
|
||||
var keys: [PostboxViewKey] {
|
||||
var keys = Set<PostboxViewKey>()
|
||||
if let item = self.item {
|
||||
for key in (item as! AnyPostboxViewDataItem).keys {
|
||||
keys.insert(key)
|
||||
}
|
||||
}
|
||||
return Array(keys)
|
||||
}
|
||||
|
||||
func _extract(views: [PostboxViewKey: PostboxView]) -> Any {
|
||||
var result: [Item.Result] = []
|
||||
|
||||
if let item = self.item {
|
||||
let itemResult = (item as! AnyPostboxViewDataItem)._extract(views: views)
|
||||
result.append(itemResult as! Item.Result)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
public extension TelegramEngine {
|
||||
final class EngineData {
|
||||
public struct Item {
|
||||
|
||||
@ -25,5 +25,14 @@ public extension TelegramEngine {
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
|
||||
public func clear(collectionIds: [Int8]) -> Signal<Never, NoError> {
|
||||
return self.account.postbox.transaction { transaction -> Void in
|
||||
for id in collectionIds {
|
||||
transaction.clearItemCacheCollection(collectionId: id)
|
||||
}
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,8 +3,7 @@ import Postbox
|
||||
import SwiftSignalKit
|
||||
import TelegramApi
|
||||
|
||||
|
||||
public func removeSavedLocalization(transaction: Transaction, languageCode: String) {
|
||||
func _internal_removeSavedLocalization(transaction: Transaction, languageCode: String) {
|
||||
updateLocalizationListStateInteractively(transaction: transaction, { state in
|
||||
var state = state
|
||||
state.availableSavedLocalizations = state.availableSavedLocalizations.filter({ $0.languageCode != languageCode })
|
||||
|
||||
@ -32,6 +32,13 @@ public extension TelegramEngine {
|
||||
public func downloadAndApplyLocalization(accountManager: AccountManager<TelegramAccountManagerTypes>, languageCode: String) -> Signal<Void, DownloadAndApplyLocalizationError> {
|
||||
return _internal_downloadAndApplyLocalization(accountManager: accountManager, postbox: self.account.postbox, network: self.account.network, languageCode: languageCode)
|
||||
}
|
||||
|
||||
public func removeSavedLocalization(languageCode: String) -> Signal<Never, NoError> {
|
||||
return self.account.postbox.transaction { transaction -> Void in
|
||||
_internal_removeSavedLocalization(transaction: transaction, languageCode: languageCode)
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -415,5 +415,19 @@ public extension TelegramEngine {
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
|
||||
public func debugAddHoles() -> Signal<Never, NoError> {
|
||||
return self.account.postbox.transaction { transaction -> Void in
|
||||
transaction.addHolesEverywhere(peerNamespaces: [Namespaces.Peer.CloudUser, Namespaces.Peer.CloudGroup, Namespaces.Peer.CloudChannel], holeNamespace: Namespaces.Message.Cloud)
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
|
||||
public func debugReindexUnreadCounters() -> Signal<Never, NoError> {
|
||||
return self.account.postbox.transaction { transaction -> Void in
|
||||
transaction.reindexUnreadCounters()
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,5 +131,29 @@ public extension TelegramEngine {
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
|
||||
public func reorderStickerPacks(namespace: ItemCollectionId.Namespace, itemIds: [ItemCollectionId]) -> Signal<Never, NoError> {
|
||||
return self.account.postbox.transaction { transaction -> Void in
|
||||
let infos = transaction.getItemCollectionsInfos(namespace: namespace)
|
||||
|
||||
var packDict: [ItemCollectionId: Int] = [:]
|
||||
for i in 0 ..< infos.count {
|
||||
packDict[infos[i].0] = i
|
||||
}
|
||||
var tempSortedPacks: [(ItemCollectionId, ItemCollectionInfo)] = []
|
||||
var processedPacks = Set<ItemCollectionId>()
|
||||
for id in itemIds {
|
||||
if let index = packDict[id] {
|
||||
tempSortedPacks.append(infos[index])
|
||||
processedPacks.insert(id)
|
||||
}
|
||||
}
|
||||
let restPacks = infos.filter { !processedPacks.contains($0.0) }
|
||||
let sortedPacks = restPacks + tempSortedPacks
|
||||
addSynchronizeInstalledStickerPacksOperation(transaction: transaction, namespace: namespace, content: .sync, noDelay: false)
|
||||
transaction.replaceItemCollectionInfos(namespace: namespace, itemCollectionInfos: sortedPacks)
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,10 +59,9 @@ private final class DeviceSpecificContactImportContexts {
|
||||
if context.reference != reference {
|
||||
context.reference = reference
|
||||
|
||||
let key: PostboxViewKey = .basicPeer(peerId)
|
||||
let signal = account.postbox.combinedView(keys: [key])
|
||||
|> map { view -> String? in
|
||||
if let user = (view.views[key] as? BasicPeerView)?.peer as? TelegramUser {
|
||||
let signal = TelegramEngine(account: account).data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
|> map { peer -> String? in
|
||||
if case let .user(user) = peer {
|
||||
return user.phone
|
||||
} else {
|
||||
return nil
|
||||
|
||||
@ -526,7 +526,7 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
||||
|
||||
self.hasActiveAudioSession.set(MediaManagerImpl.globalAudioSession.isActive())
|
||||
|
||||
let applicationBindings = TelegramApplicationBindings(isMainApp: true, appBundleId: baseAppBundleId, containerPath: appGroupUrl.path, appSpecificScheme: buildConfig.appSpecificUrlScheme, openUrl: { url in
|
||||
let applicationBindings = TelegramApplicationBindings(isMainApp: true, appBundleId: baseAppBundleId, appBuildType: buildConfig.isAppStoreBuild ? .public : .internal, containerPath: appGroupUrl.path, appSpecificScheme: buildConfig.appSpecificUrlScheme, openUrl: { url in
|
||||
var parsedUrl = URL(string: url)
|
||||
if let parsed = parsedUrl {
|
||||
if parsed.scheme == nil || parsed.scheme!.isEmpty {
|
||||
|
||||
@ -69,11 +69,11 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
|
||||
super.init(mode: .single, theme: NavigationControllerTheme(statusBar: navigationStatusBar, navigationBar: AuthorizationSequenceController.navigationBarTheme(presentationData.theme), emptyAreaColor: .black))
|
||||
|
||||
self.stateDisposable = (account.postbox.stateView()
|
||||
|> map { view -> InnerState in
|
||||
if let _ = view.state as? AuthorizedAccountState {
|
||||
self.stateDisposable = (TelegramEngineUnauthorized(account: self.account).auth.state()
|
||||
|> map { state -> InnerState in
|
||||
if case .authorized = state {
|
||||
return .authorized
|
||||
} else if let state = view.state as? UnauthorizedAccountState {
|
||||
} else if case let .unauthorized(state) = state {
|
||||
return .state(state.contents)
|
||||
} else {
|
||||
return .state(.empty)
|
||||
@ -122,9 +122,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
|
||||
let countryCode = defaultCountryCode()
|
||||
|
||||
let _ = (strongSelf.account.postbox.transaction { transaction -> Void in
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: isTestingEnvironment, masterDatacenterId: masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: "")))
|
||||
}).start()
|
||||
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: isTestingEnvironment, masterDatacenterId: masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -154,9 +152,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
transaction.removeAuth()
|
||||
}).start()
|
||||
} else {
|
||||
let _ = strongSelf.account.postbox.transaction({ transaction -> Void in
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .empty))
|
||||
}).start()
|
||||
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .empty)).start()
|
||||
}
|
||||
})
|
||||
controller.accountUpdated = { [weak self] updatedAccount in
|
||||
@ -282,9 +278,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
}
|
||||
let countryCode = defaultCountryCode()
|
||||
|
||||
let _ = (strongSelf.account.postbox.transaction { transaction -> Void in
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: "")))
|
||||
}).start()
|
||||
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start()
|
||||
})
|
||||
controller.loginWithCode = { [weak self, weak controller] code in
|
||||
if let strongSelf = self {
|
||||
@ -331,9 +325,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
return
|
||||
}
|
||||
let account = strongSelf.account
|
||||
let _ = (strongSelf.account.postbox.transaction { transaction -> Void in
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty))
|
||||
}).start()
|
||||
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty)).start()
|
||||
})]), on: .root, blockInteraction: false, completion: {})
|
||||
})
|
||||
], actionLayout: .vertical, dismissOnOutsideTap: true)
|
||||
@ -378,9 +370,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
case .codeExpired:
|
||||
text = strongSelf.presentationData.strings.Login_CodeExpired
|
||||
let account = strongSelf.account
|
||||
let _ = (strongSelf.account.postbox.transaction { transaction -> Void in
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty))
|
||||
}).start()
|
||||
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty)).start()
|
||||
}
|
||||
|
||||
if resetCode {
|
||||
@ -437,9 +427,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
controller.reset = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let account = strongSelf.account
|
||||
let _ = (strongSelf.account.postbox.transaction { transaction -> Void in
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty))
|
||||
}).start()
|
||||
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty)).start()
|
||||
}
|
||||
}
|
||||
controller.updateData(number: formatPhoneNumber(number), codeType: type, nextType: nextType, timeout: timeout, termsOfService: termsOfService)
|
||||
@ -464,9 +452,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
}
|
||||
let countryCode = defaultCountryCode()
|
||||
|
||||
let _ = (strongSelf.account.postbox.transaction { transaction -> Void in
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: "")))
|
||||
}).start()
|
||||
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start()
|
||||
})
|
||||
controller.loginWithPassword = { [weak self, weak controller] password in
|
||||
if let strongSelf = self {
|
||||
@ -503,11 +489,16 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
if let strongSelf = self, let strongController = controller {
|
||||
strongController.inProgress = false
|
||||
|
||||
let _ = (strongSelf.account.postbox.transaction { transaction -> Void in
|
||||
if let state = transaction.getState() as? UnauthorizedAccountState, case let .passwordEntry(hint, number, code, _, syncContacts) = state.contents {
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .passwordRecovery(hint: hint, number: number, code: code, emailPattern: pattern, syncContacts: syncContacts)))
|
||||
let _ = (TelegramEngineUnauthorized(account: strongSelf.account).auth.state()
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { state in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
}).start()
|
||||
if case let .unauthorized(state) = state, case let .passwordEntry(hint, number, code, _, syncContacts) = state.contents {
|
||||
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .passwordRecovery(hint: hint, number: number, code: code, emailPattern: pattern, syncContacts: syncContacts))).start()
|
||||
}
|
||||
})
|
||||
}
|
||||
}, error: { error in
|
||||
guard let strongController = controller else {
|
||||
@ -574,11 +565,16 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
return
|
||||
}
|
||||
|
||||
let _ = (strongSelf.account.postbox.transaction { transaction -> Void in
|
||||
if let state = transaction.getState() as? UnauthorizedAccountState, case let .passwordRecovery(hint, number, code, _, syncContacts) = state.contents {
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .passwordEntry(hint: hint, number: number, code: code, suggestReset: true, syncContacts: syncContacts)))
|
||||
let _ = (TelegramEngineUnauthorized(account: strongSelf.account).auth.state()
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { state in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
}).start()
|
||||
if case let .unauthorized(state) = state, case let .passwordRecovery(hint, number, code, _, syncContacts) = state.contents {
|
||||
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .passwordEntry(hint: hint, number: number, code: code, suggestReset: true, syncContacts: syncContacts))).start()
|
||||
}
|
||||
})
|
||||
}
|
||||
return controller
|
||||
}
|
||||
@ -601,9 +597,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
}
|
||||
let countryCode = defaultCountryCode()
|
||||
|
||||
let _ = (strongSelf.account.postbox.transaction { transaction -> Void in
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: "")))
|
||||
}).start()
|
||||
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start()
|
||||
})
|
||||
controller.reset = { [weak self, weak controller] in
|
||||
if let strongSelf = self, let strongController = controller {
|
||||
@ -637,9 +631,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
controller.logout = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let account = strongSelf.account
|
||||
let _ = (strongSelf.account.postbox.transaction { transaction -> Void in
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty))
|
||||
}).start()
|
||||
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty)).start()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -665,9 +657,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
}
|
||||
let countryCode = defaultCountryCode()
|
||||
|
||||
let _ = (strongSelf.account.postbox.transaction { transaction -> Void in
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: "")))
|
||||
}).start()
|
||||
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start()
|
||||
}, displayCancel: displayCancel)
|
||||
controller.signUpWithName = { [weak self, weak controller] firstName, lastName, avatarData, avatarAsset, avatarAdjustments in
|
||||
if let strongSelf = self {
|
||||
|
||||
@ -547,13 +547,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
locationBroadcastPanelSource = .none
|
||||
groupCallPanelSource = .none
|
||||
let promise = Promise<Message?>()
|
||||
let key = PostboxViewKey.messages([replyThreadMessage.messageId])
|
||||
promise.set(context.account.postbox.combinedView(keys: [key])
|
||||
|> map { views -> Message? in
|
||||
guard let view = views.views[key] as? MessagesView else {
|
||||
promise.set(context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.Message(id: replyThreadMessage.messageId))
|
||||
|> map { message -> Message? in
|
||||
guard let message = message else {
|
||||
return nil
|
||||
}
|
||||
return view.messages[replyThreadMessage.messageId]
|
||||
return message._asMessage()
|
||||
})
|
||||
self.chatLocationInfoData = .replyThread(promise)
|
||||
case .feed:
|
||||
@ -1075,7 +1074,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.dismissMessageReactionContexts()
|
||||
|
||||
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, postbox: strongSelf.context.account.postbox, message: message, selectAll: selectAll)), items: .single(actions), recognizer: recognizer, gesture: gesture)
|
||||
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, engine: strongSelf.context.engine, message: message, selectAll: selectAll)), items: .single(actions), recognizer: recognizer, gesture: gesture)
|
||||
controller.getOverlayViews = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return []
|
||||
@ -1207,7 +1206,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.dismissMessageReactionContexts()
|
||||
|
||||
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageReactionContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, postbox: strongSelf.context.account.postbox, message: message, contentView: sourceView)), items: .single(items), recognizer: nil, gesture: gesture)
|
||||
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageReactionContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, engine: strongSelf.context.engine, message: message, contentView: sourceView)), items: .single(items), recognizer: nil, gesture: gesture)
|
||||
|
||||
dismissController = { [weak controller] completion in
|
||||
controller?.dismiss(completion: {
|
||||
@ -2642,7 +2641,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.dismissMessageReactionContexts()
|
||||
|
||||
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, postbox: strongSelf.context.account.postbox, message: message._asMessage(), selectAll: true)), items: .single(ContextController.Items(content: .list(actions))), recognizer: nil)
|
||||
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, engine: strongSelf.context.engine, message: message._asMessage(), selectAll: true)), items: .single(ContextController.Items(content: .list(actions))), recognizer: nil)
|
||||
strongSelf.currentContextController = controller
|
||||
strongSelf.forEachController({ controller in
|
||||
if let controller = controller as? TooltipScreen {
|
||||
@ -2720,7 +2719,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.dismissMessageReactionContexts()
|
||||
|
||||
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, postbox: strongSelf.context.account.postbox, message: topMessage, selectAll: true)), items: .single(ContextController.Items(content: .list(actions))), recognizer: nil)
|
||||
let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, engine: strongSelf.context.engine, message: topMessage, selectAll: true)), items: .single(ContextController.Items(content: .list(actions))), recognizer: nil)
|
||||
strongSelf.currentContextController = controller
|
||||
strongSelf.forEachController({ controller in
|
||||
if let controller = controller as? TooltipScreen {
|
||||
@ -8568,42 +8567,34 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
})
|
||||
|
||||
if case let .peer(peerId) = self.chatLocation {
|
||||
let unreadCountsKey: PostboxViewKey = .unreadCounts(items: [.peer(peerId), .total(nil)])
|
||||
let notificationSettingsKey: PostboxViewKey = .peerNotificationSettings(peerIds: Set([peerId]))
|
||||
self.chatUnreadCountDisposable = (self.context.account.postbox.combinedView(keys: [unreadCountsKey, notificationSettingsKey])
|
||||
|> deliverOnMainQueue).start(next: { [weak self] views in
|
||||
if let strongSelf = self {
|
||||
var unreadCount: Int32 = 0
|
||||
var totalChatCount: Int32 = 0
|
||||
|
||||
let inAppSettings = strongSelf.context.sharedContext.currentInAppNotificationSettings.with { $0 }
|
||||
if let view = views.views[unreadCountsKey] as? UnreadMessageCountsView {
|
||||
if let count = view.count(for: .peer(peerId)) {
|
||||
unreadCount = count
|
||||
}
|
||||
if let (_, state) = view.total() {
|
||||
let (count, _) = renderedTotalUnreadCount(inAppSettings: inAppSettings, totalUnreadState: state)
|
||||
totalChatCount = count
|
||||
}
|
||||
}
|
||||
|
||||
if let view = views.views[notificationSettingsKey] as? PeerNotificationSettingsView, let notificationSettings = view.notificationSettings[peerId] {
|
||||
var globalRemainingUnreadChatCount = totalChatCount
|
||||
if !notificationSettings.isRemovedFromTotalUnreadCount(default: false) && unreadCount > 0 {
|
||||
if case .messages = inAppSettings.totalUnreadCountDisplayCategory {
|
||||
globalRemainingUnreadChatCount -= unreadCount
|
||||
} else {
|
||||
globalRemainingUnreadChatCount -= 1
|
||||
}
|
||||
}
|
||||
|
||||
if globalRemainingUnreadChatCount > 0 {
|
||||
strongSelf.navigationItem.badge = "\(globalRemainingUnreadChatCount)"
|
||||
} else {
|
||||
strongSelf.navigationItem.badge = ""
|
||||
}
|
||||
self.chatUnreadCountDisposable = (self.context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Messages.PeerUnreadCount(id: peerId),
|
||||
TelegramEngine.EngineData.Item.Messages.TotalReadCounters(),
|
||||
TelegramEngine.EngineData.Item.Peer.NotificationSettings(id: peerId)
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peerUnreadCount, totalReadCounters, notificationSettings in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let unreadCount: Int32 = Int32(peerUnreadCount)
|
||||
|
||||
let inAppSettings = strongSelf.context.sharedContext.currentInAppNotificationSettings.with { $0 }
|
||||
let totalChatCount: Int32 = renderedTotalUnreadCount(inAppSettings: inAppSettings, totalUnreadState: totalReadCounters._asCounters()).0
|
||||
|
||||
var globalRemainingUnreadChatCount = totalChatCount
|
||||
if !notificationSettings._asNotificationSettings().isRemovedFromTotalUnreadCount(default: false) && unreadCount > 0 {
|
||||
if case .messages = inAppSettings.totalUnreadCountDisplayCategory {
|
||||
globalRemainingUnreadChatCount -= unreadCount
|
||||
} else {
|
||||
globalRemainingUnreadChatCount -= 1
|
||||
}
|
||||
}
|
||||
|
||||
if globalRemainingUnreadChatCount > 0 {
|
||||
strongSelf.navigationItem.badge = "\(globalRemainingUnreadChatCount)"
|
||||
} else {
|
||||
strongSelf.navigationItem.badge = ""
|
||||
}
|
||||
})
|
||||
|
||||
self.chatUnreadMentionCountDisposable = (self.context.account.viewTracker.unseenPersonalMessagesAndReactionCount(peerId: peerId) |> deliverOnMainQueue).start(next: { [weak self] mentionCount, reactionCount in
|
||||
|
||||
@ -931,20 +931,15 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
|
||||
let customChannelDiscussionReadState: Signal<MessageId?, NoError>
|
||||
if case let .peer(peerId) = chatLocation, peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
let cachedDataKey = PostboxViewKey.cachedPeerData(peerId: peerId)
|
||||
let peerKey = PostboxViewKey.basicPeer(peerId)
|
||||
customChannelDiscussionReadState = context.account.postbox.combinedView(keys: [cachedDataKey, peerKey])
|
||||
|> mapToSignal { views -> Signal<PeerId?, NoError> in
|
||||
guard let view = views.views[cachedDataKey] as? CachedPeerDataView else {
|
||||
customChannelDiscussionReadState = context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.LinkedDiscussionPeerId(id: peerId),
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)
|
||||
)
|
||||
|> mapToSignal { linkedDiscussionPeerId, peer -> Signal<PeerId?, NoError> in
|
||||
guard case let .channel(peer) = peer, case .broadcast = peer.info else {
|
||||
return .single(nil)
|
||||
}
|
||||
guard let peer = (views.views[peerKey] as? BasicPeerView)?.peer as? TelegramChannel, case .broadcast = peer.info else {
|
||||
return .single(nil)
|
||||
}
|
||||
guard let cachedData = view.cachedPeerData as? CachedChannelData else {
|
||||
return .single(nil)
|
||||
}
|
||||
guard case let .known(value) = cachedData.linkedDiscussionPeerId else {
|
||||
guard case let .known(value) = linkedDiscussionPeerId else {
|
||||
return .single(nil)
|
||||
}
|
||||
return .single(value)
|
||||
@ -954,13 +949,10 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
guard let discussionPeerId = discussionPeerId else {
|
||||
return .single(nil)
|
||||
}
|
||||
let key = PostboxViewKey.combinedReadState(peerId: discussionPeerId)
|
||||
return context.account.postbox.combinedView(keys: [key])
|
||||
|> map { views -> MessageId? in
|
||||
guard let view = views.views[key] as? CombinedReadStateView else {
|
||||
return nil
|
||||
}
|
||||
guard let state = view.state else {
|
||||
|
||||
return context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.PeerReadCounters(id: discussionPeerId))
|
||||
|> map { readCounters -> MessageId? in
|
||||
guard let state = readCounters._asReadCounters() else {
|
||||
return nil
|
||||
}
|
||||
for (namespace, namespaceState) in state.states {
|
||||
|
||||
@ -575,7 +575,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
)
|
||||
}
|
||||
|
||||
let readState = context.engine.data.get(TelegramEngine.EngineData.Item.Messages.ReadState(id: messages[0].id.peerId))
|
||||
let readCounters = context.engine.data.get(TelegramEngine.EngineData.Item.Messages.PeerReadCounters(id: messages[0].id.peerId))
|
||||
|
||||
let dataSignal: Signal<(MessageContextMenuData, [MessageId: ChatUpdatingMessageMedia], InfoSummaryData, AppConfiguration, Bool, Int32, AvailableReactions?, TranslationSettings, LoggingSettings, NotificationSoundList?), NoError> = combineLatest(
|
||||
loadLimits,
|
||||
@ -585,13 +585,13 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
context.account.pendingUpdateMessageManager.updatingMessageMedia
|
||||
|> take(1),
|
||||
infoSummaryData,
|
||||
readState,
|
||||
readCounters,
|
||||
ApplicationSpecificNotice.getMessageViewsPrivacyTips(accountManager: context.sharedContext.accountManager),
|
||||
context.engine.stickers.availableReactions(),
|
||||
context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings, SharedDataKeys.loggingSettings]),
|
||||
context.engine.peers.notificationSoundList() |> take(1)
|
||||
)
|
||||
|> map { limitsAndAppConfig, stickerSaveStatus, resourceStatus, messageActions, updatingMessageMedia, infoSummaryData, readState, messageViewsPrivacyTips, availableReactions, sharedData, notificationSoundList -> (MessageContextMenuData, [MessageId: ChatUpdatingMessageMedia], InfoSummaryData, AppConfiguration, Bool, Int32, AvailableReactions?, TranslationSettings, LoggingSettings, NotificationSoundList?) in
|
||||
|> map { limitsAndAppConfig, stickerSaveStatus, resourceStatus, messageActions, updatingMessageMedia, infoSummaryData, readCounters, messageViewsPrivacyTips, availableReactions, sharedData, notificationSoundList -> (MessageContextMenuData, [MessageId: ChatUpdatingMessageMedia], InfoSummaryData, AppConfiguration, Bool, Int32, AvailableReactions?, TranslationSettings, LoggingSettings, NotificationSoundList?) in
|
||||
let (limitsConfiguration, appConfig) = limitsAndAppConfig
|
||||
var canEdit = false
|
||||
if !isAction {
|
||||
@ -599,10 +599,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
canEdit = canEditMessage(context: context, limitsConfiguration: limitsConfiguration, message: message)
|
||||
}
|
||||
|
||||
var isMessageRead = false
|
||||
if let readState = readState {
|
||||
isMessageRead = readState.isOutgoingMessageIndexRead(message.index)
|
||||
}
|
||||
let isMessageRead = readCounters.isOutgoingMessageIndexRead(message.index)
|
||||
|
||||
let translationSettings: TranslationSettings
|
||||
if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.translationSettings]?.get(TranslationSettings.self) {
|
||||
|
||||
@ -290,22 +290,16 @@ final class ChatMediaInputGifPane: ChatMediaInputPane, UIScrollViewDelegate {
|
||||
let filesSignal: Signal<(MultiplexedVideoNodeFiles, String?), NoError>
|
||||
switch self.mode {
|
||||
case .recent:
|
||||
filesSignal = combineLatest(self.trendingPromise.get(), self.context.account.postbox.combinedView(keys: [.orderedItemList(id: Namespaces.OrderedItemList.CloudRecentGifs)]))
|
||||
|> map { trending, view -> (MultiplexedVideoNodeFiles, String?) in
|
||||
var recentGifs: OrderedItemListView?
|
||||
if let orderedView = view.views[.orderedItemList(id: Namespaces.OrderedItemList.CloudRecentGifs)] {
|
||||
recentGifs = orderedView as? OrderedItemListView
|
||||
}
|
||||
|
||||
filesSignal = combineLatest(
|
||||
self.trendingPromise.get(),
|
||||
self.context.engine.data.subscribe(TelegramEngine.EngineData.Item.OrderedLists.ListItems(collectionId: Namespaces.OrderedItemList.CloudRecentGifs))
|
||||
)
|
||||
|> map { trending, cloudRecentGifs -> (MultiplexedVideoNodeFiles, String?) in
|
||||
var saved: [MultiplexedVideoNodeFile] = []
|
||||
|
||||
if let recentGifs = recentGifs {
|
||||
saved = recentGifs.items.map { item in
|
||||
let file = item.contents.get(RecentMediaItem.self)!.media
|
||||
return MultiplexedVideoNodeFile(file: .savedGif(media: file), contextResult: nil)
|
||||
}
|
||||
} else {
|
||||
saved = []
|
||||
saved = cloudRecentGifs.map { item in
|
||||
let file = item.contents.get(RecentMediaItem.self)!.media
|
||||
return MultiplexedVideoNodeFile(file: .savedGif(media: file), contextResult: nil)
|
||||
}
|
||||
|
||||
return (MultiplexedVideoNodeFiles(saved: saved, trending: trending?.files ?? [], isSearch: false, canLoadMore: false, isStale: false), nil)
|
||||
|
||||
@ -730,27 +730,7 @@ final class ChatMediaInputNode: ChatInputNode {
|
||||
break
|
||||
}
|
||||
}
|
||||
let _ = (context.account.postbox.transaction { transaction -> Void in
|
||||
let namespace = Namespaces.ItemCollection.CloudStickerPacks
|
||||
let infos = transaction.getItemCollectionsInfos(namespace: namespace)
|
||||
|
||||
var packDict: [ItemCollectionId: Int] = [:]
|
||||
for i in 0 ..< infos.count {
|
||||
packDict[infos[i].0] = i
|
||||
}
|
||||
var tempSortedPacks: [(ItemCollectionId, ItemCollectionInfo)] = []
|
||||
var processedPacks = Set<ItemCollectionId>()
|
||||
for id in currentIds {
|
||||
if let index = packDict[id] {
|
||||
tempSortedPacks.append(infos[index])
|
||||
processedPacks.insert(id)
|
||||
}
|
||||
}
|
||||
let restPacks = infos.filter { !processedPacks.contains($0.0) }
|
||||
let sortedPacks = restPacks + tempSortedPacks
|
||||
addSynchronizeInstalledStickerPacksOperation(transaction: transaction, namespace: namespace, content: .sync, noDelay: false)
|
||||
transaction.replaceItemCollectionInfos(namespace: namespace, itemCollectionInfos: sortedPacks)
|
||||
}
|
||||
let _ = (context.engine.stickers.reorderStickerPacks(namespace: Namespaces.ItemCollection.CloudStickerPacks, itemIds: currentIds)
|
||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||
temporaryPackOrder.set(.single(nil))
|
||||
|
||||
@ -1091,16 +1071,10 @@ final class ChatMediaInputNode: ChatInputNode {
|
||||
})
|
||||
self.trendingInteraction = trendingInteraction
|
||||
|
||||
let preferencesViewKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.appConfiguration]))
|
||||
let reactions: Signal<[String], NoError> = context.account.postbox.combinedView(keys: [preferencesViewKey])
|
||||
|> map { views -> [String] in
|
||||
let reactions: Signal<[String], NoError> = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Configuration.App())
|
||||
|> map { appConfiguration -> [String] in
|
||||
let defaultReactions: [String] = ["👍", "👎", "😍", "😂", "😯", "😕", "😢", "😡", "💪", "👏", "🙈", "😒"]
|
||||
guard let view = views.views[preferencesViewKey] as? PreferencesView else {
|
||||
return defaultReactions
|
||||
}
|
||||
guard let appConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) else {
|
||||
return defaultReactions
|
||||
}
|
||||
|
||||
guard let data = appConfiguration.data, let emojis = data["gif_search_emojies"] as? [String] else {
|
||||
return defaultReactions
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import UIKit
|
||||
import Display
|
||||
import ContextUI
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
|
||||
final class ChatMessageContextExtractedContentSource: ContextExtractedContentSource {
|
||||
@ -11,7 +12,7 @@ final class ChatMessageContextExtractedContentSource: ContextExtractedContentSou
|
||||
let blurBackground: Bool = true
|
||||
|
||||
private weak var chatNode: ChatControllerNode?
|
||||
private let postbox: Postbox
|
||||
private let engine: TelegramEngine
|
||||
private let message: Message
|
||||
private let selectAll: Bool
|
||||
|
||||
@ -19,24 +20,21 @@ final class ChatMessageContextExtractedContentSource: ContextExtractedContentSou
|
||||
if self.message.adAttribute != nil {
|
||||
return .single(false)
|
||||
}
|
||||
let viewKey = PostboxViewKey.messages(Set([self.message.id]))
|
||||
return self.postbox.combinedView(keys: [viewKey])
|
||||
|> map { views -> Bool in
|
||||
guard let view = views.views[viewKey] as? MessagesView else {
|
||||
|
||||
return self.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.Message(id: self.message.id))
|
||||
|> map { message -> Bool in
|
||||
if let _ = message {
|
||||
return false
|
||||
}
|
||||
if view.messages.isEmpty {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
}
|
||||
|
||||
init(chatNode: ChatControllerNode, postbox: Postbox, message: Message, selectAll: Bool) {
|
||||
init(chatNode: ChatControllerNode, engine: TelegramEngine, message: Message, selectAll: Bool) {
|
||||
self.chatNode = chatNode
|
||||
self.postbox = postbox
|
||||
self.engine = engine
|
||||
self.message = message
|
||||
self.selectAll = selectAll
|
||||
}
|
||||
@ -89,7 +87,7 @@ final class ChatMessageReactionContextExtractedContentSource: ContextExtractedCo
|
||||
let centerActionsHorizontally: Bool = true
|
||||
|
||||
private weak var chatNode: ChatControllerNode?
|
||||
private let postbox: Postbox
|
||||
private let engine: TelegramEngine
|
||||
private let message: Message
|
||||
private let contentView: ContextExtractedContentContainingView
|
||||
|
||||
@ -97,24 +95,21 @@ final class ChatMessageReactionContextExtractedContentSource: ContextExtractedCo
|
||||
if self.message.adAttribute != nil {
|
||||
return .single(false)
|
||||
}
|
||||
let viewKey = PostboxViewKey.messages(Set([self.message.id]))
|
||||
return self.postbox.combinedView(keys: [viewKey])
|
||||
|> map { views -> Bool in
|
||||
guard let view = views.views[viewKey] as? MessagesView else {
|
||||
|
||||
return self.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.Message(id: self.message.id))
|
||||
|> map { message -> Bool in
|
||||
if let _ = message {
|
||||
return false
|
||||
}
|
||||
if view.messages.isEmpty {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
}
|
||||
|
||||
init(chatNode: ChatControllerNode, postbox: Postbox, message: Message, contentView: ContextExtractedContentContainingView) {
|
||||
init(chatNode: ChatControllerNode, engine: TelegramEngine, message: Message, contentView: ContextExtractedContentContainingView) {
|
||||
self.chatNode = chatNode
|
||||
self.postbox = postbox
|
||||
self.engine = engine
|
||||
self.message = message
|
||||
self.contentView = contentView
|
||||
}
|
||||
|
||||
@ -33,6 +33,7 @@ private func setupSharedLogger(rootPath: String, path: String) {
|
||||
|
||||
public struct NotificationViewControllerInitializationData {
|
||||
public let appBundleId: String
|
||||
public let appBuildType: TelegramAppBuildType
|
||||
public let appGroupPath: String
|
||||
public let apiId: Int32
|
||||
public let apiHash: String
|
||||
@ -41,8 +42,9 @@ public struct NotificationViewControllerInitializationData {
|
||||
public let appVersion: String
|
||||
public let bundleData: Data?
|
||||
|
||||
public init(appBundleId: String, appGroupPath: String, apiId: Int32, apiHash: String, languagesCategory: String, encryptionParameters: (Data, Data), appVersion: String, bundleData: Data?) {
|
||||
public init(appBundleId: String, appBuildType: TelegramAppBuildType, appGroupPath: String, apiId: Int32, apiHash: String, languagesCategory: String, encryptionParameters: (Data, Data), appVersion: String, bundleData: Data?) {
|
||||
self.appBundleId = appBundleId
|
||||
self.appBuildType = appBuildType
|
||||
self.appGroupPath = appGroupPath
|
||||
self.apiId = apiId
|
||||
self.apiHash = apiHash
|
||||
@ -104,7 +106,7 @@ public final class NotificationViewControllerImpl {
|
||||
})
|
||||
semaphore.wait()
|
||||
|
||||
let applicationBindings = TelegramApplicationBindings(isMainApp: false, appBundleId: self.initializationData.appBundleId, containerPath: self.initializationData.appGroupPath, appSpecificScheme: "tgapp", openUrl: { _ in
|
||||
let applicationBindings = TelegramApplicationBindings(isMainApp: false, appBundleId: self.initializationData.appBundleId, appBuildType: self.initializationData.appBuildType, containerPath: self.initializationData.appGroupPath, appSpecificScheme: "tgapp", openUrl: { _ in
|
||||
}, openUniversalUrl: { _, completion in
|
||||
completion.completion(false)
|
||||
return
|
||||
|
||||
@ -141,10 +141,12 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
self.statusPromise.set(context.account.postbox.combinedView(keys: [PostboxViewKey.historyTagSummaryView(tag: tagMask, peerId: peerId, namespace: Namespaces.Message.Cloud)])
|
||||
|> map { views -> PeerInfoStatusData? in
|
||||
let count: Int32 = (views.views[PostboxViewKey.historyTagSummaryView(tag: tagMask, peerId: peerId, namespace: Namespaces.Message.Cloud)] as? MessageHistoryTagSummaryView)?.count ?? 0
|
||||
|
||||
self.statusPromise.set(context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: tagMask)
|
||||
)
|
||||
|> map { count -> PeerInfoStatusData? in
|
||||
let count: Int = count ?? 0
|
||||
if count == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -195,16 +195,16 @@ final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
||||
self.disposable = (combineLatest(queue: .mainQueue(),
|
||||
membersContext.state,
|
||||
self.presentationDataPromise.get(),
|
||||
context.account.postbox.combinedView(keys: [.basicPeer(peerId)])
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state, presentationData, combinedView in
|
||||
guard let strongSelf = self, let basicPeerView = combinedView.views[.basicPeer(peerId)] as? BasicPeerView, let enclosingPeer = basicPeerView.peer else {
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state, presentationData, enclosingPeer in
|
||||
guard let strongSelf = self, let enclosingPeer = enclosingPeer else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.enclosingPeer = enclosingPeer
|
||||
strongSelf.enclosingPeer = enclosingPeer._asPeer()
|
||||
strongSelf.currentState = state
|
||||
strongSelf.updateState(enclosingPeer: enclosingPeer, state: state, presentationData: presentationData)
|
||||
strongSelf.updateState(enclosingPeer: enclosingPeer._asPeer(), state: state, presentationData: presentationData)
|
||||
})
|
||||
|
||||
self.listNode.visibleBottomContentOffsetChanged = { [weak self] offset in
|
||||
|
||||
@ -2015,34 +2015,14 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
||||
case .music:
|
||||
summaries.append(.music)
|
||||
}
|
||||
return context.account.postbox.combinedView(keys: summaries.map { tag in
|
||||
return PostboxViewKey.historyTagSummaryView(tag: tag, peerId: peerId, namespace: Namespaces.Message.Cloud)
|
||||
})
|
||||
|> map { views -> (ContentType, [MessageTags: Int32]) in
|
||||
switch contentType {
|
||||
case .photoOrVideo:
|
||||
summaries.append(.photo)
|
||||
summaries.append(.video)
|
||||
case .photo:
|
||||
summaries.append(.photo)
|
||||
case .video:
|
||||
summaries.append(.video)
|
||||
case .gifs:
|
||||
summaries.append(.gif)
|
||||
case .files:
|
||||
summaries.append(.file)
|
||||
case .voiceAndVideoMessages:
|
||||
summaries.append(.voiceOrInstantVideo)
|
||||
case .music:
|
||||
summaries.append(.music)
|
||||
}
|
||||
|
||||
return context.engine.data.subscribe(EngineDataMap(
|
||||
summaries.map { TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: $0) }
|
||||
))
|
||||
|> map { summaries -> (ContentType, [MessageTags: Int32]) in
|
||||
var result: [MessageTags: Int32] = [:]
|
||||
for tag in summaries {
|
||||
if let view = views.views[PostboxViewKey.historyTagSummaryView(tag: tag, peerId: peerId, namespace: Namespaces.Message.Cloud)] as? MessageHistoryTagSummaryView {
|
||||
result[tag] = view.count ?? 0
|
||||
} else {
|
||||
result[tag] = 0
|
||||
}
|
||||
for (key, count) in summaries {
|
||||
result[key.tag] = count.flatMap(Int32.init) ?? 0
|
||||
}
|
||||
return (contentType, result)
|
||||
}
|
||||
|
||||
@ -173,7 +173,7 @@ final class PeerInfoScreenData {
|
||||
let cachedData: CachedPeerData?
|
||||
let status: PeerInfoStatusData?
|
||||
let notificationSettings: TelegramPeerNotificationSettings?
|
||||
let globalNotificationSettings: GlobalNotificationSettings?
|
||||
let globalNotificationSettings: EngineGlobalNotificationSettings?
|
||||
let isContact: Bool
|
||||
let availablePanes: [PeerInfoPaneKey]
|
||||
let groupsInCommon: GroupsInCommonContext?
|
||||
@ -191,7 +191,7 @@ final class PeerInfoScreenData {
|
||||
cachedData: CachedPeerData?,
|
||||
status: PeerInfoStatusData?,
|
||||
notificationSettings: TelegramPeerNotificationSettings?,
|
||||
globalNotificationSettings: GlobalNotificationSettings?,
|
||||
globalNotificationSettings: EngineGlobalNotificationSettings?,
|
||||
isContact: Bool,
|
||||
availablePanes: [PeerInfoPaneKey],
|
||||
groupsInCommon: GroupsInCommonContext?,
|
||||
@ -313,13 +313,13 @@ enum PeerInfoMembersData: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private func peerInfoScreenInputData(context: AccountContext, peerId: PeerId, isSettings: Bool) -> Signal<PeerInfoScreenInputData, NoError> {
|
||||
return context.account.postbox.combinedView(keys: [.basicPeer(peerId)])
|
||||
|> map { view -> PeerInfoScreenInputData in
|
||||
guard let peer = (view.views[.basicPeer(peerId)] as? BasicPeerView)?.peer else {
|
||||
private func peerInfoScreenInputData(context: AccountContext, peerId: EnginePeer.Id, isSettings: Bool) -> Signal<PeerInfoScreenInputData, NoError> {
|
||||
return context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
|> map { peer -> PeerInfoScreenInputData in
|
||||
guard let peer = peer else {
|
||||
return .none
|
||||
}
|
||||
if let user = peer as? TelegramUser {
|
||||
if case let .user(user) = peer {
|
||||
if isSettings && user.id == context.account.peerId {
|
||||
return .settings
|
||||
} else {
|
||||
@ -333,15 +333,15 @@ private func peerInfoScreenInputData(context: AccountContext, peerId: PeerId, is
|
||||
}
|
||||
return .user(userId: user.id, secretChatId: nil, kind: kind)
|
||||
}
|
||||
} else if let channel = peer as? TelegramChannel {
|
||||
} else if case let .channel(channel) = peer {
|
||||
if case .group = channel.info {
|
||||
return .group(groupId: channel.id)
|
||||
} else {
|
||||
return .channel
|
||||
}
|
||||
} else if let group = peer as? TelegramGroup {
|
||||
} else if case let .legacyGroup(group) = peer {
|
||||
return .group(groupId: group.id)
|
||||
} else if let secretChat = peer as? TelegramSecretChat {
|
||||
} else if case let .secretChat(secretChat) = peer {
|
||||
return .user(userId: secretChat.regularPeerId, secretChatId: peer.id, kind: .user)
|
||||
} else {
|
||||
return .none
|
||||
@ -565,33 +565,20 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
return disposable
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
let globalNotificationsKey: PostboxViewKey = .preferences(keys: Set<ValueBoxKey>([PreferencesKeys.globalNotifications]))
|
||||
var combinedKeys: [PostboxViewKey] = []
|
||||
combinedKeys.append(globalNotificationsKey)
|
||||
|
||||
var secretChatKeyFingerprint: Signal<EngineSecretChatKeyFingerprint?, NoError> = .single(nil)
|
||||
if let secretChatId = secretChatId {
|
||||
combinedKeys.append(.peerChatState(peerId: secretChatId))
|
||||
secretChatKeyFingerprint = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.SecretChatKeyFingerprint(id: secretChatId))
|
||||
}
|
||||
|
||||
return combineLatest(
|
||||
context.account.viewTracker.peerView(peerId, updateData: true),
|
||||
peerInfoAvailableMediaPanes(context: context, peerId: peerId),
|
||||
context.account.postbox.combinedView(keys: combinedKeys),
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
||||
secretChatKeyFingerprint,
|
||||
status
|
||||
)
|
||||
|> map { peerView, availablePanes, combinedView, status -> PeerInfoScreenData in
|
||||
var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings
|
||||
if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView {
|
||||
if let settings = preferencesView.values[PreferencesKeys.globalNotifications]?.get(GlobalNotificationSettings.self) {
|
||||
globalNotificationSettings = settings
|
||||
}
|
||||
}
|
||||
|
||||
var encryptionKeyFingerprint: SecretChatKeyFingerprint?
|
||||
if let secretChatId = secretChatId, let peerChatStateView = combinedView.views[.peerChatState(peerId: secretChatId)] as? PeerChatStateView {
|
||||
if let peerChatState = peerChatStateView.chatState?.getLegacy() as? SecretChatState {
|
||||
encryptionKeyFingerprint = peerChatState.keyFingerprint
|
||||
}
|
||||
}
|
||||
|
||||
|> map { peerView, availablePanes, globalNotificationSettings, encryptionKeyFingerprint, status -> PeerInfoScreenData in
|
||||
var availablePanes = availablePanes
|
||||
if availablePanes != nil, groupsInCommon != nil, let cachedData = peerView.cachedData as? CachedUserData {
|
||||
if cachedData.commonGroupCount != 0 {
|
||||
@ -632,10 +619,6 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
let globalNotificationsKey: PostboxViewKey = .preferences(keys: Set<ValueBoxKey>([PreferencesKeys.globalNotifications]))
|
||||
var combinedKeys: [PostboxViewKey] = []
|
||||
combinedKeys.append(globalNotificationsKey)
|
||||
|
||||
let invitationsContextPromise = Promise<PeerExportedInvitationsContext?>(nil)
|
||||
let invitationsStatePromise = Promise<PeerExportedInvitationsState?>(nil)
|
||||
|
||||
@ -645,21 +628,14 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
return combineLatest(
|
||||
context.account.viewTracker.peerView(peerId, updateData: true),
|
||||
peerInfoAvailableMediaPanes(context: context, peerId: peerId),
|
||||
context.account.postbox.combinedView(keys: combinedKeys),
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
||||
status,
|
||||
invitationsContextPromise.get(),
|
||||
invitationsStatePromise.get(),
|
||||
requestsContextPromise.get(),
|
||||
requestsStatePromise.get()
|
||||
)
|
||||
|> map { peerView, availablePanes, combinedView, status, currentInvitationsContext, invitations, currentRequestsContext, requests -> PeerInfoScreenData in
|
||||
var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings
|
||||
if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView {
|
||||
if let settings = preferencesView.values[PreferencesKeys.globalNotifications]?.get(GlobalNotificationSettings.self) {
|
||||
globalNotificationSettings = settings
|
||||
}
|
||||
}
|
||||
|
||||
|> map { peerView, availablePanes, globalNotificationSettings, status, currentInvitationsContext, invitations, currentRequestsContext, requests -> PeerInfoScreenData in
|
||||
var discussionPeer: Peer?
|
||||
if case let .known(maybeLinkedDiscussionPeerId) = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] {
|
||||
discussionPeer = peer
|
||||
@ -795,10 +771,6 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
let globalNotificationsKey: PostboxViewKey = .preferences(keys: Set<ValueBoxKey>([PreferencesKeys.globalNotifications]))
|
||||
var combinedKeys: [PostboxViewKey] = []
|
||||
combinedKeys.append(globalNotificationsKey)
|
||||
|
||||
let invitationsContextPromise = Promise<PeerExportedInvitationsContext?>(nil)
|
||||
let invitationsStatePromise = Promise<PeerExportedInvitationsState?>(nil)
|
||||
|
||||
@ -808,7 +780,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
return combineLatest(queue: .mainQueue(),
|
||||
context.account.viewTracker.peerView(groupId, updateData: true),
|
||||
peerInfoAvailableMediaPanes(context: context, peerId: groupId),
|
||||
context.account.postbox.combinedView(keys: combinedKeys),
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
||||
status,
|
||||
membersData,
|
||||
invitationsContextPromise.get(),
|
||||
@ -816,14 +788,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
requestsContextPromise.get(),
|
||||
requestsStatePromise.get()
|
||||
)
|
||||
|> map { peerView, availablePanes, combinedView, status, membersData, currentInvitationsContext, invitations, currentRequestsContext, requests -> PeerInfoScreenData in
|
||||
var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings
|
||||
if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView {
|
||||
if let settings = preferencesView.values[PreferencesKeys.globalNotifications]?.get(GlobalNotificationSettings.self) {
|
||||
globalNotificationSettings = settings
|
||||
}
|
||||
}
|
||||
|
||||
|> map { peerView, availablePanes, globalNotificationSettings, status, membersData, currentInvitationsContext, invitations, currentRequestsContext, requests -> PeerInfoScreenData in
|
||||
var discussionPeer: Peer?
|
||||
if case let .known(maybeLinkedDiscussionPeerId) = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] {
|
||||
discussionPeer = peer
|
||||
|
||||
@ -6766,24 +6766,20 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
|
||||
private func displayMediaGalleryContextMenu(source: ContextReferenceContentNode, gesture: ContextGesture?) {
|
||||
let summaryTags: [MessageTags] = [.photo, .video]
|
||||
let peerId = self.peerId
|
||||
let _ = (context.account.postbox.combinedView(keys: summaryTags.map { tag in
|
||||
return PostboxViewKey.historyTagSummaryView(tag: tag, peerId: peerId, namespace: Namespaces.Message.Cloud)
|
||||
})
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] views in
|
||||
|
||||
let _ = (self.context.engine.data.get(EngineDataMap([
|
||||
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: .photo),
|
||||
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: .video)
|
||||
]))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] messageCounts in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
var mediaCount: [MessageTags: Int32] = [:]
|
||||
for tag in summaryTags {
|
||||
if let view = views.views[PostboxViewKey.historyTagSummaryView(tag: tag, peerId: peerId, namespace: Namespaces.Message.Cloud)] as? MessageHistoryTagSummaryView {
|
||||
mediaCount[tag] = view.count ?? 0
|
||||
} else {
|
||||
mediaCount[tag] = 0
|
||||
}
|
||||
for (key, count) in messageCounts {
|
||||
mediaCount[key.tag] = count.flatMap(Int32.init) ?? 0
|
||||
}
|
||||
|
||||
let photoCount: Int32 = mediaCount[.photo] ?? 0
|
||||
|
||||
@ -875,12 +875,11 @@ final class PeerInfoGifPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDe
|
||||
self.animationTimer = animationTimer
|
||||
animationTimer.start()
|
||||
|
||||
self.statusPromise.set(context.account.postbox.combinedView(keys: [PostboxViewKey.historyTagSummaryView(tag: tagMaskForType(self.contentType), peerId: peerId, namespace: Namespaces.Message.Cloud)])
|
||||
|> map { [weak self] views -> PeerInfoStatusData? in
|
||||
guard let strongSelf = self else {
|
||||
return nil
|
||||
}
|
||||
let count: Int32 = (views.views[PostboxViewKey.historyTagSummaryView(tag: tagMaskForType(strongSelf.contentType), peerId: peerId, namespace: Namespaces.Message.Cloud)] as? MessageHistoryTagSummaryView)?.count ?? 0
|
||||
self.statusPromise.set(context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Messages.MessageCount(peerId: peerId, tag: tagMaskForType(self.contentType))
|
||||
)
|
||||
|> map { count -> PeerInfoStatusData? in
|
||||
let count: Int = count ?? 0
|
||||
if count == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -444,15 +444,13 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist {
|
||||
if item?.message.id != self.currentlyObservedMessageId {
|
||||
self.currentlyObservedMessageId = item?.message.id
|
||||
if let id = item?.message.id {
|
||||
let key: PostboxViewKey = .messages(Set([id]))
|
||||
self.currentlyObservedMessageDisposable.set((self.context.account.postbox.combinedView(keys: [key])
|
||||
|> filter { views in
|
||||
if let view = views.views[key] as? MessagesView {
|
||||
if !view.messages.isEmpty {
|
||||
return false
|
||||
}
|
||||
self.currentlyObservedMessageDisposable.set((self.context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.Message(id: id))
|
||||
|> filter { message in
|
||||
if let _ = message {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] _ in
|
||||
|
||||
@ -56,6 +56,7 @@ private enum ShareAuthorizationError {
|
||||
|
||||
public struct ShareRootControllerInitializationData {
|
||||
public let appBundleId: String
|
||||
public let appBuildType: TelegramAppBuildType
|
||||
public let appGroupPath: String
|
||||
public let apiId: Int32
|
||||
public let apiHash: String
|
||||
@ -64,8 +65,9 @@ public struct ShareRootControllerInitializationData {
|
||||
public let appVersion: String
|
||||
public let bundleData: Data?
|
||||
|
||||
public init(appBundleId: String, appGroupPath: String, apiId: Int32, apiHash: String, languagesCategory: String, encryptionParameters: (Data, Data), appVersion: String, bundleData: Data?) {
|
||||
public init(appBundleId: String, appBuildType: TelegramAppBuildType, appGroupPath: String, apiId: Int32, apiHash: String, languagesCategory: String, encryptionParameters: (Data, Data), appVersion: String, bundleData: Data?) {
|
||||
self.appBundleId = appBundleId
|
||||
self.appBuildType = appBuildType
|
||||
self.appGroupPath = appGroupPath
|
||||
self.apiId = apiId
|
||||
self.apiHash = apiHash
|
||||
@ -178,7 +180,7 @@ public class ShareRootControllerImpl {
|
||||
|
||||
setupSharedLogger(rootPath: rootPath, path: logsPath)
|
||||
|
||||
let applicationBindings = TelegramApplicationBindings(isMainApp: false, appBundleId: self.initializationData.appBundleId, containerPath: self.initializationData.appGroupPath, appSpecificScheme: "tg", openUrl: { _ in
|
||||
let applicationBindings = TelegramApplicationBindings(isMainApp: false, appBundleId: self.initializationData.appBundleId, appBuildType: self.initializationData.appBuildType, containerPath: self.initializationData.appGroupPath, appSpecificScheme: "tg", openUrl: { _ in
|
||||
}, openUniversalUrl: { _, completion in
|
||||
completion.completion(false)
|
||||
return
|
||||
|
||||
@ -575,13 +575,12 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
self.activeAccountsWithInfoPromise.set(self.activeAccountContexts
|
||||
|> mapToSignal { primary, accounts, _ -> Signal<(primary: AccountRecordId?, accounts: [AccountWithInfo]), NoError> in
|
||||
return combineLatest(accounts.map { _, context, _ -> Signal<AccountWithInfo?, NoError> in
|
||||
let peerViewKey: PostboxViewKey = .peer(peerId: context.account.peerId, components: [])
|
||||
return context.account.postbox.combinedView(keys: [peerViewKey])
|
||||
|> map { view -> AccountWithInfo? in
|
||||
guard let peerView = view.views[peerViewKey] as? PeerView, let peer = peerView.peers[peerView.peerId] else {
|
||||
return context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
|> map { peer -> AccountWithInfo? in
|
||||
guard let peer = peer else {
|
||||
return nil
|
||||
}
|
||||
return AccountWithInfo(account: context.account, peer: peer)
|
||||
return AccountWithInfo(account: context.account, peer: peer._asPeer())
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
})
|
||||
|
||||
@ -393,10 +393,6 @@ public final class SharedNotificationManager {
|
||||
|
||||
if let readMessageId = readMessageId {
|
||||
self.clearNotificationsManager?.append(readMessageId)
|
||||
|
||||
let _ = account.postbox.transaction(ignoreDisabled: true, { transaction -> Void in
|
||||
transaction.applyIncomingReadMaxId(readMessageId)
|
||||
}).start()
|
||||
}
|
||||
|
||||
for messageId in messagesDeleted {
|
||||
@ -404,9 +400,6 @@ public final class SharedNotificationManager {
|
||||
}
|
||||
|
||||
if !messagesDeleted.isEmpty {
|
||||
let _ = account.postbox.transaction(ignoreDisabled: true, { transaction -> Void in
|
||||
TelegramEngine(account: account).messages.deleteMessages(transaction: transaction, ids: messagesDeleted)
|
||||
}).start()
|
||||
}
|
||||
|
||||
if readMessageId != nil || !messagesDeleted.isEmpty {
|
||||
|
||||
@ -198,15 +198,16 @@ final class WidgetDataContext {
|
||||
if peerIds.isEmpty {
|
||||
continue
|
||||
}
|
||||
let topMessagesKey: PostboxViewKey = .topChatMessage(peerIds: Array(peerIds))
|
||||
|
||||
accountSignals.append(account.postbox.combinedView(keys: [topMessagesKey])
|
||||
|> map { combinedView -> [WidgetDataPeer] in
|
||||
guard let topMessages = combinedView.views[topMessagesKey] as? TopChatMessageView else {
|
||||
return []
|
||||
}
|
||||
accountSignals.append(TelegramEngine(account: account).data.subscribe(EngineDataMap(
|
||||
peerIds.map(TelegramEngine.EngineData.Item.Messages.TopMessage.init)
|
||||
))
|
||||
|> map { topMessages -> [WidgetDataPeer] in
|
||||
var result: [WidgetDataPeer] = []
|
||||
for (peerId, message) in topMessages.messages {
|
||||
for (peerId, message) in topMessages {
|
||||
guard let message = message else {
|
||||
continue
|
||||
}
|
||||
guard let peer = message.peers[message.id.peerId] else {
|
||||
continue
|
||||
}
|
||||
@ -227,7 +228,7 @@ final class WidgetDataContext {
|
||||
name = peer.debugDisplayTitle
|
||||
}
|
||||
|
||||
result.append(WidgetDataPeer(id: peerId.toInt64(), name: name, lastName: lastName, letters: [], avatarPath: nil, badge: nil, message: WidgetDataPeer.Message(accountPeerId: account.peerId, message: EngineMessage(message))))
|
||||
result.append(WidgetDataPeer(id: peerId.toInt64(), name: name, lastName: lastName, letters: [], avatarPath: nil, badge: nil, message: WidgetDataPeer.Message(accountPeerId: account.peerId, message: message)))
|
||||
}
|
||||
result.sort(by: { lhs, rhs in
|
||||
return lhs.id < rhs.id
|
||||
|
||||
@ -22,31 +22,6 @@ public func renderedTotalUnreadCount(inAppSettings: InAppNotificationSettings, t
|
||||
return (totalUnreadState.count(for: inAppSettings.totalUnreadCountDisplayStyle.category, in: inAppSettings.totalUnreadCountDisplayCategory.statsType, with: inAppSettings.totalUnreadCountIncludeTags), type)
|
||||
}
|
||||
|
||||
public func getCurrentRenderedTotalUnreadCount(accountManager: AccountManager<TelegramAccountManagerTypes>, postbox: Postbox) -> Signal<(Int32, RenderedTotalUnreadCountType), NoError> {
|
||||
let counters = postbox.transaction { transaction -> ChatListTotalUnreadState in
|
||||
return transaction.getTotalUnreadState(groupId: .root)
|
||||
}
|
||||
return combineLatest(
|
||||
accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.inAppNotificationSettings])
|
||||
|> take(1),
|
||||
counters
|
||||
)
|
||||
|> map { sharedData, totalReadCounters -> (Int32, RenderedTotalUnreadCountType) in
|
||||
let inAppSettings: InAppNotificationSettings
|
||||
if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings]?.get(InAppNotificationSettings.self) {
|
||||
inAppSettings = value
|
||||
} else {
|
||||
inAppSettings = .defaultSettings
|
||||
}
|
||||
let type: RenderedTotalUnreadCountType
|
||||
switch inAppSettings.totalUnreadCountDisplayStyle {
|
||||
case .filtered:
|
||||
type = .filtered
|
||||
}
|
||||
return (totalReadCounters.count(for: inAppSettings.totalUnreadCountDisplayStyle.category, in: inAppSettings.totalUnreadCountDisplayCategory.statsType, with: inAppSettings.totalUnreadCountIncludeTags), type)
|
||||
}
|
||||
}
|
||||
|
||||
public func renderedTotalUnreadCount(accountManager: AccountManager<TelegramAccountManagerTypes>, engine: TelegramEngine) -> Signal<(Int32, RenderedTotalUnreadCountType), NoError> {
|
||||
return combineLatest(
|
||||
accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.inAppNotificationSettings]),
|
||||
|
||||
@ -511,21 +511,21 @@ public final class PeerChannelMemberCategoriesContextsManager {
|
||||
let updatedIds = Set(idList)
|
||||
if previousIds != updatedIds {
|
||||
previousIds = updatedIds
|
||||
let key: PostboxViewKey = .peerPresences(peerIds: updatedIds)
|
||||
statusesDisposable.set((postbox.combinedView(keys: [key])
|
||||
|> map { view -> Int32 in
|
||||
|
||||
statusesDisposable.set((engine.data.subscribe(EngineDataMap(
|
||||
updatedIds.map(TelegramEngine.EngineData.Item.Peer.Presence.init)
|
||||
))
|
||||
|> map { presenceMap -> Int32 in
|
||||
var count: Int32 = 0
|
||||
let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970
|
||||
if let presences = (view.views[key] as? PeerPresencesView)?.presences {
|
||||
for (_, presence) in presences {
|
||||
if let presence = presence as? TelegramUserPresence {
|
||||
let relativeStatus = relativeUserPresenceStatus(EnginePeer.Presence(presence), relativeTo: Int32(timestamp))
|
||||
switch relativeStatus {
|
||||
case .online:
|
||||
count += 1
|
||||
default:
|
||||
break
|
||||
}
|
||||
for (_, presence) in presenceMap {
|
||||
if let presence = presence {
|
||||
let relativeStatus = relativeUserPresenceStatus(presence, relativeTo: Int32(timestamp))
|
||||
switch relativeStatus {
|
||||
case .online:
|
||||
count += 1
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,10 +28,13 @@ public final class CachedWallpaper: Codable {
|
||||
}
|
||||
|
||||
public func cachedWallpaper(account: Account, slug: String, settings: WallpaperSettings?, update: Bool = false) -> Signal<CachedWallpaper?, NoError> {
|
||||
return account.postbox.transaction { transaction -> Signal<CachedWallpaper?, NoError> in
|
||||
let key = ValueBoxKey(length: 8)
|
||||
key.setInt64(0, value: Int64(bitPattern: slug.persistentHashValue))
|
||||
if !update, let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedWallpapers, key: key))?.get(CachedWallpaper.self) {
|
||||
let engine = TelegramEngine(account: account)
|
||||
|
||||
let slugKey = ValueBoxKey(length: 8)
|
||||
slugKey.setInt64(0, value: Int64(bitPattern: slug.persistentHashValue))
|
||||
return engine.data.get(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: ApplicationSpecificItemCacheCollectionId.cachedWallpapers, id: slugKey))
|
||||
|> mapToSignal { entry -> Signal<CachedWallpaper?, NoError> in
|
||||
if !update, let entry = entry?.get(CachedWallpaper.self) {
|
||||
if let settings = settings {
|
||||
return .single(CachedWallpaper(wallpaper: entry.wallpaper.withUpdatedSettings(settings)))
|
||||
} else {
|
||||
@ -44,33 +47,34 @@ public func cachedWallpaper(account: Account, slug: String, settings: WallpaperS
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { wallpaper -> Signal<CachedWallpaper?, NoError> in
|
||||
return account.postbox.transaction { transaction -> CachedWallpaper? in
|
||||
let key = ValueBoxKey(length: 8)
|
||||
key.setInt64(0, value: Int64(bitPattern: slug.persistentHashValue))
|
||||
let id = ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedWallpapers, key: key)
|
||||
if var wallpaper = wallpaper {
|
||||
switch wallpaper {
|
||||
case let .file(file):
|
||||
wallpaper = .file(TelegramWallpaper.File(id: file.id, accessHash: file.accessHash, isCreator: file.isCreator, isDefault: file.isDefault, isPattern: file.isPattern, isDark: file.isDark, slug: file.slug, file: file.file.withUpdatedResource(WallpaperDataResource(slug: slug)), settings: file.settings))
|
||||
default:
|
||||
break
|
||||
}
|
||||
if let entry = CodableEntry(CachedWallpaper(wallpaper: wallpaper)) {
|
||||
transaction.putItemCacheEntry(id: id, entry: entry)
|
||||
}
|
||||
if let settings = settings {
|
||||
return CachedWallpaper(wallpaper: wallpaper.withUpdatedSettings(settings))
|
||||
} else {
|
||||
return CachedWallpaper(wallpaper: wallpaper)
|
||||
}
|
||||
} else {
|
||||
transaction.removeItemCacheEntry(id: id)
|
||||
return nil
|
||||
let slugKey = ValueBoxKey(length: 8)
|
||||
slugKey.setInt64(0, value: Int64(bitPattern: slug.persistentHashValue))
|
||||
|
||||
if var wallpaper = wallpaper {
|
||||
switch wallpaper {
|
||||
case let .file(file):
|
||||
wallpaper = .file(TelegramWallpaper.File(id: file.id, accessHash: file.accessHash, isCreator: file.isCreator, isDefault: file.isDefault, isPattern: file.isPattern, isDark: file.isDark, slug: file.slug, file: file.file.withUpdatedResource(WallpaperDataResource(slug: slug)), settings: file.settings))
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
let result: CachedWallpaper
|
||||
if let settings = settings {
|
||||
result = CachedWallpaper(wallpaper: wallpaper.withUpdatedSettings(settings))
|
||||
} else {
|
||||
result = CachedWallpaper(wallpaper: wallpaper)
|
||||
}
|
||||
return engine.itemCache.put(collectionId: ApplicationSpecificItemCacheCollectionId.cachedWallpapers, id: slugKey, item: CachedWallpaper(wallpaper: wallpaper))
|
||||
|> map { _ -> CachedWallpaper? in }
|
||||
|> then(.single(result))
|
||||
} else {
|
||||
return engine.itemCache.remove(collectionId: ApplicationSpecificItemCacheCollectionId.cachedWallpapers, id: slugKey)
|
||||
|> map { _ -> CachedWallpaper? in }
|
||||
|> then(.single(nil))
|
||||
}
|
||||
}
|
||||
}
|
||||
} |> switchToLatest
|
||||
}
|
||||
}
|
||||
|
||||
public func updateCachedWallpaper(engine: TelegramEngine, wallpaper: TelegramWallpaper) {
|
||||
|
||||
@ -282,7 +282,7 @@ class WebSearchControllerNode: ASDisplayNode {
|
||||
|
||||
if !attachment {
|
||||
let previousRecentItems = Atomic<[WebSearchRecentQueryEntry]?>(value: nil)
|
||||
self.recentDisposable = (combineLatest(webSearchRecentQueries(postbox: self.context.account.postbox), self.webSearchInterfaceStatePromise.get())
|
||||
self.recentDisposable = (combineLatest(webSearchRecentQueries(engine: self.context.engine), self.webSearchInterfaceStatePromise.get())
|
||||
|> deliverOnMainQueue).start(next: { [weak self] queries, interfaceState in
|
||||
if let strongSelf = self {
|
||||
var entries: [WebSearchRecentQueryEntry] = []
|
||||
|
||||
@ -56,16 +56,14 @@ func clearRecentWebSearchQueries(engine: TelegramEngine) -> Signal<Never, NoErro
|
||||
return engine.orderedLists.clear(collectionId: ApplicationSpecificOrderedItemListCollectionId.webSearchRecentQueries)
|
||||
}
|
||||
|
||||
func webSearchRecentQueries(postbox: Postbox) -> Signal<[String], NoError> {
|
||||
return postbox.combinedView(keys: [.orderedItemList(id: ApplicationSpecificOrderedItemListCollectionId.webSearchRecentQueries)])
|
||||
|> mapToSignal { view -> Signal<[String], NoError> in
|
||||
func webSearchRecentQueries(engine: TelegramEngine) -> Signal<[String], NoError> {
|
||||
return engine.data.subscribe(TelegramEngine.EngineData.Item.OrderedLists.ListItems(collectionId: ApplicationSpecificOrderedItemListCollectionId.webSearchRecentQueries))
|
||||
|> map { items -> [String] in
|
||||
var result: [String] = []
|
||||
if let view = view.views[.orderedItemList(id: ApplicationSpecificOrderedItemListCollectionId.webSearchRecentQueries)] as? OrderedItemListView {
|
||||
for item in view.items {
|
||||
let value = WebSearchRecentQueryItemId(item.id).value
|
||||
result.append(value)
|
||||
}
|
||||
for item in items {
|
||||
let value = WebSearchRecentQueryItemId(item.id).value
|
||||
result.append(value)
|
||||
}
|
||||
return .single(result)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user