Refactoring

This commit is contained in:
Ali 2022-05-29 02:09:25 +04:00
parent be3c85abff
commit a183d69534
96 changed files with 1104 additions and 1416 deletions

View File

@ -696,8 +696,8 @@ public protocol SharedAccountContext: AnyObject {
func openStorageUsage(context: AccountContext)
func openLocationScreen(context: AccountContext, messageId: MessageId, navigationController: NavigationController)
func openExternalUrl(context: AccountContext, urlContext: OpenURLContext, url: String, forceExternal: Bool, presentationData: PresentationData, navigationController: NavigationController?, dismissInput: @escaping () -> Void)
func chatAvailableMessageActions(postbox: Postbox, accountPeerId: EnginePeer.Id, messageIds: Set<EngineMessage.Id>) -> Signal<ChatAvailableMessageActions, NoError>
func chatAvailableMessageActions(postbox: Postbox, accountPeerId: EnginePeer.Id, messageIds: Set<EngineMessage.Id>, messages: [EngineMessage.Id: EngineMessage], peers: [EnginePeer.Id: EnginePeer]) -> Signal<ChatAvailableMessageActions, NoError>
func chatAvailableMessageActions(engine: TelegramEngine, accountPeerId: EnginePeer.Id, messageIds: Set<EngineMessage.Id>) -> Signal<ChatAvailableMessageActions, NoError>
func chatAvailableMessageActions(engine: TelegramEngine, accountPeerId: EnginePeer.Id, messageIds: Set<EngineMessage.Id>, messages: [EngineMessage.Id: EngineMessage], peers: [EnginePeer.Id: EnginePeer]) -> Signal<ChatAvailableMessageActions, NoError>
func resolveUrl(context: AccountContext, peerId: PeerId?, url: String, skipUrlAuth: Bool) -> Signal<ResolvedUrl, NoError>
func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, forceExternal: Bool, openPeer: @escaping (PeerId, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?)
func openAddContact(context: AccountContext, firstName: String, lastName: String, phoneNumber: String, label: String, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void)

View File

@ -16,21 +16,25 @@ import PremiumUI
func archiveContextMenuItems(context: AccountContext, groupId: PeerGroupId, chatListController: ChatListControllerImpl?) -> Signal<[ContextMenuItem], NoError> {
let presentationData = context.sharedContext.currentPresentationData.with({ $0 })
let strings = presentationData.strings
return context.account.postbox.transaction { [weak chatListController] transaction -> [ContextMenuItem] in
return combineLatest(
context.engine.messages.unreadChatListPeerIds(groupId: EngineChatList.Group(groupId), filterPredicate: nil),
context.engine.data.get(
TelegramEngine.EngineData.Item.Configuration.ApplicationSpecificPreference(key: ApplicationSpecificPreferencesKeys.chatArchiveSettings)
)
)
|> map { [weak chatListController] unreadChatListPeerIds, chatArchiveSettingsPreference -> [ContextMenuItem] in
var items: [ContextMenuItem] = []
if !transaction.getUnreadChatListPeerIds(groupId: groupId, filterPredicate: nil).isEmpty {
if !unreadChatListPeerIds.isEmpty {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAllAsRead, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsRead"), color: theme.contextMenu.primaryColor) }, action: { _, f in
let _ = (context.account.postbox.transaction { transaction in
markAllChatsAsReadInteractively(transaction: transaction, viewTracker: context.account.viewTracker, groupId: groupId, filterPredicate: nil)
}
let _ = (context.engine.messages.markAllChatsAsReadInteractively(items: [(groupId: EngineChatList.Group(groupId), filterPredicate: nil)])
|> deliverOnMainQueue).start(completed: {
f(.default)
})
})))
}
let settings = transaction.getPreferencesEntry(key: ApplicationSpecificPreferencesKeys.chatArchiveSettings)?.get(ChatArchiveSettings.self) ?? ChatArchiveSettings.default
let settings = chatArchiveSettingsPreference?.get(ChatArchiveSettings.self) ?? ChatArchiveSettings.default
let isPinned = !settings.isHiddenByDefault
items.append(.action(ContextMenuActionItem(text: isPinned ? strings.ChatList_Context_HideArchive : strings.ChatList_Context_UnhideArchive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin": "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { [weak chatListController] _, f in
chatListController?.toggleArchivedFolderHiddenByDefault()
@ -75,34 +79,41 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
)
|> mapToSignal { filters, pinnedItemIds -> Signal<[ContextMenuItem], NoError> in
let isPinned = pinnedItemIds.contains(.peer(peerId))
return context.account.postbox.transaction { [weak chatListController] transaction -> [ContextMenuItem] in
if promoInfo != nil {
return []
let renderedPeer = context.engine.data.get(TelegramEngine.EngineData.Item.Peer.RenderedPeer(id: peerId))
return renderedPeer
|> mapToSignal { renderedPeer -> Signal<[ContextMenuItem], NoError> in
guard let renderedPeer = renderedPeer else {
return .single([])
}
guard let peer = renderedPeer.chatMainPeer else {
return .single([])
}
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)
)
|> map { [weak chatListController] isContact, notificationSettings, readState -> [ContextMenuItem] in
if promoInfo != nil {
return []
}
var items: [ContextMenuItem] = []
var items: [ContextMenuItem] = []
if case let .search(search) = source {
switch search {
case .recentPeers:
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_RemoveFromRecents, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
let _ = (context.engine.peers.removeRecentPeer(peerId: peerId)
|> deliverOnMainQueue).start(completed: {
f(.default)
})
})))
items.append(.separator)
case .recentSearch:
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_RemoveFromRecents, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
let _ = (context.engine.peers.removeRecentlySearchedPeer(peerId: peerId)
|> deliverOnMainQueue).start(completed: {
f(.default)
})
})))
items.append(.separator)
case .search:
if recentlySearchedPeers.contains(where: { $0.peer.peerId == peerId }) {
if case let .search(search) = source {
switch search {
case .recentPeers:
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_RemoveFromRecents, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
let _ = (context.engine.peers.removeRecentPeer(peerId: peerId)
|> deliverOnMainQueue).start(completed: {
f(.default)
})
})))
items.append(.separator)
case .recentSearch:
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_RemoveFromRecents, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
let _ = (context.engine.peers.removeRecentlySearchedPeer(peerId: peerId)
|> deliverOnMainQueue).start(completed: {
@ -110,320 +121,308 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
})
})))
items.append(.separator)
}
}
}
let isSavedMessages = peerId == context.account.peerId
let chatPeer = transaction.getPeer(peerId)
var maybePeer: Peer?
if let chatPeer = chatPeer {
if let chatPeer = chatPeer as? TelegramSecretChat {
maybePeer = transaction.getPeer(chatPeer.regularPeerId)
} else {
maybePeer = chatPeer
}
}
guard let peer = maybePeer else {
return []
}
if !isSavedMessages, let peer = peer as? TelegramUser, !peer.flags.contains(.isSupport) && peer.botInfo == nil && !peer.isDeleted {
if !transaction.isPeerContact(peerId: peer.id) {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_AddToContacts, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor) }, action: { _, f in
context.sharedContext.openAddPersonContact(context: context, peerId: peerId, pushController: { controller in
if let navigationController = chatListController?.navigationController as? NavigationController {
navigationController.pushViewController(controller)
}
}, present: { c, a in
if let chatListController = chatListController {
chatListController.present(c, in: .window(.root), with: a)
}
})
f(.default)
})))
items.append(.separator)
}
}
var isMuted = false
if let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings {
if case .muted = notificationSettings.muteState {
isMuted = true
}
}
var isUnread = false
if let readState = transaction.getCombinedPeerReadState(peerId), readState.isUnread {
isUnread = true
}
let isContact = transaction.isPeerContact(peerId: peerId)
if case let .chatList(currentFilter) = source {
if let currentFilter = currentFilter, case let .filter(id, title, emoticon, data) = currentFilter {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_RemoveFromFolder, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/RemoveFromFolder"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
var filters = filters
for i in 0 ..< filters.count {
if filters[i].id == currentFilter.id {
var updatedData = data
let _ = updatedData.addExcludePeer(peerId: peer.id)
filters[i] = .filter(id: id, title: title, emoticon: emoticon, data: updatedData)
break
}
}
return filters
}
|> deliverOnMainQueue).start(completed: {
c.dismiss(completion: {
chatListController?.present(UndoOverlayController(presentationData: presentationData, content: .chatRemovedFromFolder(chatTitle: EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), folderTitle: title), elevatedLayout: false, animateInAsReplacement: true, action: { _ in
return false
}), in: .current)
})
})
})))
} else {
var hasFolders = false
for case let .filter(_, _, _, data) in filters {
let predicate = chatListFilterPredicate(filter: data)
if predicate.includes(peer: peer, groupId: .root, isRemovedFromTotalUnreadCount: isMuted, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: false) {
continue
}
var data = data
if data.addIncludePeer(peerId: peer.id) {
hasFolders = true
break
}
}
if hasFolders {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_AddToFolder, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Folder"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
var updatedItems: [ContextMenuItem] = []
for filter in filters {
if case let .filter(_, title, _, data) = filter {
let predicate = chatListFilterPredicate(filter: data)
if predicate.includes(peer: peer, groupId: .root, isRemovedFromTotalUnreadCount: isMuted, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: false) {
continue
}
var data = data
if !data.addIncludePeer(peerId: peer.id) {
continue
}
let filterType = chatListFilterType(data)
updatedItems.append(.action(ContextMenuActionItem(text: title, icon: { theme in
let imageName: String
switch filterType {
case .generic:
imageName = "Chat/Context Menu/List"
case .unmuted:
imageName = "Chat/Context Menu/Unmute"
case .unread:
imageName = "Chat/Context Menu/MarkAsUnread"
case .channels:
imageName = "Chat/Context Menu/Channels"
case .groups:
imageName = "Chat/Context Menu/Groups"
case .bots:
imageName = "Chat/Context Menu/Bots"
case .contacts:
imageName = "Chat/Context Menu/User"
case .nonContacts:
imageName = "Chat/Context Menu/UnknownUser"
}
return generateTintedImage(image: UIImage(bundleImageName: imageName), color: theme.contextMenu.primaryColor)
}, action: { c, f in
c.dismiss(completion: {
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
var filters = filters
for i in 0 ..< filters.count {
if filters[i].id == filter.id {
if case let .filter(id, title, emoticon, data) = filter {
var updatedData = data
let _ = updatedData.addIncludePeer(peerId: peer.id)
filters[i] = .filter(id: id, title: title, emoticon: emoticon, data: updatedData)
}
break
}
}
return filters
}).start()
chatListController?.present(UndoOverlayController(presentationData: presentationData, content: .chatAddedToFolder(chatTitle: EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), folderTitle: title), elevatedLayout: false, animateInAsReplacement: true, action: { _ in
return false
}), in: .current)
})
})))
}
}
updatedItems.append(.separator)
updatedItems.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Back, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
}, action: { c, _ in
c.setItems(chatContextMenuItems(context: context, peerId: peerId, promoInfo: promoInfo, source: source, chatListController: chatListController, joined: joined) |> map { ContextController.Items(content: .list($0)) }, minHeight: nil)
})))
c.setItems(.single(ContextController.Items(content: .list(updatedItems))), minHeight: nil)
})))
}
}
}
if isUnread {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAsRead, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsRead"), color: theme.contextMenu.primaryColor) }, action: { _, f in
let _ = togglePeerUnreadMarkInteractively(postbox: context.account.postbox, viewTracker: context.account.viewTracker, peerId: peerId).start()
f(.default)
})))
} else {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAsUnread, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsUnread"), color: theme.contextMenu.primaryColor) }, action: { _, f in
let _ = togglePeerUnreadMarkInteractively(postbox: context.account.postbox, viewTracker: context.account.viewTracker, peerId: peerId).start()
f(.default)
})))
}
let archiveEnabled = !isSavedMessages && peerId != PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(777000)) && peerId == context.account.peerId
if let group = peerGroup {
if archiveEnabled {
let isArchived = group == .archive
items.append(.action(ContextMenuActionItem(text: isArchived ? strings.ChatList_Context_Unarchive : strings.ChatList_Context_Archive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isArchived ? "Chat/Context Menu/Unarchive" : "Chat/Context Menu/Archive"), color: theme.contextMenu.primaryColor) }, action: { _, f in
if isArchived {
let _ = (context.account.postbox.transaction { transaction -> Void in
updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: .root)
}
|> deliverOnMainQueue).start(completed: {
f(.default)
})
} else {
if let chatListController = chatListController {
chatListController.archiveChats(peerIds: [peerId])
f(.default)
} else {
let _ = (context.account.postbox.transaction { transaction -> Void in
updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: Namespaces.PeerGroup.archive)
}
case .search:
if recentlySearchedPeers.contains(where: { $0.peer.peerId == peerId }) {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_RemoveFromRecents, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
let _ = (context.engine.peers.removeRecentlySearchedPeer(peerId: peerId)
|> deliverOnMainQueue).start(completed: {
f(.default)
})
}
})))
items.append(.separator)
}
})))
}
if isPinned || chatListFilter == nil || peerId.namespace != Namespaces.Peer.SecretChat {
items.append(.action(ContextMenuActionItem(text: isPinned ? strings.ChatList_Context_Unpin : strings.ChatList_Context_Pin, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin" : "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { c, f in
let _ = (context.engine.peers.toggleItemPinned(location: location, itemId: .peer(peerId))
|> deliverOnMainQueue).start(next: { result in
switch result {
case .done:
f(.default)
case let .limitExceeded(count, _):
f(.default)
var replaceImpl: ((ViewController) -> Void)?
let controller = PremiumLimitScreen(context: context, subject: .pins, count: Int32(count), action: {
let premiumScreen = PremiumIntroScreen(context: context, source: .pinnedChats)
replaceImpl?(premiumScreen)
})
chatListController?.push(controller)
replaceImpl = { [weak controller] c in
controller?.replace(with: c)
}
}
})
})))
}
if !isSavedMessages, let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings {
var isMuted = false
if case .muted = notificationSettings.muteState {
isMuted = true
}
items.append(.action(ContextMenuActionItem(text: isMuted ? strings.ChatList_Context_Unmute : strings.ChatList_Context_Mute, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) }, action: { _, f in
let _ = (context.engine.peers.togglePeerMuted(peerId: peerId)
|> deliverOnMainQueue).start(completed: {
f(.default)
})
})))
}
} else {
if case .search = source {
if let peer = peer as? TelegramChannel {
let text: String
if case .broadcast = peer.info {
text = strings.ChatList_Context_JoinChannel
} else {
text = strings.ChatList_Context_JoinChat
}
items.append(.action(ContextMenuActionItem(text: text, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor) }, action: { _, f in
var createSignal = context.peerChannelMemberCategoriesContextsManager.join(engine: context.engine, peerId: peerId, hash: nil)
var cancelImpl: (() -> Void)?
let progressSignal = Signal<Never, NoError> { subscriber in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
cancelImpl?()
}))
chatListController?.present(controller, in: .window(.root))
return ActionDisposable { [weak controller] in
Queue.mainQueue().async() {
controller?.dismiss()
}
}
}
|> runOn(Queue.mainQueue())
|> delay(0.15, queue: Queue.mainQueue())
let progressDisposable = progressSignal.start()
createSignal = createSignal
|> afterDisposed {
Queue.mainQueue().async {
progressDisposable.dispose()
}
}
let joinChannelDisposable = MetaDisposable()
cancelImpl = {
joinChannelDisposable.set(nil)
}
let isSavedMessages = peerId == context.account.peerId
joinChannelDisposable.set((createSignal
|> deliverOnMainQueue).start(next: { _ in
}, error: { _ in
if !isSavedMessages, case let .user(peer) = peer, !peer.flags.contains(.isSupport), peer.botInfo == nil && !peer.isDeleted {
if !isContact {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_AddToContacts, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor) }, action: { _, f in
context.sharedContext.openAddPersonContact(context: context, peerId: peerId, pushController: { controller in
if let navigationController = chatListController?.navigationController as? NavigationController {
navigationController.pushViewController(controller)
}
}, present: { c, a in
if let chatListController = chatListController {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
chatListController.present(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
chatListController.present(c, in: .window(.root), with: a)
}
}, completed: {
if let navigationController = (chatListController?.navigationController as? NavigationController) {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: peerId)))
}
}))
})
f(.default)
})))
items.append(.separator)
}
}
}
if case .chatList = source, peerGroup != nil {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Delete, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
if let chatListController = chatListController {
chatListController.deletePeerChat(peerId: peerId, joined: joined)
var isMuted = false
if case .muted = notificationSettings.muteState {
isMuted = true
}
var isUnread = false
if let readState = readState, readState.isUnread {
isUnread = true
}
if case let .chatList(currentFilter) = source {
if let currentFilter = currentFilter, case let .filter(id, title, emoticon, data) = currentFilter {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_RemoveFromFolder, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/RemoveFromFolder"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
var filters = filters
for i in 0 ..< filters.count {
if filters[i].id == currentFilter.id {
var updatedData = data
let _ = updatedData.addExcludePeer(peerId: peer.id)
filters[i] = .filter(id: id, title: title, emoticon: emoticon, data: updatedData)
break
}
}
return filters
}
|> deliverOnMainQueue).start(completed: {
c.dismiss(completion: {
chatListController?.present(UndoOverlayController(presentationData: presentationData, content: .chatRemovedFromFolder(chatTitle: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), folderTitle: title), elevatedLayout: false, animateInAsReplacement: true, action: { _ in
return false
}), in: .current)
})
})
})))
} else {
var hasFolders = false
for case let .filter(_, _, _, data) in filters {
let predicate = chatListFilterPredicate(filter: data)
if predicate.includes(peer: peer._asPeer(), groupId: .root, isRemovedFromTotalUnreadCount: isMuted, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: false) {
continue
}
var data = data
if data.addIncludePeer(peerId: peer.id) {
hasFolders = true
break
}
}
if hasFolders {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_AddToFolder, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Folder"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
var updatedItems: [ContextMenuItem] = []
for filter in filters {
if case let .filter(_, title, _, data) = filter {
let predicate = chatListFilterPredicate(filter: data)
if predicate.includes(peer: peer._asPeer(), groupId: .root, isRemovedFromTotalUnreadCount: isMuted, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: false) {
continue
}
var data = data
if !data.addIncludePeer(peerId: peer.id) {
continue
}
let filterType = chatListFilterType(data)
updatedItems.append(.action(ContextMenuActionItem(text: title, icon: { theme in
let imageName: String
switch filterType {
case .generic:
imageName = "Chat/Context Menu/List"
case .unmuted:
imageName = "Chat/Context Menu/Unmute"
case .unread:
imageName = "Chat/Context Menu/MarkAsUnread"
case .channels:
imageName = "Chat/Context Menu/Channels"
case .groups:
imageName = "Chat/Context Menu/Groups"
case .bots:
imageName = "Chat/Context Menu/Bots"
case .contacts:
imageName = "Chat/Context Menu/User"
case .nonContacts:
imageName = "Chat/Context Menu/UnknownUser"
}
return generateTintedImage(image: UIImage(bundleImageName: imageName), color: theme.contextMenu.primaryColor)
}, action: { c, f in
c.dismiss(completion: {
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
var filters = filters
for i in 0 ..< filters.count {
if filters[i].id == filter.id {
if case let .filter(id, title, emoticon, data) = filter {
var updatedData = data
let _ = updatedData.addIncludePeer(peerId: peer.id)
filters[i] = .filter(id: id, title: title, emoticon: emoticon, data: updatedData)
}
break
}
}
return filters
}).start()
chatListController?.present(UndoOverlayController(presentationData: presentationData, content: .chatAddedToFolder(chatTitle: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), folderTitle: title), elevatedLayout: false, animateInAsReplacement: true, action: { _ in
return false
}), in: .current)
})
})))
}
}
updatedItems.append(.separator)
updatedItems.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Back, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
}, action: { c, _ in
c.setItems(chatContextMenuItems(context: context, peerId: peerId, promoInfo: promoInfo, source: source, chatListController: chatListController, joined: joined) |> map { ContextController.Items(content: .list($0)) }, minHeight: nil)
})))
c.setItems(.single(ContextController.Items(content: .list(updatedItems))), minHeight: nil)
})))
}
}
f(.default)
})))
}
}
if let item = items.last, case .separator = item {
items.removeLast()
}
if isUnread {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAsRead, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsRead"), color: theme.contextMenu.primaryColor) }, action: { _, f in
let _ = togglePeerUnreadMarkInteractively(postbox: context.account.postbox, viewTracker: context.account.viewTracker, peerId: peerId).start()
f(.default)
})))
} else {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAsUnread, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsUnread"), color: theme.contextMenu.primaryColor) }, action: { _, f in
let _ = togglePeerUnreadMarkInteractively(postbox: context.account.postbox, viewTracker: context.account.viewTracker, peerId: peerId).start()
f(.default)
})))
}
return items
let archiveEnabled = !isSavedMessages && peerId != PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(777000)) && peerId == context.account.peerId
if let group = peerGroup {
if archiveEnabled {
let isArchived = group == .archive
items.append(.action(ContextMenuActionItem(text: isArchived ? strings.ChatList_Context_Unarchive : strings.ChatList_Context_Archive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isArchived ? "Chat/Context Menu/Unarchive" : "Chat/Context Menu/Archive"), color: theme.contextMenu.primaryColor) }, action: { _, f in
if isArchived {
let _ = (context.engine.peers.updatePeersGroupIdInteractively(peerIds: [peerId], groupId: .root)
|> deliverOnMainQueue).start(completed: {
f(.default)
})
} else {
if let chatListController = chatListController {
chatListController.archiveChats(peerIds: [peerId])
f(.default)
} else {
let _ = (context.engine.peers.updatePeersGroupIdInteractively(peerIds: [peerId], groupId: .archive)
|> deliverOnMainQueue).start(completed: {
f(.default)
})
}
}
})))
}
if isPinned || chatListFilter == nil || peerId.namespace != Namespaces.Peer.SecretChat {
items.append(.action(ContextMenuActionItem(text: isPinned ? strings.ChatList_Context_Unpin : strings.ChatList_Context_Pin, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin" : "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { c, f in
let _ = (context.engine.peers.toggleItemPinned(location: location, itemId: .peer(peerId))
|> deliverOnMainQueue).start(next: { result in
switch result {
case .done:
f(.default)
case let .limitExceeded(count, _):
f(.default)
var replaceImpl: ((ViewController) -> Void)?
let controller = PremiumLimitScreen(context: context, subject: .pins, count: Int32(count), action: {
let premiumScreen = PremiumIntroScreen(context: context, source: .pinnedChats)
replaceImpl?(premiumScreen)
})
chatListController?.push(controller)
replaceImpl = { [weak controller] c in
controller?.replace(with: c)
}
}
})
})))
}
if !isSavedMessages {
var isMuted = false
if case .muted = notificationSettings.muteState {
isMuted = true
}
items.append(.action(ContextMenuActionItem(text: isMuted ? strings.ChatList_Context_Unmute : strings.ChatList_Context_Mute, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) }, action: { _, f in
let _ = (context.engine.peers.togglePeerMuted(peerId: peerId)
|> deliverOnMainQueue).start(completed: {
f(.default)
})
})))
}
} else {
if case .search = source {
if case let .channel(peer) = peer {
let text: String
if case .broadcast = peer.info {
text = strings.ChatList_Context_JoinChannel
} else {
text = strings.ChatList_Context_JoinChat
}
items.append(.action(ContextMenuActionItem(text: text, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor) }, action: { _, f in
var createSignal = context.peerChannelMemberCategoriesContextsManager.join(engine: context.engine, peerId: peerId, hash: nil)
var cancelImpl: (() -> Void)?
let progressSignal = Signal<Never, NoError> { subscriber in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
cancelImpl?()
}))
chatListController?.present(controller, in: .window(.root))
return ActionDisposable { [weak controller] in
Queue.mainQueue().async() {
controller?.dismiss()
}
}
}
|> runOn(Queue.mainQueue())
|> delay(0.15, queue: Queue.mainQueue())
let progressDisposable = progressSignal.start()
createSignal = createSignal
|> afterDisposed {
Queue.mainQueue().async {
progressDisposable.dispose()
}
}
let joinChannelDisposable = MetaDisposable()
cancelImpl = {
joinChannelDisposable.set(nil)
}
joinChannelDisposable.set((createSignal
|> deliverOnMainQueue).start(next: { _ in
}, error: { _ in
if let chatListController = chatListController {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
chatListController.present(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
}
}, completed: {
if let navigationController = (chatListController?.navigationController as? NavigationController) {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: peerId)))
}
}))
f(.default)
})))
}
}
}
if case .chatList = source, peerGroup != nil {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Delete, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
if let chatListController = chatListController {
chatListController.deletePeerChat(peerId: peerId, joined: joined)
}
f(.default)
})))
}
if let item = items.last, case .separator = item {
items.removeLast()
}
return items
}
}
}
}

View File

@ -964,7 +964,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
strongSelf.archiveChats(peerIds: [peerId])
} else {
strongSelf.chatListDisplayNode.containerNode.currentItemNode.setCurrentRemovingPeerId(peerId)
let _ = updatePeerGroupIdInteractively(postbox: strongSelf.context.account.postbox, peerId: peerId, groupId: group ? Namespaces.PeerGroup.archive : .root).start(completed: {
let _ = strongSelf.context.engine.peers.updatePeersGroupIdInteractively(peerIds: [peerId], groupId: group ? .archive : .root).start(completed: {
guard let strongSelf = self else {
return
}
@ -2419,7 +2419,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
override public func toolbarActionSelected(action: ToolbarActionOption) {
let peerIds = self.chatListDisplayNode.containerNode.currentItemNode.currentState.selectedPeerIds
if case .left = action {
let signal: Signal<Void, NoError>
let signal: Signal<Never, NoError>
var completion: (() -> Void)?
let context = self.context
if !peerIds.isEmpty {
@ -2432,6 +2432,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
togglePeerUnreadMarkInteractively(transaction: transaction, viewTracker: context.account.viewTracker, peerId: peerId, setToValue: false)
}
}
|> ignoreValues
} else {
let groupId = self.groupId
let filterPredicate: ChatListFilterPredicate?
@ -2440,14 +2441,14 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
} else {
filterPredicate = nil
}
signal = self.context.account.postbox.transaction { transaction -> Void in
markAllChatsAsReadInteractively(transaction: transaction, viewTracker: context.account.viewTracker, groupId: groupId, filterPredicate: filterPredicate)
if let filterPredicate = filterPredicate {
for additionalGroupId in filterPredicate.includeAdditionalPeerGroupIds {
markAllChatsAsReadInteractively(transaction: transaction, viewTracker: context.account.viewTracker, groupId: additionalGroupId, filterPredicate: filterPredicate)
}
var markItems: [(groupId: EngineChatList.Group, filterPredicate: ChatListFilterPredicate?)] = []
markItems.append((EngineChatList.Group(groupId), filterPredicate))
if let filterPredicate = filterPredicate {
for additionalGroupId in filterPredicate.includeAdditionalPeerGroupIds {
markItems.append((EngineChatList.Group(additionalGroupId), filterPredicate))
}
}
signal = self.context.engine.messages.markAllChatsAsReadInteractively(items: markItems)
}
let _ = (signal
|> deliverOnMainQueue).start(completed: { [weak self] in
@ -2545,11 +2546,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
} else {
if !peerIds.isEmpty {
self.chatListDisplayNode.containerNode.currentItemNode.setCurrentRemovingPeerId(peerIds.first!)
let _ = (self.context.account.postbox.transaction { transaction -> Void in
for peerId in peerIds {
updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: .root)
}
}
let _ = (self.context.engine.peers.updatePeersGroupIdInteractively(peerIds: Array(peerIds), groupId: .root)
|> deliverOnMainQueue).start(completed: { [weak self] in
guard let strongSelf = self else {
return
@ -3047,15 +3044,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
guard !peerIds.isEmpty else {
return
}
let postbox = self.context.account.postbox
let engine = self.context.engine
self.chatListDisplayNode.containerNode.currentItemNode.setCurrentRemovingPeerId(peerIds[0])
let _ = (ApplicationSpecificNotice.incrementArchiveChatTips(accountManager: self.context.sharedContext.accountManager, count: 1)
|> deliverOnMainQueue).start(next: { [weak self] previousHintCount in
let _ = (postbox.transaction { transaction -> Void in
for peerId in peerIds {
updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: Namespaces.PeerGroup.archive)
}
}
let _ = (engine.peers.updatePeersGroupIdInteractively(peerIds: peerIds, groupId: .archive)
|> deliverOnMainQueue).start(completed: {
guard let strongSelf = self else {
return
@ -3072,11 +3065,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}
if value == .undo {
strongSelf.chatListDisplayNode.containerNode.currentItemNode.setCurrentRemovingPeerId(peerIds[0])
let _ = (postbox.transaction { transaction -> Void in
for peerId in peerIds {
updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: .root)
}
}
let _ = (engine.peers.updatePeersGroupIdInteractively(peerIds: peerIds, groupId: .root)
|> deliverOnMainQueue).start(completed: {
guard let strongSelf = self else {
return

View File

@ -719,7 +719,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
}
let (peers, messages) = strongSelf.currentMessages
return strongSelf.context.sharedContext.chatAvailableMessageActions(postbox: strongSelf.context.account.postbox, accountPeerId: strongSelf.context.account.peerId, messageIds: messageIds, messages: messages, peers: peers)
return strongSelf.context.sharedContext.chatAvailableMessageActions(engine: strongSelf.context.engine, accountPeerId: strongSelf.context.account.peerId, messageIds: messageIds, messages: messages, peers: peers)
}
self.selectionPanelNode = selectionPanelNode
self.addSubnode(selectionPanelNode)
@ -825,7 +825,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
}
let items = combineLatest(queue: .mainQueue(),
context.sharedContext.chatAvailableMessageActions(postbox: context.account.postbox, accountPeerId: context.account.peerId, messageIds: [message.id], messages: [message.id: message], peers: [:]),
context.sharedContext.chatAvailableMessageActions(engine: context.engine, accountPeerId: context.account.peerId, messageIds: [message.id], messages: [message.id: message], peers: [:]),
isCachedValue |> take(1)
)
|> deliverOnMainQueue
@ -934,7 +934,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
let context = self.context
let (peers, messages) = self.currentMessages
let items = context.sharedContext.chatAvailableMessageActions(postbox: context.account.postbox, accountPeerId: context.account.peerId, messageIds: [message.id], messages: messages, peers: peers)
let items = context.sharedContext.chatAvailableMessageActions(engine: context.engine, accountPeerId: context.account.peerId, messageIds: [message.id], messages: messages, peers: peers)
|> map { [weak self] actions -> [ContextMenuItem] in
guard let strongSelf = self else {
return []
@ -1000,7 +1000,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
let strings = strongSelf.presentationData.strings
let (peers, messages) = strongSelf.currentMessages
let items = context.sharedContext.chatAvailableMessageActions(postbox: context.account.postbox, accountPeerId: context.account.peerId, messageIds: [message.id], messages: messages, peers: peers)
let items = context.sharedContext.chatAvailableMessageActions(engine: context.engine, accountPeerId: context.account.peerId, messageIds: [message.id], messages: messages, peers: peers)
|> map { actions -> [ContextMenuItem] in
var items: [ContextMenuItem] = []
@ -1129,7 +1129,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
self.context.engine.messages.ensureMessagesAreLocallyAvailable(messages: messages.values.filter { messageIds.contains($0.id) })
self.activeActionDisposable.set((self.context.sharedContext.chatAvailableMessageActions(postbox: self.context.account.postbox, accountPeerId: self.context.account.peerId, messageIds: messageIds, messages: messages, peers: peers)
self.activeActionDisposable.set((self.context.sharedContext.chatAvailableMessageActions(engine: self.context.engine, accountPeerId: self.context.account.peerId, messageIds: messageIds, messages: messages, peers: peers)
|> deliverOnMainQueue).start(next: { [weak self] actions in
if let strongSelf = self, !actions.options.isEmpty {
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)

View File

@ -581,8 +581,6 @@ public enum ChatListGlobalScrollOption {
}
public enum ChatListNodeScrollPosition {
case auto
case autoUp
case top
}
@ -1895,29 +1893,6 @@ public final class ChatListNode: ListView {
public func scrollToPosition(_ position: ChatListNodeScrollPosition) {
if let view = self.chatListView?.originalView {
if case .auto = position {
switch self.visibleContentOffset() {
case .none, .unknown:
if let maxVisibleChatListIndex = self.currentlyVisibleLatestChatListIndex() {
self.scrollToEarliestUnread(earlierThan: maxVisibleChatListIndex)
return
}
case let .known(offset):
if offset <= 0.0 {
self.scrollToEarliestUnread(earlierThan: nil)
return
} else {
if let maxVisibleChatListIndex = self.currentlyVisibleLatestChatListIndex() {
self.scrollToEarliestUnread(earlierThan: maxVisibleChatListIndex)
return
}
}
}
} else if case .autoUp = position, let maxVisibleChatListIndex = self.currentlyVisibleLatestChatListIndex() {
self.scrollToEarliestUnread(earlierThan: maxVisibleChatListIndex)
return
}
if view.laterIndex == nil {
self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
} else {
@ -1938,7 +1913,7 @@ public final class ChatListNode: ListView {
private func relativeUnreadChatListIndex(position: EngineChatList.RelativePosition) -> Signal<EngineChatList.Item.Index?, NoError> {
let groupId = self.groupId
let postbox = self.context.account.postbox
let engine = self.context.engine
return self.context.sharedContext.accountManager.transaction { transaction -> Signal<EngineChatList.Item.Index?, NoError> in
var filter = true
if let inAppNotificationSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings)?.get(InAppNotificationSettings.self) {
@ -1947,31 +1922,11 @@ public final class ChatListNode: ListView {
filter = true
}
}
return postbox.transaction { transaction -> EngineChatList.Item.Index? in
return transaction.getRelativeUnreadChatListIndex(filtered: filter, position: position._asPosition(), groupId: groupId._asGroup())
}
return engine.messages.getRelativeUnreadChatListIndex(filtered: filter, position: position, groupId: groupId)
}
|> switchToLatest
}
public func scrollToEarliestUnread(earlierThan: EngineChatList.Item.Index?) {
let _ = (relativeUnreadChatListIndex(position: .earlier(than: earlierThan)) |> deliverOnMainQueue).start(next: { [weak self] index in
guard let strongSelf = self else {
return
}
if let index = index {
let location: ChatListNodeLocation = .scroll(index: index, sourceIndex: self?.currentlyVisibleLatestChatListIndex() ?? .absoluteUpperBound
, scrollPosition: .center(.top), animated: true, filter: strongSelf.chatListFilter)
strongSelf.setChatListLocation(location)
} else {
let location: ChatListNodeLocation = .scroll(index: .absoluteUpperBound, sourceIndex: .absoluteLowerBound
, scrollPosition: .top(0.0), animated: true, filter: strongSelf.chatListFilter)
strongSelf.setChatListLocation(location)
}
})
}
public func selectChat(_ option: ChatListSelectionOption) {
guard let interaction = self.interaction else {
return

View File

@ -230,7 +230,7 @@ public func chatMessageGalleryControllerData(context: AccountContext, chatLocati
if let timecode = timecode {
startState = .single((timecode: timecode, rate: 1.0))
} else {
startState = mediaPlaybackStoredState(postbox: context.account.postbox, messageId: message.id)
startState = mediaPlaybackStoredState(engine: context.engine, messageId: message.id)
|> map { state in
return (state?.timestamp, state?.playbackRate.doubleValue ?? 1.0)
}

View File

@ -1093,7 +1093,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
}
private func commitDeleteMessages(_ messages: [EngineMessage], ask: Bool) {
self.messageContextDisposable.set((self.context.sharedContext.chatAvailableMessageActions(postbox: self.context.account.postbox, accountPeerId: self.context.account.peerId, messageIds: Set(messages.map { $0.id })) |> deliverOnMainQueue).start(next: { [weak self] actions in
self.messageContextDisposable.set((self.context.sharedContext.chatAvailableMessageActions(engine: self.context.engine, accountPeerId: self.context.account.peerId, messageIds: Set(messages.map { $0.id })) |> deliverOnMainQueue).start(next: { [weak self] actions in
if let strongSelf = self, let controllerInteration = strongSelf.controllerInteraction, !actions.options.isEmpty {
var presentationData = strongSelf.presentationData
if !presentationData.theme.overallDarkAppearance {

View File

@ -317,7 +317,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
Queue.concurrentDefaultQueue().async {
if let message = strongSelf.message, !message.isCopyProtected() && !imageReference.media.flags.contains(.hasStickers) {
strongSelf.recognitionDisposable.set((recognizedContent(postbox: strongSelf.context.account.postbox, image: { return generate(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets()))?.generateImage() }, messageId: message.id)
strongSelf.recognitionDisposable.set((recognizedContent(engine: strongSelf.context.engine, image: { return generate(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets()))?.generateImage() }, messageId: message.id)
|> deliverOnMainQueue).start(next: { [weak self] results in
if let strongSelf = self {
strongSelf.recognizedContentNode?.removeFromSupernode()

View File

@ -26,36 +26,30 @@ private final class CachedImageRecognizedContent: Codable {
}
}
private func cachedImageRecognizedContent(postbox: Postbox, messageId: MessageId) -> Signal<CachedImageRecognizedContent?, NoError> {
return postbox.transaction { transaction -> CachedImageRecognizedContent? in
let key = ValueBoxKey(length: 20)
key.setInt32(0, value: messageId.namespace)
key.setInt32(4, value: messageId.peerId.namespace._internalGetInt32Value())
key.setInt64(8, value: messageId.peerId.id._internalGetInt64Value())
key.setInt32(16, value: messageId.id)
if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedImageRecognizedContent, key: key))?.get(CachedImageRecognizedContent.self) {
return entry
} else {
return nil
}
private func cachedImageRecognizedContent(engine: TelegramEngine, messageId: MessageId) -> Signal<CachedImageRecognizedContent?, NoError> {
let key = ValueBoxKey(length: 20)
key.setInt32(0, value: messageId.namespace)
key.setInt32(4, value: messageId.peerId.namespace._internalGetInt32Value())
key.setInt64(8, value: messageId.peerId.id._internalGetInt64Value())
key.setInt32(16, value: messageId.id)
return engine.data.get(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: ApplicationSpecificItemCacheCollectionId.cachedImageRecognizedContent, id: key))
|> map { entry -> CachedImageRecognizedContent? in
return entry?.get(CachedImageRecognizedContent.self)
}
}
private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 50, highWaterItemCount: 100)
private func updateCachedImageRecognizedContent(postbox: Postbox, messageId: MessageId, content: CachedImageRecognizedContent?) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
let key = ValueBoxKey(length: 20)
key.setInt32(0, value: messageId.namespace)
key.setInt32(4, value: messageId.peerId.namespace._internalGetInt32Value())
key.setInt64(8, value: messageId.peerId.id._internalGetInt64Value())
key.setInt32(16, value: messageId.id)
let id = ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedImageRecognizedContent, key: key)
if let content = content, let entry = CodableEntry(content) {
transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec)
} else {
transaction.removeItemCacheEntry(id: id)
}
private func updateCachedImageRecognizedContent(engine: TelegramEngine, messageId: MessageId, content: CachedImageRecognizedContent?) -> Signal<Never, NoError> {
let key = ValueBoxKey(length: 20)
key.setInt32(0, value: messageId.namespace)
key.setInt32(4, value: messageId.peerId.namespace._internalGetInt32Value())
key.setInt64(8, value: messageId.peerId.id._internalGetInt64Value())
key.setInt32(16, value: messageId.id)
if let content = content {
return engine.itemCache.put(collectionId: ApplicationSpecificItemCacheCollectionId.cachedImageRecognizedContent, id: key, item: content)
} else {
return engine.itemCache.remove(collectionId: ApplicationSpecificItemCacheCollectionId.cachedImageRecognizedContent, id: key)
}
}
@ -338,8 +332,8 @@ private func recognizeContent(in image: UIImage?) -> Signal<[RecognizedContent],
}
}
public func recognizedContent(postbox: Postbox, image: @escaping () -> UIImage?, messageId: MessageId) -> Signal<[RecognizedContent], NoError> {
return cachedImageRecognizedContent(postbox: postbox, messageId: messageId)
public func recognizedContent(engine: TelegramEngine, image: @escaping () -> UIImage?, messageId: MessageId) -> Signal<[RecognizedContent], NoError> {
return cachedImageRecognizedContent(engine: engine, messageId: messageId)
|> mapToSignal { cachedContent -> Signal<[RecognizedContent], NoError> in
if let cachedContent = cachedContent {
return .single(cachedContent.results)
@ -349,7 +343,7 @@ public func recognizedContent(postbox: Postbox, image: @escaping () -> UIImage?,
|> then(
recognizeContent(in: image())
|> beforeNext { results in
let _ = updateCachedImageRecognizedContent(postbox: postbox, messageId: messageId, content: CachedImageRecognizedContent(results: results)).start()
let _ = updateCachedImageRecognizedContent(engine: engine, messageId: messageId, content: CachedImageRecognizedContent(results: results)).start()
}
)
}

View File

@ -32,29 +32,23 @@ public final class CachedInstantPage: Codable {
}
}
public func cachedInstantPage(postbox: Postbox, url: String) -> Signal<CachedInstantPage?, NoError> {
return postbox.transaction { transaction -> CachedInstantPage? in
let key = ValueBoxKey(length: 8)
key.setInt64(0, value: Int64(bitPattern: url.persistentHashValue))
if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedInstantPages, key: key))?.get(CachedInstantPage.self) {
return entry
} else {
return nil
}
public func cachedInstantPage(engine: TelegramEngine, url: String) -> Signal<CachedInstantPage?, NoError> {
let key = ValueBoxKey(length: 8)
key.setInt64(0, value: Int64(bitPattern: url.persistentHashValue))
return engine.data.get(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: ApplicationSpecificItemCacheCollectionId.cachedInstantPages, id: key))
|> map { entry -> CachedInstantPage? in
return entry?.get(CachedInstantPage.self)
}
}
private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 5, highWaterItemCount: 10)
public func updateCachedInstantPage(postbox: Postbox, url: String, webPage: TelegramMediaWebpage?) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
let key = ValueBoxKey(length: 8)
key.setInt64(0, value: Int64(bitPattern: url.persistentHashValue))
let id = ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedInstantPages, key: key)
if let webPage = webPage, let entry = CodableEntry(CachedInstantPage(webPage: webPage, timestamp: Int32(CFAbsoluteTimeGetCurrent()))) {
transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec)
} else {
transaction.removeItemCacheEntry(id: id)
}
public func updateCachedInstantPage(engine: TelegramEngine, url: String, webPage: TelegramMediaWebpage?) -> Signal<Never, NoError> {
let key = ValueBoxKey(length: 8)
key.setInt64(0, value: Int64(bitPattern: url.persistentHashValue))
if let webPage = webPage {
return engine.itemCache.put(collectionId: ApplicationSpecificItemCacheCollectionId.cachedInstantPages, id: key, item: CachedInstantPage(webPage: webPage, timestamp: Int32(CFAbsoluteTimeGetCurrent())))
} else {
return engine.itemCache.remove(collectionId: ApplicationSpecificItemCacheCollectionId.cachedInstantPages, id: key)
}
}

View File

@ -51,18 +51,18 @@ public func cachedPrivacyPage(context: AccountContext) -> Signal<ResolvedUrl, No
private func cachedInternalInstantPage(context: AccountContext, url: String) -> Signal<ResolvedUrl, NoError> {
let (cachedUrl, anchor) = extractAnchor(string: url)
return cachedInstantPage(postbox: context.account.postbox, url: cachedUrl)
return cachedInstantPage(engine: context.engine, url: cachedUrl)
|> mapToSignal { cachedInstantPage -> Signal<ResolvedUrl, NoError> in
let updated = resolveInstantViewUrl(account: context.account, url: url)
|> afterNext { result in
if case let .instantView(webPage, _) = result, case let .Loaded(content) = webPage.content, let instantPage = content.instantPage {
if instantPage.isComplete {
let _ = updateCachedInstantPage(postbox: context.account.postbox, url: cachedUrl, webPage: webPage).start()
let _ = updateCachedInstantPage(engine: context.engine, url: cachedUrl, webPage: webPage).start()
} else {
let _ = (actualizedWebpage(postbox: context.account.postbox, network: context.account.network, webpage: webPage)
|> mapToSignal { webPage -> Signal<Void, NoError> in
|> mapToSignal { webPage -> Signal<Never, NoError> in
if case let .Loaded(content) = webPage.content, let instantPage = content.instantPage, instantPage.isComplete {
return updateCachedInstantPage(postbox: context.account.postbox, url: cachedUrl, webPage: webPage)
return updateCachedInstantPage(engine: context.engine, url: cachedUrl, webPage: webPage)
} else {
return .complete()
}

View File

@ -141,7 +141,7 @@ public final class InstantPageController: ViewController {
}
override public func viewWillDisappear(_ animated: Bool) {
let _ = updateInstantPageStoredStateInteractively(postbox: self.context.account.postbox, webPage: self.webPage, state: self.controllerNode.currentState).start()
let _ = updateInstantPageStoredStateInteractively(engine: self.context.engine, webPage: self.webPage, state: self.controllerNode.currentState).start()
}
override public func loadDisplayNode() {
@ -167,7 +167,7 @@ public final class InstantPageController: ViewController {
}
})
self.storedStateDisposable = (instantPageStoredState(postbox: self.context.account.postbox, webPage: self.webPage)
self.storedStateDisposable = (instantPageStoredState(engine: self.context.engine, webPage: self.webPage)
|> deliverOnMainQueue).start(next: { [weak self] state in
if let strongSelf = self {
strongSelf.controllerNode.updateWebPage(strongSelf.webPage, anchor: strongSelf.anchor, state: state)

View File

@ -57,29 +57,23 @@ public final class InstantPageStoredState: Codable {
}
}
public func instantPageStoredState(postbox: Postbox, webPage: TelegramMediaWebpage) -> Signal<InstantPageStoredState?, NoError> {
return postbox.transaction { transaction -> InstantPageStoredState? in
let key = ValueBoxKey(length: 8)
key.setInt64(0, value: webPage.webpageId.id)
if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.instantPageStoredState, key: key))?.get(InstantPageStoredState.self) {
return entry
} else {
return nil
}
public func instantPageStoredState(engine: TelegramEngine, webPage: TelegramMediaWebpage) -> Signal<InstantPageStoredState?, NoError> {
let key = ValueBoxKey(length: 8)
key.setInt64(0, value: webPage.webpageId.id)
return engine.data.get(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: ApplicationSpecificItemCacheCollectionId.instantPageStoredState, id: key))
|> map { entry -> InstantPageStoredState? in
return entry?.get(InstantPageStoredState.self)
}
}
private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 100, highWaterItemCount: 200)
public func updateInstantPageStoredStateInteractively(postbox: Postbox, webPage: TelegramMediaWebpage, state: InstantPageStoredState?) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
let key = ValueBoxKey(length: 8)
key.setInt64(0, value: webPage.webpageId.id)
let id = ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.instantPageStoredState, key: key)
if let state = state, let entry = CodableEntry(state) {
transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec)
} else {
transaction.removeItemCacheEntry(id: id)
}
public func updateInstantPageStoredStateInteractively(engine: TelegramEngine, webPage: TelegramMediaWebpage, state: InstantPageStoredState?) -> Signal<Never, NoError> {
let key = ValueBoxKey(length: 8)
key.setInt64(0, value: webPage.webpageId.id)
if let state = state {
return engine.itemCache.put(collectionId: ApplicationSpecificItemCacheCollectionId.instantPageStoredState, id: key, item: state)
} else {
return engine.itemCache.remove(collectionId: ApplicationSpecificItemCacheCollectionId.instantPageStoredState, id: key)
}
}

View File

@ -32,34 +32,27 @@ public final class CachedGeocode: Codable {
}
}
private func cachedGeocode(postbox: Postbox, address: DeviceContactAddressData) -> Signal<CachedGeocode?, NoError> {
return postbox.transaction { transaction -> CachedGeocode? in
let key = ValueBoxKey(length: 8)
key.setInt64(0, value: Int64(bitPattern: address.string.persistentHashValue))
if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedGeocodes, key: key))?.get(CachedGeocode.self) {
return entry
} else {
return nil
}
private func cachedGeocode(engine: TelegramEngine, address: DeviceContactAddressData) -> Signal<CachedGeocode?, NoError> {
let key = ValueBoxKey(length: 8)
key.setInt64(0, value: Int64(bitPattern: address.string.persistentHashValue))
return engine.data.get(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: ApplicationSpecificItemCacheCollectionId.cachedGeocodes, id: key))
|> map { entry -> CachedGeocode? in
return entry?.get(CachedGeocode.self)
}
}
private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 10, highWaterItemCount: 20)
private func updateCachedGeocode(postbox: Postbox, address: DeviceContactAddressData, latitude: Double, longitude: Double) -> Signal<(Double, Double), NoError> {
return postbox.transaction { transaction -> (Double, Double) in
let key = ValueBoxKey(length: 8)
key.setInt64(0, value: Int64(bitPattern: address.string.persistentHashValue))
let id = ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedGeocodes, key: key)
if let entry = CodableEntry(CachedGeocode(latitude: latitude, longitude: longitude)) {
transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec)
}
return (latitude, longitude)
}
private func updateCachedGeocode(engine: TelegramEngine, address: DeviceContactAddressData, latitude: Double, longitude: Double) -> Signal<(Double, Double), NoError> {
let key = ValueBoxKey(length: 8)
key.setInt64(0, value: Int64(bitPattern: address.string.persistentHashValue))
return engine.itemCache.put(collectionId: ApplicationSpecificItemCacheCollectionId.cachedGeocodes, id: key, item: CachedGeocode(latitude: latitude, longitude: longitude))
|> map { _ -> (Double, Double) in }
|> then(.single((latitude, longitude)))
}
public func geocodeAddress(postbox: Postbox, address: DeviceContactAddressData) -> Signal<(Double, Double)?, NoError> {
return cachedGeocode(postbox: postbox, address: address)
public func geocodeAddress(engine: TelegramEngine, address: DeviceContactAddressData) -> Signal<(Double, Double)?, NoError> {
return cachedGeocode(engine: engine, address: address)
|> mapToSignal { cached -> Signal<(Double, Double)?, NoError> in
if let cached = cached {
return .single((cached.latitude, cached.longitude))
@ -67,7 +60,7 @@ public func geocodeAddress(postbox: Postbox, address: DeviceContactAddressData)
return geocodeLocation(dictionary: address.dictionary)
|> mapToSignal { coordinate in
if let (latitude, longitude) = coordinate {
return updateCachedGeocode(postbox: postbox, address: address, latitude: latitude, longitude: longitude)
return updateCachedGeocode(engine: engine, address: address, latitude: latitude, longitude: longitude)
|> map(Optional.init)
} else {
return .single(nil)

View File

@ -420,12 +420,12 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
let home: Signal<(Double, Double)?, NoError>
let work: Signal<(Double, Double)?, NoError>
if let address = homeAddress {
home = geocodeAddress(postbox: context.account.postbox, address: address)
home = geocodeAddress(engine: context.engine, address: address)
} else {
home = .single(nil)
}
if let address = workAddress {
work = geocodeAddress(postbox: context.account.postbox, address: address)
work = geocodeAddress(engine: context.engine, address: address)
} else {
work = .single(nil)
}

View File

@ -33,9 +33,8 @@ public func ==(lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool
}
public func nearbyVenues(context: AccountContext, latitude: Double, longitude: Double, query: String? = nil) -> Signal<[TelegramMediaMap], NoError> {
return context.account.postbox.transaction { transaction -> SearchBotsConfiguration in
return currentSearchBotsConfiguration(transaction: transaction)
} |> mapToSignal { searchBotsConfiguration in
return context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.SearchBots())
|> mapToSignal { searchBotsConfiguration in
return context.engine.peers.resolvePeerByName(name: searchBotsConfiguration.venueBotUsername ?? "foursquare")
|> take(1)
|> mapToSignal { peer -> Signal<ChatContextResultCollection?, NoError> in

View File

@ -29,35 +29,29 @@ public final class MediaPlaybackStoredState: Codable {
}
}
public func mediaPlaybackStoredState(postbox: Postbox, messageId: MessageId) -> Signal<MediaPlaybackStoredState?, NoError> {
return postbox.transaction { transaction -> MediaPlaybackStoredState? in
let key = ValueBoxKey(length: 20)
key.setInt32(0, value: messageId.namespace)
key.setInt32(4, value: messageId.peerId.namespace._internalGetInt32Value())
key.setInt64(8, value: messageId.peerId.id._internalGetInt64Value())
key.setInt32(16, value: messageId.id)
if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.mediaPlaybackStoredState, key: key))?.get(MediaPlaybackStoredState.self) {
return entry
} else {
return nil
}
public func mediaPlaybackStoredState(engine: TelegramEngine, messageId: MessageId) -> Signal<MediaPlaybackStoredState?, NoError> {
let key = ValueBoxKey(length: 20)
key.setInt32(0, value: messageId.namespace)
key.setInt32(4, value: messageId.peerId.namespace._internalGetInt32Value())
key.setInt64(8, value: messageId.peerId.id._internalGetInt64Value())
key.setInt32(16, value: messageId.id)
return engine.data.get(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: ApplicationSpecificItemCacheCollectionId.mediaPlaybackStoredState, id: key))
|> map { entry -> MediaPlaybackStoredState? in
return entry?.get(MediaPlaybackStoredState.self)
}
}
private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 25, highWaterItemCount: 50)
public func updateMediaPlaybackStoredStateInteractively(postbox: Postbox, messageId: MessageId, state: MediaPlaybackStoredState?) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
let key = ValueBoxKey(length: 20)
key.setInt32(0, value: messageId.namespace)
key.setInt32(4, value: messageId.peerId.namespace._internalGetInt32Value())
key.setInt64(8, value: messageId.peerId.id._internalGetInt64Value())
key.setInt32(16, value: messageId.id)
let id = ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.mediaPlaybackStoredState, key: key)
if let state = state, let entry = CodableEntry(state) {
transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec)
} else {
transaction.removeItemCacheEntry(id: id)
}
public func updateMediaPlaybackStoredStateInteractively(engine: TelegramEngine, messageId: MessageId, state: MediaPlaybackStoredState?) -> Signal<Never, NoError> {
let key = ValueBoxKey(length: 20)
key.setInt32(0, value: messageId.namespace)
key.setInt32(4, value: messageId.peerId.namespace._internalGetInt32Value())
key.setInt64(8, value: messageId.peerId.id._internalGetInt64Value())
key.setInt32(16, value: messageId.id)
if let state = state {
return engine.itemCache.put(collectionId: ApplicationSpecificItemCacheCollectionId.mediaPlaybackStoredState, id: key, item: state)
} else {
return engine.itemCache.remove(collectionId: ApplicationSpecificItemCacheCollectionId.mediaPlaybackStoredState, id: key)
}
}

View File

@ -387,11 +387,7 @@ private final class ContextControllerContentSourceImpl: ContextControllerContent
}
private func peerNearbyContextMenuItems(context: AccountContext, peerId: EnginePeer.Id, present: @escaping (ViewController) -> Void) -> Signal<[ContextMenuItem], NoError> {
return context.account.postbox.transaction { _ -> [ContextMenuItem] in
let items: [ContextMenuItem] = []
return items
}
return .single([])
}
private class PeersNearbyControllerImpl: ItemListController {

View File

@ -2,16 +2,6 @@ import Foundation
public typealias ItemCacheCollectionId = Int8
public struct ItemCacheCollectionSpec {
public let lowWaterItemCount: Int32
public let highWaterItemCount: Int32
public init(lowWaterItemCount: Int32, highWaterItemCount: Int32) {
self.lowWaterItemCount = lowWaterItemCount
self.highWaterItemCount = highWaterItemCount
}
}
struct ItemCacheCollectionState: PostboxCoding {
let nextAccessIndex: Int32

View File

@ -740,9 +740,9 @@ public final class Transaction {
return self.postbox?.storedMessageId(peerId: peerId, namespace: namespace, timestamp: timestamp)
}
public func putItemCacheEntry(id: ItemCacheEntryId, entry: CodableEntry, collectionSpec: ItemCacheCollectionSpec) {
public func putItemCacheEntry(id: ItemCacheEntryId, entry: CodableEntry) {
assert(!self.disposed)
self.postbox?.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec)
self.postbox?.putItemCacheEntry(id: id, entry: entry)
}
public func removeItemCacheEntry(id: ItemCacheEntryId) {
@ -2351,7 +2351,7 @@ final class PostboxImpl {
}
}
fileprivate func putItemCacheEntry(id: ItemCacheEntryId, entry: CodableEntry, collectionSpec: ItemCacheCollectionSpec) {
fileprivate func putItemCacheEntry(id: ItemCacheEntryId, entry: CodableEntry) {
self.itemCacheTable.put(id: id, entry: entry, metaTable: self.itemCacheMetaTable)
self.currentUpdatedCacheEntryKeys.insert(id)
}

View File

@ -675,9 +675,7 @@ public func notificationsAndSoundsController(context: AccountContext, exceptions
ActionSheetButtonItem(title: presentationData.strings.Notifications_Reset, color: .destructive, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
let modifyPeers = context.account.postbox.transaction { transaction -> Void in
transaction.resetAllPeerNotificationSettings(TelegramPeerNotificationSettings.defaultSettings)
}
let modifyPeers = context.engine.peers.resetAllPeerNotificationSettings()
let updateGlobal = updateGlobalNotificationSettingsInteractively(postbox: context.account.postbox, { _ in
return GlobalNotificationSettingsSet.defaultSettings
})

View File

@ -222,9 +222,7 @@ public func selectivePrivacyPeersController(context: AccountContext, title: Stri
actionsDisposable.add(removePeerDisposable)
let peersPromise = Promise<[SelectivePrivacyPeer]>()
peersPromise.set(context.account.postbox.transaction { transaction -> [SelectivePrivacyPeer] in
return Array(initialPeers.values)
})
peersPromise.set(.single(Array(initialPeers.values)))
let arguments = SelectivePrivacyPeersControllerArguments(context: context, setPeerIdWithRevealedOptions: { peerId, fromPeerId in
updateState { state in

View File

@ -365,10 +365,10 @@ public final class SettingsSearchContainerNode: SearchDisplayControllerContentNo
self.addSubnode(self.listNode)
let interaction = SettingsSearchInteraction(openItem: { result in
addRecentSettingsSearchItem(postbox: context.account.postbox, item: result.id)
addRecentSettingsSearchItem(engine: context.engine, item: result.id)
openResult(result)
}, deleteRecentItem: { id in
removeRecentSettingsSearchItem(postbox: context.account.postbox, item: id)
removeRecentSettingsSearchItem(engine: context.engine, item: id)
})
let searchableItems = Promise<[SettingsSearchableItem]>()
@ -449,7 +449,7 @@ public final class SettingsSearchContainerNode: SearchDisplayControllerContentNo
|> deliverOnMainQueue).start(next: { [weak self] recentSearchItems, faqItems, presentationData in
if let strongSelf = self {
let recentHeader = ChatListSearchItemHeader(type: .recentPeers, theme: presentationData.theme, strings: presentationData.strings, actionTitle: presentationData.strings.WebSearch_RecentSectionClear, action: {
clearRecentSettingsSearchItems(postbox: context.account.postbox)
clearRecentSettingsSearchItems(engine: context.engine)
})
let faqHeader = ChatListSearchItemHeader(type: .faq, theme: presentationData.theme, strings: presentationData.strings)

View File

@ -1,6 +1,7 @@
import Foundation
import UIKit
import Postbox
import TelegramCore
import SwiftSignalKit
import TelegramUIPreferences
@ -37,42 +38,32 @@ public final class RecentSettingsSearchQueryItem: Codable {
}
}
func addRecentSettingsSearchItem(postbox: Postbox, item: SettingsSearchableItemId) {
let _ = (postbox.transaction { transaction in
let itemId = SettingsSearchRecentQueryItemId(item.index)
if let entry = CodableEntry(RecentSettingsSearchQueryItem()) {
transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: ApplicationSpecificOrderedItemListCollectionId.settingsSearchRecentItems, item: OrderedItemListEntry(id: itemId.rawValue, contents: entry), removeTailIfCountExceeds: 100)
}
}).start()
func addRecentSettingsSearchItem(engine: TelegramEngine, item: SettingsSearchableItemId) {
let itemId = SettingsSearchRecentQueryItemId(item.index)
let _ = engine.orderedLists.addOrMoveToFirstPosition(collectionId: ApplicationSpecificOrderedItemListCollectionId.settingsSearchRecentItems, id: itemId.rawValue, item: RecentSettingsSearchQueryItem(), removeTailIfCountExceeds: 100).start()
}
func removeRecentSettingsSearchItem(postbox: Postbox, item: SettingsSearchableItemId) {
let _ = (postbox.transaction { transaction -> Void in
let itemId = SettingsSearchRecentQueryItemId(item.index)
transaction.removeOrderedItemListItem(collectionId: ApplicationSpecificOrderedItemListCollectionId.settingsSearchRecentItems, itemId: itemId.rawValue)
}).start()
func removeRecentSettingsSearchItem(engine: TelegramEngine, item: SettingsSearchableItemId) {
let itemId = SettingsSearchRecentQueryItemId(item.index)
let _ = engine.orderedLists.removeItem(collectionId: ApplicationSpecificOrderedItemListCollectionId.settingsSearchRecentItems, id: itemId.rawValue).start()
}
func clearRecentSettingsSearchItems(postbox: Postbox) {
let _ = (postbox.transaction { transaction -> Void in
transaction.replaceOrderedItemListItems(collectionId: ApplicationSpecificOrderedItemListCollectionId.settingsSearchRecentItems, items: [])
}).start()
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)])
|> mapToSignal { view -> Signal<[SettingsSearchableItemId], NoError> in
return postbox.transaction { transaction -> [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)
}
|> map { view -> [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)
}
}
return result
}
return result
}
}

View File

@ -599,7 +599,7 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
let resolvedWallpaper: TelegramWallpaper?
if let theme = theme, case let .file(file) = theme.chat.defaultWallpaper, file.id != 0 {
resolvedWallpaper = theme.chat.defaultWallpaper
updateCachedWallpaper(account: context.account, wallpaper: theme.chat.defaultWallpaper)
updateCachedWallpaper(engine: context.engine, wallpaper: theme.chat.defaultWallpaper)
} else {
resolvedWallpaper = nil
}

View File

@ -433,7 +433,7 @@ final class ThemeGridSearchContentNode: SearchDisplayControllerContentNode {
let query = strongSelf.queryValue.query
if !query.isEmpty {
let _ = addRecentWallpaperSearchQuery(postbox: strongSelf.context.account.postbox, string: query).start()
let _ = addRecentWallpaperSearchQuery(engine: strongSelf.context.engine, string: query).start()
}
}
}, selectColor: { [weak self] color in
@ -444,12 +444,10 @@ final class ThemeGridSearchContentNode: SearchDisplayControllerContentNode {
return query
}, updateInterface: true)
}, deleteRecentQuery: { query in
let _ = removeRecentWallpaperSearchQuery(postbox: context.account.postbox, string: query).start()
let _ = removeRecentWallpaperSearchQuery(engine: context.engine, string: query).start()
})
let configuration = self.context.account.postbox.transaction { transaction -> SearchBotsConfiguration in
return currentSearchBotsConfiguration(transaction: transaction)
}
let configuration = self.context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.SearchBots())
let foundItems = self.queryPromise.get()
|> mapToSignal { query -> Signal<([ThemeGridSearchEntry], Bool)?, NoError> in
@ -582,7 +580,7 @@ final class ThemeGridSearchContentNode: SearchDisplayControllerContentNode {
}
let header = ChatListSearchItemHeader(type: .recentPeers, theme: presentationData.theme, strings: presentationData.strings, actionTitle: presentationData.strings.WebSearch_RecentSectionClear, action: {
_ = clearRecentWallpaperSearchQueries(postbox: strongSelf.context.account.postbox).start()
let _ = clearRecentWallpaperSearchQueries(engine: strongSelf.context.engine).start()
})
let previousEntries = previousRecentItems.swap(entries)

View File

@ -1,5 +1,6 @@
import Foundation
import Postbox
import TelegramCore
import SwiftSignalKit
import TelegramUIPreferences
@ -34,42 +35,36 @@ public final class RecentWallpaperSearchQueryItem: Codable {
}
}
func addRecentWallpaperSearchQuery(postbox: Postbox, string: String) -> Signal<Void, NoError> {
return postbox.transaction { transaction in
if let itemId = WallpaperSearchRecentQueryItemId(string) {
if let entry = CodableEntry(RecentWallpaperSearchQueryItem()) {
transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: ApplicationSpecificOrderedItemListCollectionId.wallpaperSearchRecentQueries, item: OrderedItemListEntry(id: itemId.rawValue, contents: entry), removeTailIfCountExceeds: 100)
}
}
func addRecentWallpaperSearchQuery(engine: TelegramEngine, string: String) -> Signal<Never, NoError> {
if let itemId = WallpaperSearchRecentQueryItemId(string) {
return engine.orderedLists.addOrMoveToFirstPosition(collectionId: ApplicationSpecificOrderedItemListCollectionId.wallpaperSearchRecentQueries, id: itemId.rawValue, item: RecentWallpaperSearchQueryItem(), removeTailIfCountExceeds: 100)
} else {
return .complete()
}
}
func removeRecentWallpaperSearchQuery(postbox: Postbox, string: String) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
if let itemId = WallpaperSearchRecentQueryItemId(string) {
transaction.removeOrderedItemListItem(collectionId: ApplicationSpecificOrderedItemListCollectionId.wallpaperSearchRecentQueries, itemId: itemId.rawValue)
}
func removeRecentWallpaperSearchQuery(engine: TelegramEngine, string: String) -> Signal<Never, NoError> {
if let itemId = WallpaperSearchRecentQueryItemId(string) {
return engine.orderedLists.removeItem(collectionId: ApplicationSpecificOrderedItemListCollectionId.wallpaperSearchRecentQueries, id: itemId.rawValue)
} else {
return .complete()
}
}
func clearRecentWallpaperSearchQueries(postbox: Postbox) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
transaction.replaceOrderedItemListItems(collectionId: ApplicationSpecificOrderedItemListCollectionId.wallpaperSearchRecentQueries, items: [])
}
func clearRecentWallpaperSearchQueries(engine: TelegramEngine) -> Signal<Never, NoError> {
return engine.orderedLists.clear(collectionId: ApplicationSpecificOrderedItemListCollectionId.wallpaperSearchRecentQueries)
}
func wallpaperSearchRecentQueries(postbox: Postbox) -> Signal<[String], NoError> {
return postbox.combinedView(keys: [.orderedItemList(id: ApplicationSpecificOrderedItemListCollectionId.wallpaperSearchRecentQueries)])
|> mapToSignal { view -> Signal<[String], NoError> in
return postbox.transaction { transaction -> [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)
}
}
return result
|> map { view -> [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)
}
}
return result
}
}

View File

@ -673,24 +673,19 @@ public final class ShareController: ViewController {
for (id, status, error) in statuses {
if let error = error {
Queue.mainQueue().async {
let _ = (account.postbox.transaction { transaction -> Peer? in
TelegramEngine(account: account).messages.deleteMessages(transaction: transaction, ids: [id])
return transaction.getPeer(id.peerId)
}
let _ = TelegramEngine(account: account).messages.deleteMessagesInteractively(messageIds: [id], type: .forEveryone).start()
let _ = (TelegramEngine(account: account).data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: id.peerId))
|> deliverOnMainQueue).start(next: { peer in
guard let strongSelf = self, let peer = peer else {
return
}
if !displayedError, case .slowmodeActive = error {
displayedError = true
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: strongSelf.presentationData.strings.Chat_SlowmodeSendError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: strongSelf.presentationData.strings.Chat_SlowmodeSendError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
}
})
}
}
let _ = account.postbox.transaction({ transaction in
}).start()
if status != nil {
hasStatuses = true
}

View File

@ -211,7 +211,6 @@ public final class PresentationCallImpl: PresentationCall {
private let serializedData: String?
private let dataSaving: VoiceCallDataSaving
private let derivedState: VoipDerivedState
private let proxyServer: ProxyServerSettings?
private let auxiliaryServers: [OngoingCallContext.AuxiliaryServer]
private let currentNetworkType: NetworkType
@ -307,7 +306,6 @@ public final class PresentationCallImpl: PresentationCall {
callKitIntegration: CallKitIntegration?,
serializedData: String?,
dataSaving: VoiceCallDataSaving,
derivedState: VoipDerivedState,
getDeviceAccessData: @escaping () -> (presentationData: PresentationData, present: (ViewController, Any?) -> Void, openSettings: () -> Void),
initialState: CallSession?,
internalId: CallSessionInternalId,
@ -363,7 +361,6 @@ public final class PresentationCallImpl: PresentationCall {
self.serializedData = serializedData
self.dataSaving = dataSaving
self.derivedState = derivedState
self.proxyServer = proxyServer
self.currentNetworkType = currentNetworkType
self.updatedNetworkType = updatedNetworkType
@ -692,7 +689,7 @@ public final class PresentationCallImpl: PresentationCall {
let updatedConnections = connections
let ongoingContext = OngoingCallContext(account: self.context.account, callSessionManager: self.callSessionManager, callId: id, internalId: self.internalId, proxyServer: proxyServer, initialNetworkType: self.currentNetworkType, updatedNetworkType: self.updatedNetworkType, serializedData: self.serializedData, dataSaving: dataSaving, derivedState: self.derivedState, key: key, isOutgoing: sessionState.isOutgoing, video: self.videoCapturer, connections: updatedConnections, maxLayer: maxLayer, version: version, allowP2P: allowsP2P, enableTCP: self.enableTCP, enableStunMarking: self.enableStunMarking, audioSessionActive: self.audioSessionActive.get(), logName: logName, preferredVideoCodec: self.preferredVideoCodec)
let ongoingContext = OngoingCallContext(account: self.context.account, callSessionManager: self.callSessionManager, callId: id, internalId: self.internalId, proxyServer: proxyServer, initialNetworkType: self.currentNetworkType, updatedNetworkType: self.updatedNetworkType, serializedData: self.serializedData, dataSaving: dataSaving, key: key, isOutgoing: sessionState.isOutgoing, video: self.videoCapturer, connections: updatedConnections, maxLayer: maxLayer, version: version, allowP2P: allowsP2P, enableTCP: self.enableTCP, enableStunMarking: self.enableStunMarking, audioSessionActive: self.audioSessionActive.get(), logName: logName, preferredVideoCodec: self.preferredVideoCodec)
self.ongoingContext = ongoingContext
ongoingContext.setIsMuted(self.isMutedValue)
if let requestedVideoAspect = self.requestedVideoAspect {

View File

@ -287,14 +287,13 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
private func ringingStatesUpdated(_ ringingStates: [(AccountContext, Peer, CallSessionRingingState, Bool, NetworkType)], enableCallKit: Bool) {
if let firstState = ringingStates.first {
if self.currentCall == nil && self.currentGroupCall == nil {
self.currentCallDisposable.set((combineLatest(firstState.0.account.postbox.preferencesView(keys: [PreferencesKeys.voipConfiguration, ApplicationSpecificPreferencesKeys.voipDerivedState, PreferencesKeys.appConfiguration]) |> take(1), accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings, ApplicationSpecificSharedDataKeys.experimentalUISettings]) |> take(1))
self.currentCallDisposable.set((combineLatest(firstState.0.account.postbox.preferencesView(keys: [PreferencesKeys.voipConfiguration, PreferencesKeys.appConfiguration]) |> take(1), accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings, ApplicationSpecificSharedDataKeys.experimentalUISettings]) |> take(1))
|> deliverOnMainQueue).start(next: { [weak self] preferences, sharedData in
guard let strongSelf = self else {
return
}
let configuration = preferences.values[PreferencesKeys.voipConfiguration]?.get(VoipConfiguration.self) ?? .defaultValue
let derivedState = preferences.values[ApplicationSpecificPreferencesKeys.voipDerivedState]?.get(VoipDerivedState.self) ?? .default
let autodownloadSettings = sharedData.entries[SharedDataKeys.autodownloadSettings]?.get(AutodownloadSettings.self) ?? .defaultSettings
let experimentalSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.experimentalUISettings]?.get(ExperimentalUISettings.self) ?? .defaultSettings
let appConfiguration = preferences.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue
@ -306,7 +305,6 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
callKitIntegration: enableCallKit ? callKitIntegrationIfEnabled(strongSelf.callKitIntegration, settings: strongSelf.callSettings) : nil,
serializedData: configuration.serializedData,
dataSaving: effectiveDataSaving(for: strongSelf.callSettings, autodownloadSettings: autodownloadSettings),
derivedState: derivedState,
getDeviceAccessData: strongSelf.getDeviceAccessData,
initialState: nil,
internalId: firstState.2.id,
@ -508,7 +506,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
return (combineLatest(queue: .mainQueue(), request, networkType |> take(1), context.account.postbox.peerView(id: peerId) |> map { peerView -> Bool in
return peerView.peerIsContact
} |> take(1), context.account.postbox.preferencesView(keys: [PreferencesKeys.voipConfiguration, ApplicationSpecificPreferencesKeys.voipDerivedState, PreferencesKeys.appConfiguration]) |> take(1), accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings, ApplicationSpecificSharedDataKeys.experimentalUISettings]) |> take(1), areVideoCallsAvailable)
} |> take(1), context.account.postbox.preferencesView(keys: [PreferencesKeys.voipConfiguration, PreferencesKeys.appConfiguration]) |> take(1), accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings, ApplicationSpecificSharedDataKeys.experimentalUISettings]) |> take(1), areVideoCallsAvailable)
|> deliverOnMainQueue
|> beforeNext { internalId, currentNetworkType, isContact, preferences, sharedData, areVideoCallsAvailable in
if let strongSelf = self, accessEnabled {
@ -517,7 +515,6 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
}
let configuration = preferences.values[PreferencesKeys.voipConfiguration]?.get(VoipConfiguration.self) ?? .defaultValue
let derivedState = preferences.values[ApplicationSpecificPreferencesKeys.voipDerivedState]?.get(VoipDerivedState.self) ?? .default
let autodownloadSettings = sharedData.entries[SharedDataKeys.autodownloadSettings]?.get(AutodownloadSettings.self) ?? .defaultSettings
let appConfiguration = preferences.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue
@ -535,7 +532,6 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
),
serializedData: configuration.serializedData,
dataSaving: effectiveDataSaving(for: strongSelf.callSettings, autodownloadSettings: autodownloadSettings),
derivedState: derivedState,
getDeviceAccessData: strongSelf.getDeviceAccessData,
initialState: nil,
internalId: internalId,

View File

@ -1708,17 +1708,19 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|> distinctUntilChanged
|> runOn(.mainQueue())
} else {
peerAdminIds = strongSelf.account.postbox.transaction { transaction -> [PeerId] in
var result: [PeerId] = []
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedGroupData {
if let participants = cachedData.participants {
for participant in participants.participants {
if case .creator = participant {
result.append(participant.peerId)
} else if case .admin = participant {
result.append(participant.peerId)
}
}
peerAdminIds = strongSelf.accountContext.engine.data.get(
TelegramEngine.EngineData.Item.Peer.LegacyGroupParticipants(id: peerId)
)
|> map { participants -> [EnginePeer.Id] in
guard case let .known(participants) = participants else {
return []
}
var result: [EnginePeer.Id] = []
for participant in participants {
if case .creator = participant {
result.append(participant.peerId)
} else if case .admin = participant {
result.append(participant.peerId)
}
}
return result
@ -1801,17 +1803,6 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
} else if case .invalidJoinAsPeer = error {
let peerId = strongSelf.peerId
let _ = strongSelf.accountContext.engine.calls.clearCachedGroupCallDisplayAsAvailablePeers(peerId: peerId).start()
let _ = (strongSelf.accountContext.account.postbox.transaction { transaction -> Void in
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedChannelData {
return current.withUpdatedCallJoinPeerId(nil)
} else if let current = current as? CachedGroupData {
return current.withUpdatedCallJoinPeerId(nil)
} else {
return current
}
})
}).start()
}
strongSelf.markAsCanBeRemoved()
}))

View File

@ -13,7 +13,7 @@ public struct ContentSettings: Equatable {
}
}
private extension ContentSettings {
extension ContentSettings {
init(appConfiguration: AppConfiguration) {
var reasons: [String] = []
if let data = appConfiguration.data, let reasonsData = data["ignore_restriction_reasons"] as? [String] {

View File

@ -39,7 +39,8 @@ extension PeerStatusSettings {
public func unarchiveAutomaticallyArchivedPeer(account: Account, peerId: PeerId) {
let _ = (account.postbox.transaction { transaction -> Void in
updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: .root)
_internal_updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: .root)
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let currentData = current as? CachedUserData, let currentStatusSettings = currentData.peerStatusSettings {
var statusSettings = currentStatusSettings

View File

@ -258,7 +258,7 @@ func _internal_setCachedAvailableReactions(transaction: Transaction, availableRe
key.setInt64(0, value: 0)
if let entry = CodableEntry(availableReactions) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.availableReactions, key: key), entry: entry, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 10, highWaterItemCount: 10))
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.availableReactions, key: key), entry: entry)
}
}

View File

@ -2,9 +2,6 @@ import Foundation
import Postbox
import SwiftSignalKit
private let cachedSentMediaCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 10000, highWaterItemCount: 20000)
enum CachedSentMediaReferenceKey {
case image(hash: Data)
case file(hash: Data)
@ -39,5 +36,5 @@ func cachedSentMediaReference(postbox: Postbox, key: CachedSentMediaReferenceKey
}
func storeCachedSentMediaReference(transaction: Transaction, key: CachedSentMediaReferenceKey, media: Media) {
//transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSentMediaReferences, key: key.key), entry: media, collectionSpec: cachedSentMediaCollectionSpec)
//transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSentMediaReferences, key: key.key), entry: media)
}

View File

@ -2,14 +2,7 @@ import Foundation
import Postbox
import SwiftSignalKit
public func updatePeerGroupIdInteractively(postbox: Postbox, peerId: PeerId, groupId: PeerGroupId) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: groupId)
}
}
public func updatePeerGroupIdInteractively(transaction: Transaction, peerId: PeerId, groupId: PeerGroupId) {
func _internal_updatePeerGroupIdInteractively(transaction: Transaction, peerId: PeerId, groupId: PeerGroupId) {
let initialInclusion = transaction.getPeerChatListInclusion(peerId)
var updatedInclusion = initialInclusion
switch initialInclusion {

View File

@ -40,7 +40,7 @@ func addRecentlyUsedSticker(transaction: Transaction, fileReference: FileMediaRe
}
}
public func clearRecentlyUsedStickers(transaction: Transaction) {
func _internal_clearRecentlyUsedStickers(transaction: Transaction) {
transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudRecentStickers, items: [])
addSynchronizeRecentlyUsedMediaOperation(transaction: transaction, category: .stickers, operation: .clear)
}

View File

@ -23,7 +23,7 @@ func addSynchronizeSavedGifsOperation(transaction: Transaction, operation: Synch
transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeSavedGifsOperation(content: .sync))
}
public func isGifSaved(transaction: Transaction, mediaId: MediaId) -> Bool {
public func getIsGifSaved(transaction: Transaction, mediaId: MediaId) -> Bool {
if transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, itemId: RecentMediaItemId(mediaId).rawValue) != nil {
return true
}

View File

@ -353,7 +353,7 @@ func _internal_cacheTwoStepPasswordToken(postbox: Postbox, token: TemporaryTwoSt
let key = ValueBoxKey(length: 1)
key.setUInt8(0, value: 0)
if let token = token.flatMap(CodableEntry.init) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedTwoStepToken, key: key), entry: token, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1))
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedTwoStepToken, key: key), entry: token)
} else {
transaction.removeItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedTwoStepToken, key: key))
}

View File

@ -480,6 +480,18 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?,
} else if error.errorDescription == "GROUPCALL_PARTICIPANTS_TOO_MUCH" {
return .fail(.tooManyParticipants)
} else if error.errorDescription == "JOIN_AS_PEER_INVALID" {
let _ = (account.postbox.transaction { transaction -> Void in
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedChannelData {
return current.withUpdatedCallJoinPeerId(nil)
} else if let current = current as? CachedGroupData {
return current.withUpdatedCallJoinPeerId(nil)
} else {
return current
}
})
}).start()
return .fail(.invalidJoinAsPeer)
} else if error.errorDescription == "GROUPCALL_INVALID" {
return account.postbox.transaction { transaction -> Signal<Api.Updates, JoinGroupCallError> in
@ -2381,7 +2393,7 @@ func _internal_cachedGroupCallDisplayAsAvailablePeers(account: Account, peerId:
return account.postbox.transaction { transaction -> [FoundPeer] in
let currentTimestamp = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
if let entry = CodableEntry(CachedDisplayAsPeers(peerIds: peers.map { $0.peer.id }, timestamp: currentTimestamp)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedGroupCallDisplayAsPeers, key: key), entry: entry, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 10, highWaterItemCount: 20))
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedGroupCallDisplayAsPeers, key: key), entry: entry)
}
return peers
}

View File

@ -11,6 +11,7 @@ public enum EngineConfiguration {
public var maxSupergroupMemberCount: Int32
public var maxMessageForwardBatchSize: Int32
public var maxSavedGifCount: Int32
public var maxFavedStickerCount: Int32
public var maxRecentStickerCount: Int32
public var maxMessageEditingInterval: Int32
public var maxMediaCaptionLength: Int32
@ -25,6 +26,7 @@ public enum EngineConfiguration {
maxSupergroupMemberCount: Int32,
maxMessageForwardBatchSize: Int32,
maxSavedGifCount: Int32,
maxFavedStickerCount: Int32,
maxRecentStickerCount: Int32,
maxMessageEditingInterval: Int32,
maxMediaCaptionLength: Int32,
@ -38,6 +40,7 @@ public enum EngineConfiguration {
self.maxSupergroupMemberCount = maxSupergroupMemberCount
self.maxMessageForwardBatchSize = maxMessageForwardBatchSize
self.maxSavedGifCount = maxSavedGifCount
self.maxFavedStickerCount = maxFavedStickerCount
self.maxRecentStickerCount = maxRecentStickerCount
self.maxMessageEditingInterval = maxMessageEditingInterval
self.maxMediaCaptionLength = maxMediaCaptionLength
@ -89,7 +92,9 @@ public enum EngineConfiguration {
}
}
extension EngineConfiguration.Limits {
public typealias EngineContentSettings = ContentSettings
public extension EngineConfiguration.Limits {
init(_ limitsConfiguration: LimitsConfiguration) {
self.init(
maxPinnedChatCount: limitsConfiguration.maxPinnedChatCount,
@ -98,6 +103,7 @@ extension EngineConfiguration.Limits {
maxSupergroupMemberCount: limitsConfiguration.maxSupergroupMemberCount,
maxMessageForwardBatchSize: limitsConfiguration.maxMessageForwardBatchSize,
maxSavedGifCount: limitsConfiguration.maxSavedGifCount,
maxFavedStickerCount: limitsConfiguration.maxFavedStickerCount,
maxRecentStickerCount: limitsConfiguration.maxRecentStickerCount,
maxMessageEditingInterval: limitsConfiguration.maxMessageEditingInterval,
maxMediaCaptionLength: limitsConfiguration.maxMediaCaptionLength,
@ -106,6 +112,24 @@ extension EngineConfiguration.Limits {
maxMessageRevokeIntervalInPrivateChats: limitsConfiguration.maxMessageRevokeIntervalInPrivateChats
)
}
func _asLimits() -> LimitsConfiguration {
return LimitsConfiguration(
maxPinnedChatCount: self.maxPinnedChatCount,
maxArchivedPinnedChatCount: self.maxArchivedPinnedChatCount,
maxGroupMemberCount: self.maxGroupMemberCount,
maxSupergroupMemberCount: self.maxSupergroupMemberCount,
maxMessageForwardBatchSize: self.maxMessageForwardBatchSize,
maxSavedGifCount: self.maxSavedGifCount,
maxRecentStickerCount: self.maxRecentStickerCount,
maxFavedStickerCount: self.maxFavedStickerCount,
maxMessageEditingInterval: self.maxMessageEditingInterval,
maxMediaCaptionLength: self.maxMediaCaptionLength,
canRemoveIncomingMessagesInPrivateChats: self.canRemoveIncomingMessagesInPrivateChats,
maxMessageRevokeInterval: self.maxMessageRevokeInterval,
maxMessageRevokeIntervalInPrivateChats: self.maxMessageRevokeIntervalInPrivateChats
)
}
}
public extension EngineConfiguration.UserLimits {
@ -155,6 +179,27 @@ public extension EngineConfiguration.SearchBots {
public extension TelegramEngine.EngineData.Item {
enum Configuration {
public struct App: TelegramEngineDataItem, PostboxViewDataItem {
public typealias Result = AppConfiguration
public init() {
}
var key: PostboxViewKey {
return .preferences(keys: Set([PreferencesKeys.appConfiguration]))
}
func extract(view: PostboxView) -> Result {
guard let view = view as? PreferencesView else {
preconditionFailure()
}
guard let appConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) else {
return AppConfiguration.defaultValue
}
return appConfiguration
}
}
public struct Limits: TelegramEngineDataItem, PostboxViewDataItem {
public typealias Result = EngineConfiguration.Limits
@ -240,5 +285,49 @@ public extension TelegramEngine.EngineData.Item {
return EngineConfiguration.SearchBots(value)
}
}
public struct ApplicationSpecificPreference: TelegramEngineDataItem, PostboxViewDataItem {
public typealias Result = PreferencesEntry?
private let itemKey: ValueBoxKey
public init(key: ValueBoxKey) {
self.itemKey = key
}
var key: PostboxViewKey {
return .preferences(keys: Set([self.itemKey]))
}
func extract(view: PostboxView) -> Result {
guard let view = view as? PreferencesView else {
preconditionFailure()
}
guard let value = view.values[self.itemKey] else {
return nil
}
return value
}
}
public struct ContentSettings: TelegramEngineDataItem, PostboxViewDataItem {
public typealias Result = EngineContentSettings
public init() {
}
var key: PostboxViewKey {
return .preferences(keys: Set([PreferencesKeys.appConfiguration]))
}
func extract(view: PostboxView) -> Result {
guard let view = view as? PreferencesView else {
preconditionFailure()
}
guard let appConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) else {
return EngineContentSettings(appConfiguration: AppConfiguration.defaultValue)
}
return EngineContentSettings(appConfiguration: appConfiguration)
}
}
}
}

View File

@ -0,0 +1,29 @@
import SwiftSignalKit
import Postbox
public extension TelegramEngine.EngineData.Item {
enum ItemCache {
public struct Item: TelegramEngineDataItem, PostboxViewDataItem {
public typealias Result = CodableEntry?
private let collectionId: Int8
private let id: ValueBoxKey
public init(collectionId: Int8, id: ValueBoxKey) {
self.collectionId = collectionId
self.id = id
}
var key: PostboxViewKey {
return .cachedItem(ItemCacheEntryId(collectionId: collectionId, key: self.id))
}
func extract(view: PostboxView) -> Result {
guard let view = view as? CachedItemView else {
preconditionFailure()
}
return view.value
}
}
}
}

View File

@ -127,6 +127,31 @@ public extension TelegramEngine.EngineData.Item {
return result
}
}
public struct ReadState: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
public typealias Result = CombinedPeerReadState?
fileprivate let id: EnginePeer.Id
public var mapKey: EnginePeer.Id {
return self.id
}
var key: PostboxViewKey {
return .combinedReadState(peerId: self.id)
}
public init(id: EnginePeer.Id) {
self.id = id
}
func extract(view: PostboxView) -> Result {
guard let view = view as? CombinedReadStateView else {
preconditionFailure()
}
return view.state
}
}
public struct PeerUnreadCount: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
public typealias Result = Int
@ -144,7 +169,7 @@ public extension TelegramEngine.EngineData.Item {
self.id = id
}
func extract(view: PostboxView) -> Int {
func extract(view: PostboxView) -> Result {
guard let view = view as? UnreadMessageCountsView else {
preconditionFailure()
}

View File

@ -8,6 +8,81 @@ public enum EnginePeerCachedInfoItem<T> {
case unknown
}
public enum EngineChannelParticipant: Equatable {
case creator(id: EnginePeer.Id, adminInfo: ChannelParticipantAdminInfo?, rank: String?)
case member(id: EnginePeer.Id, invitedAt: Int32, adminInfo: ChannelParticipantAdminInfo?, banInfo: ChannelParticipantBannedInfo?, rank: String?)
public var peerId: EnginePeer.Id {
switch self {
case let .creator(id, _, _):
return id
case let .member(id, _, _, _, _):
return id
}
}
}
public extension EngineChannelParticipant {
init(_ participant: ChannelParticipant) {
switch participant {
case let .creator(id, adminInfo, rank):
self = .creator(id: id, adminInfo: adminInfo, rank: rank)
case let .member(id, invitedAt, adminInfo, banInfo, rank):
self = .member(id: id, invitedAt: invitedAt, adminInfo: adminInfo, banInfo: banInfo, rank: rank)
}
}
func _asParticipant() -> ChannelParticipant {
switch self {
case let .creator(id, adminInfo, rank):
return .creator(id: id, adminInfo: adminInfo, rank: rank)
case let .member(id, invitedAt, adminInfo, banInfo, rank):
return .member(id: id, invitedAt: invitedAt, adminInfo: adminInfo, banInfo: banInfo, rank: rank)
}
}
}
public enum EngineLegacyGroupParticipant: Equatable {
case member(id: EnginePeer.Id, invitedBy: EnginePeer.Id, invitedAt: Int32)
case creator(id: EnginePeer.Id)
case admin(id: EnginePeer.Id, invitedBy: EnginePeer.Id, invitedAt: Int32)
public var peerId: EnginePeer.Id {
switch self {
case let .member(id, _, _):
return id
case let .creator(id):
return id
case let .admin(id, _, _):
return id
}
}
}
public extension EngineLegacyGroupParticipant {
init(_ participant: GroupParticipant) {
switch participant {
case let .member(id, invitedBy, invitedAt):
self = .member(id: id, invitedBy: invitedBy, invitedAt: invitedAt)
case let .creator(id):
self = .creator(id: id)
case let .admin(id, invitedBy, invitedAt):
self = .admin(id: id, invitedBy: invitedBy, invitedAt: invitedAt)
}
}
func _asParticipant() -> GroupParticipant {
switch self {
case let .member(id, invitedBy, invitedAt):
return .member(id: id, invitedBy: invitedBy, invitedAt: invitedAt)
case let .creator(id):
return .creator(id: id)
case let .admin(id, invitedBy, invitedAt):
return .admin(id: id, invitedBy: invitedBy, invitedAt: invitedAt)
}
}
}
public extension TelegramEngine.EngineData.Item {
enum NotificationSettings {
public struct Global: TelegramEngineDataItem, PostboxViewDataItem {
@ -675,5 +750,37 @@ public extension TelegramEngine.EngineData.Item {
}
}
}
public struct LegacyGroupParticipants: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
public typealias Result = EnginePeerCachedInfoItem<[EngineLegacyGroupParticipant]>
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 .cachedPeerData(peerId: self.id)
}
func extract(view: PostboxView) -> Result {
guard let view = view as? CachedPeerDataView else {
preconditionFailure()
}
if let cachedData = view.cachedPeerData as? CachedGroupData {
if let participants = cachedData.participants {
return .known(participants.participants.map(EngineLegacyGroupParticipant.init))
} else {
return .unknown
}
} else {
return .unknown
}
}
}
}
}

View File

@ -0,0 +1,29 @@
import Foundation
import SwiftSignalKit
import Postbox
public extension TelegramEngine {
final class ItemCache {
private let account: Account
init(account: Account) {
self.account = account
}
public func put<T: Codable>(collectionId: Int8, id: ValueBoxKey, item: T) -> Signal<Never, NoError> {
return self.account.postbox.transaction { transaction -> Void in
if let entry = CodableEntry(item) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: collectionId, key: id), entry: entry)
}
}
|> ignoreValues
}
public func remove(collectionId: Int8, id: ValueBoxKey) -> Signal<Never, NoError> {
return self.account.postbox.transaction { transaction -> Void in
transaction.removeItemCacheEntry(id: ItemCacheEntryId(collectionId: collectionId, key: id))
}
|> ignoreValues
}
}
}

View File

@ -57,7 +57,7 @@ func _internal_availableLocalizations(postbox: Postbox, network: Network, allowC
let infos: [LocalizationInfo] = languages.map(LocalizationInfo.init(apiLanguage:))
return postbox.transaction { transaction -> [LocalizationInfo] in
if let entry = CodableEntry(CachedLocalizationInfos(list: infos)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAvailableLocalizations, key: ValueBoxKey(length: 0)), entry: entry, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1))
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAvailableLocalizations, key: ValueBoxKey(length: 0)), entry: entry)
}
return infos
}

View File

@ -304,8 +304,6 @@ private class AdMessagesHistoryContextImpl {
}, forKey: "messages")
}
private static let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 5, highWaterItemCount: 10)
public static func getCached(postbox: Postbox, peerId: PeerId) -> Signal<CachedState?, NoError> {
return postbox.transaction { transaction -> CachedState? in
let key = ValueBoxKey(length: 8)
@ -323,7 +321,7 @@ private class AdMessagesHistoryContextImpl {
key.setInt64(0, value: peerId.toInt64())
let id = ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAdMessageStates, key: key)
if let state = state, let entry = CodableEntry(state) {
transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec)
transaction.putItemCacheEntry(id: id, entry: entry)
} else {
transaction.removeItemCacheEntry(id: id)
}

View File

@ -176,7 +176,7 @@ public func clearPeerUnseenReactionsInteractively(account: Account, peerId: Peer
|> ignoreValues
}
public func markAllChatsAsReadInteractively(transaction: Transaction, viewTracker: AccountViewTracker, groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate?) {
func _internal_markAllChatsAsReadInteractively(transaction: Transaction, viewTracker: AccountViewTracker, groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate?) {
for peerId in transaction.getUnreadChatListPeerIds(groupId: groupId, filterPredicate: filterPredicate) {
togglePeerUnreadMarkInteractively(transaction: transaction, viewTracker: viewTracker, peerId: peerId, setToValue: false)
}

View File

@ -222,7 +222,7 @@ private func setCachedAttachMenuBots(transaction: Transaction, attachMenuBots: A
let entryId = ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.attachMenuBots, key: key)
if let entry = CodableEntry(attachMenuBots) {
transaction.putItemCacheEntry(id: entryId, entry: entry, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 10, highWaterItemCount: 10))
transaction.putItemCacheEntry(id: entryId, entry: entry)
} else {
transaction.removeItemCacheEntry(id: entryId)
}

View File

@ -149,8 +149,6 @@ func _internal_requestClosePoll(postbox: Postbox, network: Network, stateManager
}
}
private let cachedPollResultsCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 20, highWaterItemCount: 40)
final class CachedPollOptionResult: Codable {
let peerIds: [PeerId]
let count: Int32
@ -299,7 +297,7 @@ private final class PollResultsOptionContext {
}
if populateCache {
if let entry = CodableEntry(CachedPollOptionResult(peerIds: resultPeers.map { $0.peerId }, count: count)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPollResults, key: CachedPollOptionResult.key(pollId: pollId, optionOpaqueIdentifier: opaqueIdentifier)), entry: entry, collectionSpec: cachedPollResultsCollectionSpec)
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPollResults, key: CachedPollOptionResult.key(pollId: pollId, optionOpaqueIdentifier: opaqueIdentifier)), entry: entry)
}
}
return (resultPeers, Int(count), nextOffset)

View File

@ -33,8 +33,6 @@ public final class CachedChatContextResult: Codable {
}
}
private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 40, highWaterItemCount: 60)
private struct RequestData: Codable {
let version: String
let botId: PeerId
@ -146,7 +144,7 @@ func _internal_requestChatContextResults(account: Account, botId: PeerId, peerId
if let keyData = try? JSONEncoder().encode(requestData) {
let key = ValueBoxKey(MemoryBuffer(data: keyData))
if let entry = CodableEntry(CachedChatContextResult(data: resultData, timestamp: Int32(Date().timeIntervalSince1970))) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedContextResults, key: key), entry: entry, collectionSpec: collectionSpec)
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedContextResults, key: key), entry: entry)
}
}
}

View File

@ -62,7 +62,7 @@ func _internal_cachedPeerSendAsAvailablePeers(account: Account, peerId: PeerId)
return account.postbox.transaction { transaction -> [FoundPeer] in
let currentTimestamp = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
if let entry = CodableEntry(CachedSendAsPeers(peerIds: peers.map { $0.peer.id }, timestamp: currentTimestamp)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSendAsPeers, key: key), entry: entry, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 10, highWaterItemCount: 20))
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSendAsPeers, key: key), entry: entry)
}
return peers
}

View File

@ -51,12 +51,15 @@ public extension TelegramEngine {
return _internal_searchMessageIdByTimestamp(account: self.account, peerId: peerId, threadId: threadId, timestamp: timestamp)
}
public func deleteMessages(transaction: Transaction, ids: [MessageId], deleteMedia: Bool = true, manualAddMessageThreadStatsDifference: ((MessageId, Int, Int) -> Void)? = nil) {
return _internal_deleteMessages(transaction: transaction, mediaBox: self.account.postbox.mediaBox, ids: ids, deleteMedia: deleteMedia, manualAddMessageThreadStatsDifference: manualAddMessageThreadStatsDifference)
public func deleteMessages(transaction: Transaction, ids: [MessageId]) {
return _internal_deleteMessages(transaction: transaction, mediaBox: self.account.postbox.mediaBox, ids: ids, deleteMedia: true, manualAddMessageThreadStatsDifference: nil)
}
public func deleteAllMessagesWithAuthor(transaction: Transaction, peerId: PeerId, authorId: PeerId, namespace: MessageId.Namespace) {
return _internal_deleteAllMessagesWithAuthor(transaction: transaction, mediaBox: self.account.postbox.mediaBox, peerId: peerId, authorId: authorId, namespace: namespace)
public func deleteAllMessagesWithAuthor(peerId: PeerId, authorId: PeerId, namespace: MessageId.Namespace) -> Signal<Never, NoError> {
return self.account.postbox.transaction { transaction -> Void in
_internal_deleteAllMessagesWithAuthor(transaction: transaction, mediaBox: self.account.postbox.mediaBox, peerId: peerId, authorId: authorId, namespace: namespace)
}
|> ignoreValues
}
public func deleteAllMessagesWithForwardAuthor(transaction: Transaction, peerId: PeerId, forwardAuthorId: PeerId, namespace: MessageId.Namespace) {
@ -378,5 +381,27 @@ public extension TelegramEngine {
return transaction.getMessageFailedGroup(id)?.map(EngineMessage.init) ?? []
}
}
public func unreadChatListPeerIds(groupId: EngineChatList.Group, filterPredicate: ChatListFilterPredicate?) -> Signal<[EnginePeer.Id], NoError> {
return self.account.postbox.transaction { transaction -> [EnginePeer.Id] in
return transaction.getUnreadChatListPeerIds(groupId: groupId._asGroup(), filterPredicate: filterPredicate)
}
}
public func markAllChatsAsReadInteractively(items: [(groupId: EngineChatList.Group, filterPredicate: ChatListFilterPredicate?)]) -> Signal<Never, NoError> {
let account = self.account
return self.account.postbox.transaction { transaction -> Void in
for (groupId, filterPredicate) in items {
_internal_markAllChatsAsReadInteractively(transaction: transaction, viewTracker: account.viewTracker, groupId: groupId._asGroup(), filterPredicate: filterPredicate)
}
}
|> ignoreValues
}
public func getRelativeUnreadChatListIndex(filtered: Bool, position: EngineChatList.RelativePosition, groupId: EngineChatList.Group) -> Signal<EngineChatList.Item.Index?, NoError> {
return self.account.postbox.transaction { transaction -> EngineChatList.Item.Index? in
return transaction.getRelativeUnreadChatListIndex(filtered: filtered, position: position._asPosition(), groupId: groupId._asGroup())
}
}
}
}

View File

@ -10,6 +10,27 @@ public extension TelegramEngine {
self.account = account
}
public func addOrMoveToFirstPosition<T: Codable>(collectionId: Int32, id: MemoryBuffer, item: T, removeTailIfCountExceeds: Int?) -> Signal<Never, NoError> {
return self.account.postbox.transaction { transaction -> Void in
if let entry = CodableEntry(item) {
transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: collectionId, item: OrderedItemListEntry(id: id, contents: entry), removeTailIfCountExceeds: removeTailIfCountExceeds)
}
}
|> ignoreValues
}
public func clear(collectionId: Int32) -> Signal<Never, NoError> {
return self.account.postbox.transaction { transaction -> Void in
transaction.replaceOrderedItemListItems(collectionId: collectionId, items: [])
}
|> ignoreValues
}
public func removeItem(collectionId: Int32, id: MemoryBuffer) -> Signal<Never, NoError> {
return self.account.postbox.transaction { transaction -> Void in
transaction.removeOrderedItemListItem(collectionId: collectionId, itemId: id)
}
|> ignoreValues
}
}
}

View File

@ -317,8 +317,6 @@ func _internal_deleteAllRevokedPeerExportedInvitations(account: Account, peerId:
|> switchToLatest
}
private let cachedPeerExportedInvitationsCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 10, highWaterItemCount: 20)
public struct PeerExportedInvitationsState: Equatable {
public var invitations: [ExportedInvitation]
public var isLoadingMore: Bool
@ -500,7 +498,7 @@ private final class PeerExportedInvitationsContextImpl {
let invitations: [ExportedInvitation] = invites.compactMap { ExportedInvitation(apiExportedInvite: $0) }
if populateCache {
if let entry = CodableEntry(CachedPeerExportedInvitations(invitations: invitations, canLoadMore: count >= 50, count: count)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerExportedInvitations, key: CachedPeerExportedInvitations.key(peerId: peerId, revoked: revoked)), entry: entry, collectionSpec: cachedPeerExportedInvitationsCollectionSpec)
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerExportedInvitations, key: CachedPeerExportedInvitations.key(peerId: peerId, revoked: revoked)), entry: entry)
}
}
return (invitations, count)
@ -590,7 +588,7 @@ private final class PeerExportedInvitationsContextImpl {
let count = self.count
self.updateDisposable.set(self.account.postbox.transaction({ transaction in
if let entry = CodableEntry(CachedPeerExportedInvitations(invitations: invitations, canLoadMore: canLoadMore, count: count)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerExportedInvitations, key: CachedPeerExportedInvitations.key(peerId: peerId, revoked: revoked)), entry: entry, collectionSpec: cachedPeerExportedInvitationsCollectionSpec)
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerExportedInvitations, key: CachedPeerExportedInvitations.key(peerId: peerId, revoked: revoked)), entry: entry)
}
}).start())
}
@ -660,10 +658,6 @@ public final class PeerExportedInvitationsContext {
}
}
private let cachedPeerInvitationImportersCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 10, highWaterItemCount: 20)
public struct PeerInvitationImportersState: Equatable {
public struct Importer: Equatable {
public var peer: RenderedPeer
@ -977,7 +971,7 @@ private final class PeerInvitationImportersContextImpl {
}
if populateCache && query == nil {
if let entry = CodableEntry(CachedPeerInvitationImporters(importers: resultImporters, count: count)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerInvitationImporters.key(peerId: peerId, link: link ?? "requests", requested: self.requested)), entry: entry, collectionSpec: cachedPeerInvitationImportersCollectionSpec)
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerInvitationImporters.key(peerId: peerId, link: link ?? "requests", requested: self.requested)), entry: entry)
}
}
return (resultImporters, count)
@ -1073,7 +1067,7 @@ private final class PeerInvitationImportersContextImpl {
let link = self.link
self.updateDisposables.add(self.account.postbox.transaction({ transaction in
if let entry = CodableEntry(CachedPeerInvitationImporters(importers: resultImporters, count: count)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerInvitationImporters.key(peerId: peerId, link: link ?? "requests", requested: self.requested)), entry: entry, collectionSpec: cachedPeerInvitationImportersCollectionSpec)
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerInvitationImporters.key(peerId: peerId, link: link ?? "requests", requested: self.requested)), entry: entry)
}
}).start())
}

View File

@ -135,7 +135,7 @@ public func _internal_cachedNotificationSoundList(transaction: Transaction) -> N
func _internal_setCachedNotificationSoundList(transaction: Transaction, notificationSoundList: NotificationSoundList) {
if let entry = CodableEntry(notificationSoundList) {
transaction.putItemCacheEntry(id: _internal_cachedNotificationSoundListCacheKey(), entry: entry, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 10, highWaterItemCount: 10))
transaction.putItemCacheEntry(id: _internal_cachedNotificationSoundListCacheKey(), entry: entry)
}
}

View File

@ -3,14 +3,11 @@ import Postbox
import TelegramApi
import SwiftSignalKit
public enum RecentPeers {
case peers([Peer])
case disabled
}
private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1)
private func cachedRecentPeersEntryId() -> ItemCacheEntryId {
return ItemCacheEntryId(collectionId: 101, key: CachedRecentPeers.cacheKey())
}
@ -82,13 +79,13 @@ func _internal_managedUpdatedRecentPeers(accountPeerId: PeerId, postbox: Postbox
updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences)
if let entry = CodableEntry(CachedRecentPeers(enabled: true, ids: peers.map { $0.id })) {
transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: entry, collectionSpec: collectionSpec)
transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: entry)
}
case .topPeersNotModified:
break
case .topPeersDisabled:
if let entry = CodableEntry(CachedRecentPeers(enabled: false, ids: [])) {
transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: entry, collectionSpec: collectionSpec)
transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: entry)
}
}
}
@ -109,7 +106,7 @@ func _internal_removeRecentPeer(account: Account, peerId: PeerId) -> Signal<Void
var updatedIds = entry.ids
updatedIds.remove(at: index)
if let entry = CodableEntry(CachedRecentPeers(enabled: entry.enabled, ids: updatedIds)) {
transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: entry, collectionSpec: collectionSpec)
transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: entry)
}
}
if let peer = transaction.getPeer(peerId), let apiPeer = apiInputPeer(peer) {
@ -145,12 +142,12 @@ func _internal_updateRecentPeersEnabled(postbox: Postbox, network: Network, enab
return postbox.transaction { transaction -> Void in
if !enabled {
if let entry = CodableEntry(CachedRecentPeers(enabled: false, ids: [])) {
transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: entry, collectionSpec: collectionSpec)
transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: entry)
}
} else {
let entry = transaction.retrieveItemCacheEntry(id: cachedRecentPeersEntryId())?.get(CachedRecentPeers.self)
if let codableEntry = CodableEntry(CachedRecentPeers(enabled: true, ids: entry?.ids ?? [])) {
transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: codableEntry, collectionSpec: collectionSpec)
transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: codableEntry)
}
}
}

View File

@ -3,9 +3,6 @@ import Postbox
import TelegramApi
import SwiftSignalKit
private let resolvedByNamePeersCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 150, highWaterItemCount: 200)
public enum ResolvePeerByNameOptionCached {
case none
case cached
@ -65,7 +62,7 @@ func _internal_resolvePeerByName(account: Account, name: String, ageLimit: Int32
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
if let entry = CodableEntry(CachedResolvedByNamePeer(peerId: peerId, timestamp: timestamp)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.resolvedByNamePeers, key: CachedResolvedByNamePeer.key(name: normalizedName)), entry: entry, collectionSpec: resolvedByNamePeersCollectionSpec)
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.resolvedByNamePeers, key: CachedResolvedByNamePeer.key(name: normalizedName)), entry: entry)
}
return peerId
}
@ -78,8 +75,6 @@ func _internal_resolvePeerByName(account: Account, name: String, ageLimit: Int32
}
}
private let resolvedByPhonePeersCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 150, highWaterItemCount: 200)
func _internal_resolvePeerByPhone(account: Account, phone: String, ageLimit: Int32 = 2 * 60 * 60 * 24) -> Signal<PeerId?, NoError> {
var normalizedPhone = phone
if normalizedPhone.hasPrefix("+") {
@ -128,7 +123,7 @@ func _internal_resolvePeerByPhone(account: Account, phone: String, ageLimit: Int
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
if let entry = CodableEntry(CachedResolvedByPhonePeer(peerId: peerId, timestamp: timestamp)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.resolvedByPhonePeers, key: CachedResolvedByPhonePeer.key(name: normalizedPhone)), entry: entry, collectionSpec: resolvedByNamePeersCollectionSpec)
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.resolvedByPhonePeers, key: CachedResolvedByPhonePeer.key(name: normalizedPhone)), entry: entry)
}
return peerId
}

View File

@ -756,6 +756,22 @@ public extension TelegramEngine {
}
}
}
public func updatePeersGroupIdInteractively(peerIds: [EnginePeer.Id], groupId: EngineChatList.Group) -> Signal<Never, NoError> {
return self.account.postbox.transaction { transaction -> Void in
for peerId in peerIds {
_internal_updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: groupId._asGroup())
}
}
|> ignoreValues
}
public func resetAllPeerNotificationSettings() -> Signal<Never, NoError> {
return self.account.postbox.transaction { transaction -> Void in
transaction.resetAllPeerNotificationSettings(TelegramPeerNotificationSettings.defaultSettings)
}
|> ignoreValues
}
}
}

View File

@ -36,7 +36,7 @@ public func secureIdConfiguration(postbox: Postbox, network: Network) -> Signal<
}
return postbox.transaction { transaction -> SecureIdConfiguration in
if let entry = CodableEntry(parsed) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSecureIdConfiguration, key: ValueBoxKey(length: 0)), entry: entry, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1))
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSecureIdConfiguration, key: ValueBoxKey(length: 0)), entry: entry)
}
return parsed.value
}

View File

@ -3,9 +3,6 @@ import Postbox
import SwiftSignalKit
import MurMurHash32
private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 100, highWaterItemCount: 200)
public enum CachedStickerPackResult {
case none
case fetching
@ -14,10 +11,10 @@ public enum CachedStickerPackResult {
func cacheStickerPack(transaction: Transaction, info: StickerPackCollectionInfo, items: [StickerPackItem], reference: StickerPackReference? = nil) {
if let entry = CodableEntry(CachedStickerPack(info: info, items: items, hash: info.hash)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(info.id)), entry: entry, collectionSpec: collectionSpec)
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(info.id)), entry: entry)
}
if let entry = CodableEntry(CachedStickerPack(info: info, items: items, hash: info.hash)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(shortName: info.shortName.lowercased())), entry: entry, collectionSpec: collectionSpec)
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(shortName: info.shortName.lowercased())), entry: entry)
}
if let reference = reference {
@ -38,7 +35,7 @@ func cacheStickerPack(transaction: Transaction, info: StickerPackCollectionInfo,
}
if let namespace = namespace, let id = id {
if let entry = CodableEntry(CachedStickerPack(info: info, items: items, hash: info.hash)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))), entry: entry, collectionSpec: collectionSpec)
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))), entry: entry)
}
}
}

View File

@ -43,8 +43,6 @@ public final class FoundStickerItem: Equatable {
}
}
private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 100, highWaterItemCount: 200)
public struct SearchStickersScope: OptionSet {
public var rawValue: Int32
@ -244,7 +242,7 @@ func _internal_searchStickers(account: Account, query: String, scope: SearchStic
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
if let entry = CodableEntry(CachedStickerQueryResult(items: files, hash: hash, timestamp: currentTime)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query)), entry: entry, collectionSpec: collectionSpec)
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query)), entry: entry)
}
return result

View File

@ -118,5 +118,18 @@ public extension TelegramEngine {
return getIsStickerSaved(transaction: transaction, fileId: id)
}
}
public func isGifSaved(id: EngineMedia.Id) -> Signal<Bool, NoError> {
return self.account.postbox.transaction { transaction -> Bool in
return getIsGifSaved(transaction: transaction, mediaId: id)
}
}
public func clearRecentlyUsedStickers() -> Signal<Never, NoError> {
return self.account.postbox.transaction { transaction -> Void in
_internal_clearRecentlyUsedStickers(transaction: transaction)
}
|> ignoreValues
}
}
}

View File

@ -79,6 +79,10 @@ public final class TelegramEngine {
public lazy var orderedLists: OrderedLists = {
return OrderedLists(account: self.account)
}()
public lazy var itemCache: ItemCache = {
return ItemCache(account: self.account)
}()
}
public final class TelegramEngineUnauthorized {

View File

@ -55,7 +55,7 @@ public func telegramThemes(postbox: Postbox, network: Network, accountManager: A
}
transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudThemes, items: entries)
if let entry = CodableEntry(CachedThemesConfiguration(hash: hash)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedThemesConfiguration, key: ValueBoxKey(length: 0)), entry: entry, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1))
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedThemesConfiguration, key: ValueBoxKey(length: 0)), entry: entry)
}
return items
}

View File

@ -49,7 +49,7 @@ public func telegramWallpapers(postbox: Postbox, network: Network, forceUpdate:
}
transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudWallpapers, items: entries)
if let entry = CodableEntry(CachedWallpapersConfiguration(hash: hash)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedWallpapersConfiguration, key: ValueBoxKey(length: 0)), entry: entry, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1))
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedWallpapersConfiguration, key: ValueBoxKey(length: 0)), entry: entry)
}
return items
}

View File

@ -893,7 +893,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let timestamp = timestamp {
storedState = MediaPlaybackStoredState(timestamp: timestamp, playbackRate: AudioPlaybackRate(playbackRate))
}
let _ = updateMediaPlaybackStoredStateInteractively(postbox: strongSelf.context.account.postbox, messageId: messageId, state: storedState).start()
let _ = updateMediaPlaybackStoredStateInteractively(engine: strongSelf.context.engine, messageId: messageId, state: storedState).start()
}, editMedia: { [weak self] messageId, snapshots, transitionCompletion in
guard let strongSelf = self else {
return
@ -6517,7 +6517,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}, deleteSelectedMessages: { [weak self] in
if let strongSelf = self {
if let messageIds = strongSelf.presentationInterfaceState.interfaceState.selectionState?.selectedIds, !messageIds.isEmpty {
strongSelf.messageContextDisposable.set((strongSelf.context.sharedContext.chatAvailableMessageActions(postbox: strongSelf.context.account.postbox, accountPeerId: strongSelf.context.account.peerId, messageIds: messageIds)
strongSelf.messageContextDisposable.set((strongSelf.context.sharedContext.chatAvailableMessageActions(engine: strongSelf.context.engine, accountPeerId: strongSelf.context.account.peerId, messageIds: messageIds)
|> deliverOnMainQueue).start(next: { actions in
if let strongSelf = self, !actions.options.isEmpty {
if let banAuthor = actions.banAuthor {
@ -6633,7 +6633,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}, deleteMessages: { [weak self] messages, contextController, completion in
if let strongSelf = self, !messages.isEmpty {
let messageIds = Set(messages.map { $0.id })
strongSelf.messageContextDisposable.set((strongSelf.context.sharedContext.chatAvailableMessageActions(postbox: strongSelf.context.account.postbox, accountPeerId: strongSelf.context.account.peerId, messageIds: messageIds)
strongSelf.messageContextDisposable.set((strongSelf.context.sharedContext.chatAvailableMessageActions(engine: strongSelf.context.engine, accountPeerId: strongSelf.context.account.peerId, messageIds: messageIds)
|> deliverOnMainQueue).start(next: { actions in
if let strongSelf = self, !actions.options.isEmpty {
if let banAuthor = actions.banAuthor {
@ -7968,20 +7968,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
if let stickerFile = stickerFile {
let context = strongSelf.context
let _ = (context.account.postbox.transaction { transaction -> Signal<(SavedStickerResult, Bool), AddSavedStickerError> in
let isSaved: Bool
if getIsStickerSaved(transaction: transaction, fileId: stickerFile.fileId) {
isSaved = true
} else {
isSaved = false
}
let _ = (context.engine.stickers.isStickerSaved(id: stickerFile.fileId)
|> castError(AddSavedStickerError.self)
|> mapToSignal { isSaved -> Signal<(SavedStickerResult, Bool), AddSavedStickerError> in
return context.engine.stickers.toggleStickerSaved(file: stickerFile, saved: !isSaved)
|> map { result -> (SavedStickerResult, Bool) in
return (result, !isSaved)
}
}
|> castError(AddSavedStickerError.self)
|> switchToLatest
|> deliverOnMainQueue).start(next: { [weak self] result, added in
if let strongSelf = self {
switch result {
@ -8185,9 +8179,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
})
})
let _ = (strongSelf.context.account.postbox.transaction { transaction -> Void in
updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: .root)
}
let _ = (strongSelf.context.engine.peers.updatePeersGroupIdInteractively(peerIds: [peerId], groupId: .root)
|> deliverOnMainQueue).start()
}, openLinkEditing: { [weak self] in
if let strongSelf = self {
@ -15068,9 +15060,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState { $0.withoutSelectionState() } })
if actions.contains(3) {
let context = strongSelf.context
let _ = context.account.postbox.transaction({ transaction -> Void in
context.engine.messages.deleteAllMessagesWithAuthor(transaction: transaction, peerId: peerId, authorId: author.id, namespace: Namespaces.Message.Cloud)
}).start()
let _ = context.engine.messages.deleteAllMessagesWithAuthor(peerId: peerId, authorId: author.id, namespace: Namespaces.Message.Cloud).start()
let _ = strongSelf.context.engine.messages.clearAuthorHistory(peerId: peerId, memberId: author.id).start()
} else if actions.contains(0) {
let _ = strongSelf.context.engine.messages.deleteMessagesInteractively(messageIds: Array(messageIds), type: .forEveryone).start()

View File

@ -1583,129 +1583,6 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
self.loadStateUpdated = f
}
/*private func updateHistoryScrollingArea(transition: ContainedViewLayoutTransition) {
guard let historyScrollingArea = self.historyScrollingArea else {
return
}
guard let transactionState = self.opaqueTransactionState as? ChatHistoryTransactionOpaqueState else {
return
}
let historyView = transactionState.historyView
var updatedScrollingState = self.scrollingState
if var scrollingState = updatedScrollingState {
let convertedIndex = historyView.filteredEntries.count - scrollingState.topItem.index - 1
if convertedIndex < 0 || convertedIndex >= historyView.filteredEntries.count {
return
}
let firstItem = historyView.filteredEntries[convertedIndex]
var location: MessageHistoryEntryLocation?
switch firstItem {
case let .MessageEntry(_, _, _, locationValue, _, _):
location = locationValue
case let .MessageGroupEntry(_, group, _):
if let locationValue = group.last?.4 {
location = locationValue
}
default:
break
}
if let location = location {
let locationDelta = (location.count - location.index - 1) - scrollingState.topItem.index
scrollingState.topItem.index += locationDelta
scrollingState.bottomItem.index += locationDelta
scrollingState.itemCount = max(scrollingState.itemCount, location.count)
}
updatedScrollingState = scrollingState
}
historyScrollingArea.update(
containerSize: self.bounds.size,
containerInsets: UIEdgeInsets(top: self.scrollIndicatorInsets.top, left: 0.0, bottom: self.scrollIndicatorInsets.bottom, right: 0.0),
scrollingState: updatedScrollingState,
isScrolling: self.isDragging || self.isDeceleratingAfterTracking,
theme: self.currentPresentationData.theme.theme,
transition: transition
)
}
private func navigateToAbsolutePosition(position: Float) {
guard let transactionState = self.opaqueTransactionState as? ChatHistoryTransactionOpaqueState else {
return
}
let historyView = transactionState.historyView
let convertedIndex = 0
if convertedIndex < 0 || convertedIndex >= historyView.filteredEntries.count {
self.historyScrollingArea?.resetNavigatingToPosition()
return
}
let firstItem = historyView.filteredEntries[convertedIndex]
var location: MessageHistoryEntryLocation?
switch firstItem {
case let .MessageEntry(_, _, _, locationValue, _, _):
location = locationValue
case let .MessageGroupEntry(_, group, _):
if let locationValue = group.last?.4 {
location = locationValue
}
default:
break
}
if let location = location {
var absoluteIndex = Int(Float(location.count) * position)
if absoluteIndex >= location.count {
absoluteIndex = location.count - 1
}
if absoluteIndex < 0 {
absoluteIndex = 0
}
if case let .peer(peerId) = self.chatLocation {
let _ = (self.context.account.postbox.transaction { transaction -> MessageIndex? in
return transaction.findMessageAtAbsoluteIndex(peerId: peerId, namespace: Namespaces.Message.Cloud, index: absoluteIndex)
}
|> deliverOnMainQueue).start(next: { [weak self] index in
guard let strongSelf = self else {
return
}
if let index = index {
let content: ChatHistoryLocation = .Scroll(index: .message(index), anchorIndex: .message(index), sourceIndex: .message(index), scrollPosition: .top(0.0), animated: false, highlight: false)
strongSelf.scrollNavigationDisposable.set((preloadedChatHistoryViewForLocation(ChatHistoryLocationInput(content: content, id: 0), context: strongSelf.context, chatLocation: strongSelf.chatLocation, subject: strongSelf.subject, chatLocationContextHolder: strongSelf.chatLocationContextHolder, fixedCombinedReadStates: nil, tagMask: nil, additionalData: [])
|> map { historyView -> Bool in
switch historyView {
case .Loading:
return false
case .HistoryView:
return true
}
}
|> filter { $0 }
|> take(1)
|> deliverOnMainQueue).start(next: { _ in
guard let strongSelf = self else {
return
}
strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: content, id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0)
Queue.mainQueue().after(0.5, {
self?.historyScrollingArea?.resetNavigatingToPosition()
})
}))
} else {
strongSelf.historyScrollingArea?.resetNavigatingToPosition()
}
})
}
} else {
self.historyScrollingArea?.resetNavigatingToPosition()
}
}*/
private func maybeUpdateOverscrollAction(offset: CGFloat?) {
if self.freezeOverscrollControl {
return
@ -2304,7 +2181,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
if historyView.originalView.laterId == nil {
for entry in historyView.filteredEntries.reversed() {
if case let .MessageEntry(message, _, _, _, _, _) = entry {
if canEditMessage(context: context, limitsConfiguration: context.currentLimitsConfiguration.with { $0 }, message: message) {
if canEditMessage(context: context, limitsConfiguration: context.currentLimitsConfiguration.with { EngineConfiguration.Limits($0) }, message: message) {
return message
}
}

View File

@ -42,11 +42,11 @@ private struct MessageContextMenuData {
let messageActions: ChatAvailableMessageActions
}
func canEditMessage(context: AccountContext, limitsConfiguration: LimitsConfiguration, message: Message) -> Bool {
func canEditMessage(context: AccountContext, limitsConfiguration: EngineConfiguration.Limits, message: Message) -> Bool {
return canEditMessage(accountPeerId: context.account.peerId, limitsConfiguration: limitsConfiguration, message: message)
}
private func canEditMessage(accountPeerId: PeerId, limitsConfiguration: LimitsConfiguration, message: Message, reschedule: Bool = false) -> Bool {
private func canEditMessage(accountPeerId: PeerId, limitsConfiguration: EngineConfiguration.Limits, message: Message, reschedule: Bool = false) -> Bool {
var hasEditRights = false
var unlimitedInterval = reschedule
@ -153,7 +153,7 @@ private func canEditMessage(accountPeerId: PeerId, limitsConfiguration: LimitsCo
}
if !hasUneditableAttributes || reschedule {
if canPerformEditingActions(limits: limitsConfiguration, accountPeerId: accountPeerId, message: message, unlimitedInterval: unlimitedInterval) {
if canPerformEditingActions(limits: limitsConfiguration._asLimits(), accountPeerId: accountPeerId, message: message, unlimitedInterval: unlimitedInterval) {
return true
}
}
@ -161,7 +161,7 @@ private func canEditMessage(accountPeerId: PeerId, limitsConfiguration: LimitsCo
return false
}
private func canViewReadStats(message: Message, cachedData: CachedPeerData?, isMessageRead: Bool, appConfig: AppConfiguration) -> Bool {
private func canViewReadStats(message: Message, participantCount: Int?, isMessageRead: Bool, appConfig: AppConfiguration) -> Bool {
guard let peer = message.peers[message.id.peerId] else {
return false
}
@ -210,12 +210,8 @@ private func canViewReadStats(message: Message, cachedData: CachedPeerData?, isM
case let channel as TelegramChannel:
if case .broadcast = channel.info {
return false
} else if let cachedData = cachedData as? CachedChannelData {
if let memberCount = cachedData.participantsSummary.memberCount {
if Int(memberCount) > maxParticipantCount {
return false
}
} else {
} else if let participantCount = participantCount {
if participantCount > maxParticipantCount {
return false
}
} else {
@ -555,36 +551,47 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|> map(Optional.init)
}
let loadLimits = context.account.postbox.transaction { transaction -> (LimitsConfiguration, AppConfiguration) in
let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration)?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue
let appConfig = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue
return (limitsConfiguration, appConfig)
let loadLimits = context.engine.data.get(
TelegramEngine.EngineData.Item.Configuration.Limits(),
TelegramEngine.EngineData.Item.Configuration.App()
)
struct InfoSummaryData {
var linkedDiscusionPeerId: EnginePeerCachedInfoItem<EnginePeer.Id?>
var canViewStats: Bool
var participantCount: Int?
}
let cachedData = context.account.postbox.transaction { transaction -> CachedPeerData? in
return transaction.getPeerCachedData(peerId: messages[0].id.peerId)
let infoSummaryData = context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.LinkedDiscussionPeerId(id: messages[0].id.peerId),
TelegramEngine.EngineData.Item.Peer.CanViewStats(id: messages[0].id.peerId),
TelegramEngine.EngineData.Item.Peer.ParticipantCount(id: messages[0].id.peerId)
)
|> map { linkedDiscusionPeerId, canViewStats, participantCount -> InfoSummaryData in
return InfoSummaryData(
linkedDiscusionPeerId: linkedDiscusionPeerId,
canViewStats: canViewStats,
participantCount: participantCount
)
}
//let readState = context.engine.data.get(TelegramEngine.EngineData.Item.Messages.PeerUnreadCount)
let readState = context.account.postbox.transaction { transaction -> CombinedPeerReadState? in
return transaction.getCombinedPeerReadState(messages[0].id.peerId)
}
let readState = context.engine.data.get(TelegramEngine.EngineData.Item.Messages.ReadState(id: messages[0].id.peerId))
let dataSignal: Signal<(MessageContextMenuData, [MessageId: ChatUpdatingMessageMedia], CachedPeerData?, AppConfiguration, Bool, Int32, AvailableReactions?, TranslationSettings, LoggingSettings, NotificationSoundList?), NoError> = combineLatest(
let dataSignal: Signal<(MessageContextMenuData, [MessageId: ChatUpdatingMessageMedia], InfoSummaryData, AppConfiguration, Bool, Int32, AvailableReactions?, TranslationSettings, LoggingSettings, NotificationSoundList?), NoError> = combineLatest(
loadLimits,
loadStickerSaveStatusSignal,
loadResourceStatusSignal,
context.sharedContext.chatAvailableMessageActions(postbox: context.account.postbox, accountPeerId: context.account.peerId, messageIds: Set(messages.map { $0.id })),
context.sharedContext.chatAvailableMessageActions(engine: context.engine, accountPeerId: context.account.peerId, messageIds: Set(messages.map { $0.id })),
context.account.pendingUpdateMessageManager.updatingMessageMedia
|> take(1),
cachedData,
infoSummaryData,
readState,
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, cachedData, readState, messageViewsPrivacyTips, availableReactions, sharedData, notificationSoundList -> (MessageContextMenuData, [MessageId: ChatUpdatingMessageMedia], CachedPeerData?, AppConfiguration, Bool, Int32, AvailableReactions?, TranslationSettings, LoggingSettings, NotificationSoundList?) in
|> map { limitsAndAppConfig, stickerSaveStatus, resourceStatus, messageActions, updatingMessageMedia, infoSummaryData, readState, 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 {
@ -611,12 +618,12 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
loggingSettings = LoggingSettings.defaultSettings
}
return (MessageContextMenuData(starStatus: stickerSaveStatus, canReply: canReply, canPin: canPin, canEdit: canEdit, canSelect: canSelect, resourceStatus: resourceStatus, messageActions: messageActions), updatingMessageMedia, cachedData, appConfig, isMessageRead, messageViewsPrivacyTips, availableReactions, translationSettings, loggingSettings, notificationSoundList)
return (MessageContextMenuData(starStatus: stickerSaveStatus, canReply: canReply, canPin: canPin, canEdit: canEdit, canSelect: canSelect, resourceStatus: resourceStatus, messageActions: messageActions), updatingMessageMedia, infoSummaryData, appConfig, isMessageRead, messageViewsPrivacyTips, availableReactions, translationSettings, loggingSettings, notificationSoundList)
}
return dataSignal
|> deliverOnMainQueue
|> map { data, updatingMessageMedia, cachedData, appConfig, isMessageRead, messageViewsPrivacyTips, availableReactions, translationSettings, loggingSettings, notificationSoundList -> ContextController.Items in
|> map { data, updatingMessageMedia, infoSummaryData, appConfig, isMessageRead, messageViewsPrivacyTips, availableReactions, translationSettings, loggingSettings, notificationSoundList -> ContextController.Items in
var actions: [ContextMenuItem] = []
var isPinnedMessages = false
@ -988,7 +995,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
var threadId: Int64?
var threadMessageCount: Int = 0
if case .peer = chatPresentationInterfaceState.chatLocation, let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel, case .group = channel.info {
if let cachedData = cachedData as? CachedChannelData, case let .known(maybeValue) = cachedData.linkedDiscussionPeerId, let _ = maybeValue {
if case let .known(maybeValue) = infoSummaryData.linkedDiscusionPeerId, let _ = maybeValue {
if let value = messages[0].threadId {
threadId = value
} else {
@ -1265,7 +1272,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
}
}
if let cachedData = cachedData as? CachedChannelData, cachedData.flags.contains(.canViewStats), views >= 100 {
if infoSummaryData.canViewStats, views >= 100 {
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextViewStats, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Statistics"), color: theme.actionSheet.primaryTextColor)
}, action: { c, _ in
@ -1359,7 +1366,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
}
}
let canViewStats = canViewReadStats(message: message, cachedData: cachedData, isMessageRead: isMessageRead, appConfig: appConfig)
let canViewStats = canViewReadStats(message: message, participantCount: infoSummaryData.participantCount, isMessageRead: isMessageRead, appConfig: appConfig)
var reactionCount = 0
for reaction in mergedMessageReactionsAndPeers(message: message).reactions {
reactionCount += Int(reaction.count)
@ -1467,9 +1474,13 @@ private func canPerformDeleteActions(limits: LimitsConfiguration, accountPeerId:
return false
}
func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, messageIds: Set<MessageId>, messages: [MessageId: Message] = [:], peers: [PeerId: Peer] = [:]) -> Signal<ChatAvailableMessageActions, NoError> {
return postbox.transaction { transaction -> ChatAvailableMessageActions in
let limitsConfiguration: LimitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration)?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue
func chatAvailableMessageActionsImpl(engine: TelegramEngine, accountPeerId: PeerId, messageIds: Set<MessageId>, messages: [MessageId: Message] = [:], peers: [PeerId: Peer] = [:]) -> Signal<ChatAvailableMessageActions, NoError> {
return engine.data.get(
TelegramEngine.EngineData.Item.Configuration.Limits(),
EngineDataMap(Set(messageIds.map(\.peerId)).map(TelegramEngine.EngineData.Item.Peer.Peer.init)),
EngineDataMap(Set(messageIds).map(TelegramEngine.EngineData.Item.Messages.Message.init))
)
|> map { limitsConfiguration, peerMap, messageMap -> ChatAvailableMessageActions in
var optionsMap: [MessageId: ChatAvailableMessageActionOptions] = [:]
var banPeer: Peer?
var hadPersonalIncoming = false
@ -1478,8 +1489,8 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me
var isCopyProtected = false
func getPeer(_ peerId: PeerId) -> Peer? {
if let peer = transaction.getPeer(peerId) {
return peer
if let maybePeer = peerMap[peerId], let peer = maybePeer {
return peer._asPeer()
} else if let peer = peers[peerId] {
return peer
} else {
@ -1488,8 +1499,8 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me
}
func getMessage(_ messageId: MessageId) -> Message? {
if let message = transaction.getMessage(messageId) {
return message
if let maybeMessage = messageMap[messageId], let message = maybeMessage {
return message._asMessage()
} else if let message = messages[messageId] {
return message
} else {
@ -1638,7 +1649,7 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me
}
optionsMap[id]!.insert(.deleteLocally)
var canDeleteGlobally = false
if canPerformDeleteActions(limits: limitsConfiguration, accountPeerId: accountPeerId, message: message) {
if canPerformDeleteActions(limits: limitsConfiguration._asLimits(), accountPeerId: accountPeerId, message: message) {
canDeleteGlobally = true
} else if limitsConfiguration.canRemoveIncomingMessagesInPrivateChats {
canDeleteGlobally = true

View File

@ -928,9 +928,7 @@ final class ChatMediaInputNode: ChatInputNode {
var items: [ActionSheetItem] = []
items.append(ActionSheetButtonItem(title: strongSelf.strings.Stickers_ClearRecent, color: .destructive, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
let _ = (context.account.postbox.transaction { transaction in
clearRecentlyUsedStickers(transaction: transaction)
}).start()
let _ = context.engine.stickers.clearRecentlyUsedStickers().start()
}))
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
@ -1407,16 +1405,15 @@ final class ChatMediaInputNode: ChatInputNode {
canSaveGif = false
}
let _ = (self.context.account.postbox.transaction { transaction -> Bool in
if !canSaveGif {
return false
}
return isGifSaved(transaction: transaction, mediaId: file.file.media.fileId)
}
let _ = (self.context.engine.stickers.isGifSaved(id: file.file.media.fileId)
|> deliverOnMainQueue).start(next: { [weak self] isGifSaved in
guard let strongSelf = self else {
return
}
var isGifSaved = isGifSaved
if !canSaveGif {
isGifSaved = false
}
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: PeerId(0), namespace: Namespaces.Message.Local, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: nil, text: "", attributes: [], media: [file.file.media], peers: SimpleDictionary(), associatedMessages: SimpleDictionary(), associatedMessageIds: [])
@ -1530,9 +1527,7 @@ final class ChatMediaInputNode: ChatInputNode {
if let (itemNode, item) = searchContainerNode.itemAt(point: point.offsetBy(dx: -searchContainerNode.frame.minX, dy: -searchContainerNode.frame.minY)) {
if let item = item as? StickerPreviewPeekItem {
return strongSelf.context.account.postbox.transaction { transaction -> Bool in
return getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
}
return strongSelf.context.engine.stickers.isStickerSaved(id: item.file.fileId)
|> deliverOnMainQueue
|> map { isStarred -> (ASDisplayNode, PeekControllerContent)? in
if let strongSelf = self {

View File

@ -292,9 +292,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
switch resourceStatus.mediaStatus {
case let .fetchStatus(fetchStatus):
if let context = self.context, let message = self.message, message.flags.isSending {
let _ = context.account.postbox.transaction({ transaction -> Void in
context.engine.messages.deleteMessages(transaction: transaction, ids: [message.id])
}).start()
let _ = context.engine.messages.deleteMessagesInteractively(messageIds: [message.id], type: .forEveryone).start()
} else {
switch fetchStatus {
case .Fetching:

View File

@ -846,10 +846,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
switch fetchStatus {
case .Fetching:
if item.message.flags.isSending {
let messageId = item.message.id
let _ = item.context.account.postbox.transaction({ transaction -> Void in
item.context.engine.messages.deleteMessages(transaction: transaction, ids: [messageId])
}).start()
let _ = item.context.engine.messages.deleteMessagesInteractively(messageIds: [item.message.id], type: .forEveryone).start()
} else {
messageMediaFileCancelInteractiveFetch(context: item.context, messageId: item.message.id, file: file)
}

View File

@ -307,9 +307,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
switch fetchStatus {
case .Fetching:
if let context = self.context, let message = self.message, message.flags.isSending {
let _ = context.account.postbox.transaction({ transaction -> Void in
context.engine.messages.deleteMessages(transaction: transaction, ids: [message.id])
}).start()
let _ = context.engine.messages.deleteMessagesInteractively(messageIds: [message.id], type: .forEveryone).start()
} else if let media = media, let context = self.context, let message = message {
if let media = media as? TelegramMediaFile {
messageMediaFileCancelInteractiveFetch(context: context, messageId: message.id, file: media)

View File

@ -38,7 +38,7 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
}
self.canDeleteMessagesDisposable.set(nil)
} else if let context = self.context {
self.canDeleteMessagesDisposable.set((context.sharedContext.chatAvailableMessageActions(postbox: context.account.postbox, accountPeerId: context.account.peerId, messageIds: self.selectedMessages)
self.canDeleteMessagesDisposable.set((context.sharedContext.chatAvailableMessageActions(engine: context.engine, accountPeerId: context.account.peerId, messageIds: self.selectedMessages)
|> deliverOnMainQueue).start(next: { [weak self] actions in
if let strongSelf = self {
strongSelf.actions = actions

View File

@ -117,11 +117,10 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
}
})
self.limitsConfigurationDisposable = (context.account.postbox.transaction { transaction -> LimitsConfiguration in
return currentLimitsConfiguration(transaction: transaction)
} |> deliverOnMainQueue).start(next: { [weak self] value in
self.limitsConfigurationDisposable = (context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.Limits())
|> deliverOnMainQueue).start(next: { [weak self] value in
if let strongSelf = self {
strongSelf.limitsConfiguration = value
strongSelf.limitsConfiguration = value._asLimits()
strongSelf.updateTitle()
strongSelf._limitsReady.set(.single(true))
}

View File

@ -326,9 +326,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
var items: [ActionSheetItem] = []
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Stickers_ClearRecent, color: .destructive, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
let _ = (context.account.postbox.transaction { transaction in
clearRecentlyUsedStickers(transaction: transaction)
}).start()
let _ = context.engine.stickers.clearRecentlyUsedStickers().start()
}))
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
@ -441,9 +439,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
var items: [ActionSheetItem] = []
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Stickers_ClearRecent, color: .destructive, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
let _ = (context.account.postbox.transaction { transaction in
clearRecentlyUsedStickers(transaction: transaction)
}).start()
let _ = context.engine.stickers.clearRecentlyUsedStickers().start()
}))
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in

View File

@ -476,9 +476,7 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode {
if let searchNode = strongSelf.searchNode, searchNode.isActive {
if let (itemNode, item) = searchNode.itemAt(point: strongSelf.view.convert(point, to: searchNode.view)) {
if let item = item as? StickerPreviewPeekItem {
return strongSelf.context.account.postbox.transaction { transaction -> Bool in
return getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
}
return strongSelf.context.engine.stickers.isStickerSaved(id: item.file.fileId)
|> deliverOnMainQueue
|> map { isStarred -> (ASDisplayNode, PeekControllerContent)? in
if let strongSelf = self {
@ -563,9 +561,7 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode {
let itemNodeAndItem: (ASDisplayNode, StickerPackItem)? = strongSelf.itemAt(point: point)
if let (itemNode, item) = itemNodeAndItem {
return strongSelf.context.account.postbox.transaction { transaction -> Bool in
return getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
}
return strongSelf.context.engine.stickers.isStickerSaved(id: item.file.fileId)
|> deliverOnMainQueue
|> map { isStarred -> (ASDisplayNode, PeekControllerContent)? in
if let strongSelf = self {

View File

@ -25,11 +25,9 @@ class PaneGifSearchForQueryResult {
}
func paneGifSearchForQuery(context: AccountContext, query: String, offset: String?, incompleteResults: Bool = false, staleCachedResults: Bool = false, delayRequest: Bool = true, updateActivity: ((Bool) -> Void)?) -> Signal<PaneGifSearchForQueryResult?, NoError> {
let contextBot = context.account.postbox.transaction { transaction -> String in
let configuration = currentSearchBotsConfiguration(transaction: transaction)
return configuration.gifBotUsername ?? "gif"
}
|> mapToSignal { botName -> Signal<EnginePeer?, NoError> in
let contextBot = context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.SearchBots())
|> mapToSignal { searchBots -> Signal<EnginePeer?, NoError> in
let botName = searchBots.gifBotUsername ?? "gif"
return context.engine.peers.resolvePeerByName(name: botName)
}
|> mapToSignal { peer -> Signal<(ChatPresentationInputQueryResult?, Bool, Bool), NoError> in

View File

@ -171,9 +171,7 @@ final class HorizontalStickersChatContextPanelNode: ChatInputContextPanelNode {
}
if let itemNode = strongSelf.gridNode.itemNodeAtPoint(strongSelf.view.convert(point, to: strongSelf.gridNode.view)) as? HorizontalStickerGridItemNode, let item = itemNode.stickerItem {
return strongSelf.context.account.postbox.transaction { transaction -> Bool in
return getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
}
return strongSelf.context.engine.stickers.isStickerSaved(id: item.file.fileId)
|> deliverOnMainQueue
|> map { isStarred -> (ASDisplayNode, PeekControllerContent)? in
if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction {

View File

@ -99,9 +99,7 @@ private final class InlineReactionSearchStickersNode: ASDisplayNode, UIScrollVie
}
if let itemNode = selectedNode, let item = itemNode.stickerItem {
return strongSelf.context.account.postbox.transaction { transaction -> Bool in
return getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
}
return strongSelf.context.engine.stickers.isStickerSaved(id: item.file.fileId)
|> deliverOnMainQueue
|> map { isStarred -> (ASDisplayNode, PeekControllerContent)? in
if let strongSelf = self, let controllerInteraction = strongSelf.getControllerInteraction?() {

View File

@ -434,7 +434,7 @@ public final class MediaManagerImpl: NSObject, MediaManager {
if state.status.timestamp > 5.0 && state.status.timestamp < state.status.duration - 5.0 {
storedState = MediaPlaybackStoredState(timestamp: state.status.timestamp, playbackRate: state.status.baseRate > 1.0 ? .x2 : .x1)
}
let _ = updateMediaPlaybackStoredStateInteractively(postbox: account.postbox, messageId: item.message.id, state: storedState).start()
let _ = updateMediaPlaybackStoredStateInteractively(engine: TelegramEngine(account: account), messageId: item.message.id, state: storedState).start()
}
}
}
@ -487,7 +487,7 @@ public final class MediaManagerImpl: NSObject, MediaManager {
let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.musicPlaybackSettings]?.get(MusicPlaybackSettings.self) ?? MusicPlaybackSettings.defaultSettings
if let location = playlist.location as? PeerMessagesPlaylistLocation, let messageId = location.messageId {
return mediaPlaybackStoredState(postbox: account.postbox, messageId: messageId)
return mediaPlaybackStoredState(engine: TelegramEngine(account: account), messageId: messageId)
|> map { storedState in
return (account, playlist, settings, storedState)
}

View File

@ -1849,7 +1849,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
guard let strongSelf = self else {
return
}
let _ = updateVisualMediaStoredState(postbox: strongSelf.context.account.postbox, peerId: strongSelf.peerId, messageTag: strongSelf.stateTag, state: VisualMediaStoredState(zoomLevel: Int32(zoomLevel.rawValue))).start()
let _ = updateVisualMediaStoredState(engine: strongSelf.context.engine, peerId: strongSelf.peerId, messageTag: strongSelf.stateTag, state: VisualMediaStoredState(zoomLevel: Int32(zoomLevel.rawValue))).start()
}
self._itemInteraction = VisualMediaItemInteraction(
@ -1946,7 +1946,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
strongSelf.itemGrid.cancelGestures()
}
self.storedStateDisposable = (visualMediaStoredState(postbox: context.account.postbox, peerId: peerId, messageTag: self.stateTag)
self.storedStateDisposable = (visualMediaStoredState(engine: context.engine, peerId: peerId, messageTag: self.stateTag)
|> deliverOnMainQueue).start(next: { [weak self] value in
guard let strongSelf = self else {
return
@ -2200,7 +2200,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
func updateZoomLevel(level: ZoomLevel) {
self.itemGrid.setZoomLevel(level: level.value)
let _ = updateVisualMediaStoredState(postbox: self.context.account.postbox, peerId: self.peerId, messageTag: self.stateTag, state: VisualMediaStoredState(zoomLevel: level.rawValue)).start()
let _ = updateVisualMediaStoredState(engine: self.context.engine, peerId: self.peerId, messageTag: self.stateTag, state: VisualMediaStoredState(zoomLevel: level.rawValue)).start()
}
func ensureMessageIsVisible(id: MessageId) {
@ -2575,32 +2575,25 @@ final class VisualMediaStoredState: Codable {
}
}
func visualMediaStoredState(postbox: Postbox, peerId: PeerId, messageTag: MessageTags) -> Signal<VisualMediaStoredState?, NoError> {
return postbox.transaction { transaction -> VisualMediaStoredState? in
let key = ValueBoxKey(length: 8 + 4)
key.setInt64(0, value: peerId.toInt64())
key.setUInt32(8, value: messageTag.rawValue)
if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.visualMediaStoredState, key: key))?.get(VisualMediaStoredState.self) {
return entry
} else {
return nil
}
func visualMediaStoredState(engine: TelegramEngine, peerId: PeerId, messageTag: MessageTags) -> Signal<VisualMediaStoredState?, NoError> {
let key = ValueBoxKey(length: 8 + 4)
key.setInt64(0, value: peerId.toInt64())
key.setUInt32(8, value: messageTag.rawValue)
return engine.data.get(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: ApplicationSpecificItemCacheCollectionId.visualMediaStoredState, id: key))
|> map { entry -> VisualMediaStoredState? in
return entry?.get(VisualMediaStoredState.self)
}
}
private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 25, highWaterItemCount: 50)
func updateVisualMediaStoredState(postbox: Postbox, peerId: PeerId, messageTag: MessageTags, state: VisualMediaStoredState?) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
let key = ValueBoxKey(length: 8 + 4)
key.setInt64(0, value: peerId.toInt64())
key.setUInt32(8, value: messageTag.rawValue)
let id = ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.visualMediaStoredState, key: key)
if let state = state, let entry = CodableEntry(state) {
transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec)
} else {
transaction.removeItemCacheEntry(id: id)
}
func updateVisualMediaStoredState(engine: TelegramEngine, peerId: PeerId, messageTag: MessageTags, state: VisualMediaStoredState?) -> Signal<Never, NoError> {
let key = ValueBoxKey(length: 8 + 4)
key.setInt64(0, value: peerId.toInt64())
key.setUInt32(8, value: messageTag.rawValue)
if let state = state {
return engine.itemCache.put(collectionId: ApplicationSpecificItemCacheCollectionId.visualMediaStoredState, id: key, item: state)
} else {
return engine.itemCache.remove(collectionId: ApplicationSpecificItemCacheCollectionId.visualMediaStoredState, id: key)
}
}

View File

@ -1861,7 +1861,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
let gesture: ContextGesture? = anyRecognizer as? ContextGesture
let _ = (chatAvailableMessageActionsImpl(postbox: strongSelf.context.account.postbox, accountPeerId: strongSelf.context.account.peerId, messageIds: [message.id])
let _ = (chatAvailableMessageActionsImpl(engine: strongSelf.context.engine, accountPeerId: strongSelf.context.account.peerId, messageIds: [message.id])
|> deliverOnMainQueue).start(next: { actions in
guard let strongSelf = self else {
return
@ -2016,7 +2016,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
if let previewData = previewData {
let context = strongSelf.context
let strings = strongSelf.presentationData.strings
let items = chatAvailableMessageActionsImpl(postbox: strongSelf.context.account.postbox, accountPeerId: strongSelf.context.account.peerId, messageIds: [message.id])
let items = chatAvailableMessageActionsImpl(engine: strongSelf.context.engine, accountPeerId: strongSelf.context.account.peerId, messageIds: [message.id])
|> map { actions -> [ContextMenuItem] in
var items: [ContextMenuItem] = []
@ -3285,7 +3285,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
if let timestamp = timestamp {
storedState = MediaPlaybackStoredState(timestamp: timestamp, playbackRate: AudioPlaybackRate(playbackRate))
}
let _ = updateMediaPlaybackStoredStateInteractively(postbox: strongSelf.context.account.postbox, messageId: messageId, state: storedState).start()
let _ = updateMediaPlaybackStoredStateInteractively(engine: strongSelf.context.engine, messageId: messageId, state: storedState).start()
}, editMedia: { [weak self] messageId, snapshots, transitionCompletion in
guard let strongSelf = self else {
return
@ -6379,14 +6379,13 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
private func accountContextMenuItems(context: AccountContext, logout: @escaping () -> Void) -> Signal<[ContextMenuItem], NoError> {
let strings = context.sharedContext.currentPresentationData.with({ $0 }).strings
return context.account.postbox.transaction { transaction -> [ContextMenuItem] in
return context.engine.messages.unreadChatListPeerIds(groupId: .root, filterPredicate: nil)
|> map { unreadChatListPeerIds -> [ContextMenuItem] in
var items: [ContextMenuItem] = []
if !transaction.getUnreadChatListPeerIds(groupId: .root, filterPredicate: nil).isEmpty {
if !unreadChatListPeerIds.isEmpty {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAllAsRead, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsRead"), color: theme.contextMenu.primaryColor) }, action: { _, f in
let _ = (context.account.postbox.transaction { transaction in
markAllChatsAsReadInteractively(transaction: transaction, viewTracker: context.account.viewTracker, groupId: .root, filterPredicate: nil)
}
let _ = (context.engine.messages.markAllChatsAsReadInteractively(items: [(groupId: .root, filterPredicate: nil)])
|> deliverOnMainQueue).start(completed: {
f(.default)
})
@ -6436,7 +6435,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
private func deleteMessages(messageIds: Set<MessageId>?) {
if let messageIds = messageIds ?? self.state.selectedMessageIds, !messageIds.isEmpty {
self.activeActionDisposable.set((self.context.sharedContext.chatAvailableMessageActions(postbox: self.context.account.postbox, accountPeerId: self.context.account.peerId, messageIds: messageIds)
self.activeActionDisposable.set((self.context.sharedContext.chatAvailableMessageActions(engine: self.context.engine, accountPeerId: self.context.account.peerId, messageIds: messageIds)
|> deliverOnMainQueue).start(next: { [weak self] actions in
if let strongSelf = self, let peer = strongSelf.data?.peer, !actions.options.isEmpty {
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)

View File

@ -299,20 +299,19 @@ public class ShareRootControllerImpl {
let applicationInterface = account
|> mapToSignal { sharedContext, account, otherAccounts -> Signal<(AccountContext, PostboxAccessChallengeData, [AccountWithInfo]), ShareAuthorizationError> in
let limitsConfigurationAndContentSettings = account.postbox.transaction { transaction -> (LimitsConfiguration, ContentSettings, AppConfiguration) in
return (
transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration)?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue,
getContentSettings(transaction: transaction),
getAppConfiguration(transaction: transaction)
)
}
let limitsConfigurationAndContentSettings = TelegramEngine(account: account).data.get(
TelegramEngine.EngineData.Item.Configuration.Limits(),
TelegramEngine.EngineData.Item.Configuration.ContentSettings(),
TelegramEngine.EngineData.Item.Configuration.App()
)
return combineLatest(sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationPasscodeSettings]), limitsConfigurationAndContentSettings, sharedContext.accountManager.accessChallengeData())
|> take(1)
|> deliverOnMainQueue
|> castError(ShareAuthorizationError.self)
|> map { sharedData, limitsConfigurationAndContentSettings, data -> (AccountContext, PostboxAccessChallengeData, [AccountWithInfo]) in
updateLegacyLocalization(strings: sharedContext.currentPresentationData.with({ $0 }).strings)
let context = AccountContextImpl(sharedContext: sharedContext, account: account, limitsConfiguration: limitsConfigurationAndContentSettings.0, contentSettings: limitsConfigurationAndContentSettings.1, appConfiguration: limitsConfigurationAndContentSettings.2)
let context = AccountContextImpl(sharedContext: sharedContext, account: account, limitsConfiguration: limitsConfigurationAndContentSettings.0._asLimits(), contentSettings: limitsConfigurationAndContentSettings.1, appConfiguration: limitsConfigurationAndContentSettings.2)
return (context, data.data, otherAccounts)
}
}

View File

@ -412,11 +412,13 @@ public final class SharedAccountContextImpl: SharedAccountContext {
switch result {
case let .authorized(account):
setupAccount(account, fetchCachedResourceRepresentation: fetchCachedResourceRepresentation, transformOutgoingMessageMedia: transformOutgoingMessageMedia)
return account.postbox.transaction { transaction -> AddedAccountResult in
let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration)?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue
let contentSettings = getContentSettings(transaction: transaction)
let appConfiguration = getAppConfiguration(transaction: transaction)
return .ready(id, account, attributes.sortIndex, limitsConfiguration, contentSettings, appConfiguration)
return TelegramEngine(account: account).data.get(
TelegramEngine.EngineData.Item.Configuration.Limits(),
TelegramEngine.EngineData.Item.Configuration.ContentSettings(),
TelegramEngine.EngineData.Item.Configuration.App()
)
|> map { limitsConfiguration, contentSettings, appConfiguration -> AddedAccountResult in
return .ready(id, account, attributes.sortIndex, limitsConfiguration._asLimits(), contentSettings, appConfiguration)
}
case let .upgrading(progress):
return .single(.upgrading(progress))
@ -1140,12 +1142,12 @@ public final class SharedAccountContextImpl: SharedAccountContext {
openExternalUrlImpl(context: context, urlContext: urlContext, url: url, forceExternal: forceExternal, presentationData: presentationData, navigationController: navigationController, dismissInput: dismissInput)
}
public func chatAvailableMessageActions(postbox: Postbox, accountPeerId: EnginePeer.Id, messageIds: Set<EngineMessage.Id>) -> Signal<ChatAvailableMessageActions, NoError> {
return chatAvailableMessageActionsImpl(postbox: postbox, accountPeerId: accountPeerId, messageIds: messageIds)
public func chatAvailableMessageActions(engine: TelegramEngine, accountPeerId: EnginePeer.Id, messageIds: Set<EngineMessage.Id>) -> Signal<ChatAvailableMessageActions, NoError> {
return chatAvailableMessageActionsImpl(engine: engine, accountPeerId: accountPeerId, messageIds: messageIds)
}
public func chatAvailableMessageActions(postbox: Postbox, accountPeerId: EnginePeer.Id, messageIds: Set<EngineMessage.Id>, messages: [EngineMessage.Id: EngineMessage] = [:], peers: [EnginePeer.Id: EnginePeer] = [:]) -> Signal<ChatAvailableMessageActions, NoError> {
return chatAvailableMessageActionsImpl(postbox: postbox, accountPeerId: accountPeerId, messageIds: messageIds, messages: messages.mapValues({ $0._asMessage() }), peers: peers.mapValues({ $0._asPeer() }))
public func chatAvailableMessageActions(engine: TelegramEngine, accountPeerId: EnginePeer.Id, messageIds: Set<EngineMessage.Id>, messages: [EngineMessage.Id: EngineMessage] = [:], peers: [EnginePeer.Id: EnginePeer] = [:]) -> Signal<ChatAvailableMessageActions, NoError> {
return chatAvailableMessageActionsImpl(engine: engine, accountPeerId: accountPeerId, messageIds: messageIds, messages: messages.mapValues({ $0._asMessage() }), peers: peers.mapValues({ $0._asPeer() }))
}
public func navigateToChatController(_ params: NavigateToChatControllerParams) {

View File

@ -127,9 +127,7 @@ final class StickersChatInputContextPanelNode: ChatInputContextPanelNode {
if let stickersNode = stickersNode {
let point = strongSelf.listView.view.convert(point, to: stickersNode.view)
if let (item, itemNode) = stickersNode.stickerItem(at: point) {
return strongSelf.context.account.postbox.transaction { transaction -> Bool in
return getIsStickerSaved(transaction: transaction, fileId: item.file.fileId)
}
return strongSelf.context.engine.stickers.isStickerSaved(id: item.file.fileId)
|> deliverOnMainQueue
|> map { isStarred -> (ASDisplayNode, PeekControllerContent)? in
if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction {

View File

@ -1,283 +0,0 @@
#if ENABLE_WALLET
import Foundation
import UIKit
import Display
import WalletUI
import Postbox
import TelegramCore
import AccountContext
import SwiftSignalKit
import TelegramPresentationData
import ShareController
import DeviceAccess
import PresentationDataUtils
import WalletCore
extension WalletConfiguration {
static func with(appConfiguration: AppConfiguration) -> WalletConfiguration {
if let data = appConfiguration.data, let config = data["wallet_config"] as? String, let blockchainName = data["wallet_blockchain_name"] as? String {
var disableProxy = false
if let value = data["wallet_disable_proxy"] as? String {
disableProxy = value != "0"
} else if let value = data["wallet_disable_proxy"] as? Int {
disableProxy = value != 0
}
return WalletConfiguration(config: config, blockchainName: blockchainName, disableProxy: disableProxy)
} else {
return .defaultValue
}
}
}
final class WalletStorageInterfaceImpl: WalletStorageInterface {
private let postbox: Postbox
init(postbox: Postbox) {
self.postbox = postbox
}
func watchWalletRecords() -> Signal<[WalletStateRecord], NoError> {
return self.postbox.preferencesView(keys: [PreferencesKeys.walletCollection])
|> map { view -> [WalletStateRecord] in
guard let walletCollection = view.values[PreferencesKeys.walletCollection] as? WalletCollection else {
return []
}
return walletCollection.wallets.flatMap { item -> WalletStateRecord? in
do {
return WalletStateRecord(info: try JSONDecoder().decode(WalletInfo.self, from: item.info), exportCompleted: item.exportCompleted, state: item.state.flatMap { try? JSONDecoder().decode(CombinedWalletState.self, from: $0) })
} catch {
return nil
}
}
}
}
func getWalletRecords() -> Signal<[WalletStateRecord], NoError> {
return self.postbox.transaction { transaction -> [WalletStateRecord] in
guard let walletCollection = transaction.getPreferencesEntry(key: PreferencesKeys.walletCollection) as? WalletCollection else {
return []
}
return walletCollection.wallets.flatMap { item -> WalletStateRecord? in
do {
return WalletStateRecord(info: try JSONDecoder().decode(WalletInfo.self, from: item.info), exportCompleted: item.exportCompleted, state: item.state.flatMap { try? JSONDecoder().decode(CombinedWalletState.self, from: $0) })
} catch {
return nil
}
}
}
}
func updateWalletRecords(_ f: @escaping ([WalletStateRecord]) -> [WalletStateRecord]) -> Signal<[WalletStateRecord], NoError> {
return self.postbox.transaction { transaction -> [WalletStateRecord] in
var updatedRecords: [WalletStateRecord] = []
transaction.updatePreferencesEntry(key: PreferencesKeys.walletCollection, { current in
var walletCollection = (current as? WalletCollection) ?? WalletCollection(wallets: [])
let updatedItems = f(walletCollection.wallets.flatMap { item -> WalletStateRecord? in
do {
return WalletStateRecord(info: try JSONDecoder().decode(WalletInfo.self, from: item.info), exportCompleted: item.exportCompleted, state: item.state.flatMap { try? JSONDecoder().decode(CombinedWalletState.self, from: $0) })
} catch {
return nil
}
})
walletCollection.wallets = updatedItems.flatMap { item in
do {
return WalletCollectionItem(info: try JSONEncoder().encode(item.info), exportCompleted: item.exportCompleted, state: item.state.flatMap {
try? JSONEncoder().encode($0)
})
} catch {
return nil
}
}
return walletCollection
})
return updatedRecords
}
}
func localWalletConfiguration() -> Signal<LocalWalletConfiguration, NoError> {
return .single(LocalWalletConfiguration(source: .string(""), blockchainName: ""))
}
func updateLocalWalletConfiguration(_ f: @escaping (LocalWalletConfiguration) -> LocalWalletConfiguration) -> Signal<Never, NoError> {
return .complete()
}
}
final class WalletContextImpl: WalletContext {
private let context: AccountContext
let storage: WalletStorageInterface
let tonInstance: TonInstance
let keychain: TonKeychain
let strings: PresentationStrings
let presentationData: WalletPresentationData
let supportsCustomConfigurations: Bool = false
var termsUrl: String? {
return self.strings.TelegramWallet_Intro_TermsUrl
}
var feeInfoUrl: String? {
return self.strings.AppWallet_TransactionInfo_FeeInfoURL
}
var inForeground: Signal<Bool, NoError> {
return self.context.sharedContext.applicationBindings.applicationInForeground
}
func downloadFile(url: URL) -> Signal<Data, WalletDownloadFileError> {
return .fail(.generic)
}
func updateResolvedWalletConfiguration(source: LocalWalletConfigurationSource, blockchainName: String, resolvedValue: String) -> Signal<Never, NoError> {
return .complete()
}
init(context: AccountContext, tonContext: TonContext) {
self.context = context
self.storage = WalletStorageInterfaceImpl(postbox: self.context.account.postbox)
self.tonInstance = tonContext.instance
self.keychain = tonContext.keychain
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.strings = presentationData.strings
let theme = presentationData.theme
let strings = presentationData.strings
let timeFormat: WalletTimeFormat
switch presentationData.dateTimeFormat.timeFormat {
case .military:
timeFormat = .military
case .regular:
timeFormat = .regular
}
let dateFormat: WalletDateFormat
switch presentationData.dateTimeFormat.dateFormat {
case .dayFirst:
dateFormat = .dayFirst
case .monthFirst:
dateFormat = .monthFirst
}
let navigationBarData = NavigationBarPresentationData(presentationData: presentationData)
self.presentationData = WalletPresentationData(
theme: WalletTheme(
info: WalletInfoTheme(
buttonBackgroundColor: UIColor(rgb: 0x32aafe),
buttonTextColor: .white,
incomingFundsTitleColor: theme.chatList.secretTitleColor,
outgoingFundsTitleColor: theme.list.itemDestructiveColor
), transaction: WalletTransactionTheme(
descriptionBackgroundColor: theme.chat.message.incoming.bubble.withoutWallpaper.fill,
descriptionTextColor: theme.chat.message.incoming.primaryTextColor
), setup: WalletSetupTheme(
buttonFillColor: theme.list.itemCheckColors.fillColor,
buttonForegroundColor: theme.list.itemCheckColors.foregroundColor,
inputBackgroundColor: theme.actionSheet.inputBackgroundColor,
inputPlaceholderColor: theme.actionSheet.inputPlaceholderColor,
inputTextColor: theme.actionSheet.inputTextColor,
inputClearButtonColor: theme.actionSheet.inputClearButtonColor.withAlphaComponent(0.8)
),
list: WalletListTheme(
itemPrimaryTextColor: theme.list.itemPrimaryTextColor,
itemSecondaryTextColor: theme.list.itemSecondaryTextColor,
itemPlaceholderTextColor: theme.list.itemPlaceholderTextColor,
itemDestructiveColor: theme.list.itemDestructiveColor,
itemAccentColor: theme.list.itemAccentColor,
itemDisabledTextColor: theme.list.itemDisabledTextColor,
plainBackgroundColor: theme.list.plainBackgroundColor,
blocksBackgroundColor: theme.list.blocksBackgroundColor,
itemPlainSeparatorColor: theme.list.itemPlainSeparatorColor,
itemBlocksBackgroundColor: theme.list.itemBlocksBackgroundColor,
itemBlocksSeparatorColor: theme.list.itemBlocksSeparatorColor,
itemHighlightedBackgroundColor: theme.list.itemHighlightedBackgroundColor,
sectionHeaderTextColor: theme.list.sectionHeaderTextColor,
freeTextColor: theme.list.freeTextColor,
freeTextErrorColor: theme.list.freeTextErrorColor,
inputClearButtonColor: theme.list.inputClearButtonColor
),
statusBarStyle: theme.rootController.statusBarStyle.style,
navigationBar: navigationBarData.theme,
keyboardAppearance: theme.rootController.keyboardColor.keyboardAppearance,
alert: AlertControllerTheme(presentationData: presentationData),
actionSheet: ActionSheetControllerTheme(presentationData: presentationData)
), strings: WalletStrings(
primaryComponent: WalletStringsComponent(
languageCode: strings.primaryComponent.languageCode,
localizedName: strings.primaryComponent.localizedName,
pluralizationRulesCode: strings.primaryComponent.pluralizationRulesCode,
dict: strings.primaryComponent.dict
),
secondaryComponent: strings.secondaryComponent.flatMap { component in
return WalletStringsComponent(
languageCode: component.languageCode,
localizedName: component.localizedName,
pluralizationRulesCode: component.pluralizationRulesCode,
dict: component.dict
)
},
groupingSeparator: strings.groupingSeparator
), dateTimeFormat: WalletPresentationDateTimeFormat(
timeFormat: timeFormat,
dateFormat: dateFormat,
dateSeparator: presentationData.dateTimeFormat.dateSeparator,
decimalSeparator: presentationData.dateTimeFormat.decimalSeparator,
groupingSeparator: presentationData.dateTimeFormat.groupingSeparator
)
)
}
func getServerSalt() -> Signal<Data, WalletContextGetServerSaltError> {
return getServerWalletSalt(network: self.context.account.network)
|> mapError { _ -> WalletContextGetServerSaltError in
return .generic
}
}
func presentNativeController(_ controller: UIViewController) {
self.context.sharedContext.mainWindow?.presentNative(controller)
}
func idleTimerExtension() -> Disposable {
return self.context.sharedContext.applicationBindings.pushIdleTimerExtension()
}
func openUrl(_ url: String) {
return self.context.sharedContext.openExternalUrl(context: self.context, urlContext: .generic, url: url, forceExternal: true, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {})
}
func shareUrl(_ url: String) {
let controller = ShareController(context: self.context, subject: .url(url))
self.context.sharedContext.mainWindow?.present(controller, on: .root)
}
func openPlatformSettings() {
self.context.sharedContext.applicationBindings.openSettings()
}
func authorizeAccessToCamera(completion: @escaping () -> Void) {
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
DeviceAccess.authorizeAccess(to: .camera(.video), presentationData: presentationData, present: { c, a in
c.presentationArguments = a
self.context.sharedContext.mainWindow?.present(c, on: .root)
}, openSettings: { [weak self] in
self?.openPlatformSettings()
}, { granted in
guard granted else {
return
}
completion()
})
}
func pickImage(present: @escaping (ViewController) -> Void, completion: @escaping (UIImage) -> Void) {
self.context.sharedContext.openImagePicker(context: self.context, completion: { image in
completion(image)
}, present: { [weak self] controller in
present(controller)
})
}
}
#endif

View File

@ -1,42 +0,0 @@
import Foundation
import Postbox
import TelegramCore
import SwiftSignalKit
public struct VoipDerivedState: Codable, Equatable {
public var data: Data
public static var `default`: VoipDerivedState {
return VoipDerivedState(data: Data())
}
public init(data: Data) {
self.data = data
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: StringCodingKey.self)
self.data = try container.decode(Data.self, forKey: "data")
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: StringCodingKey.self)
try container.encode(self.data, forKey: "data")
}
}
public func updateVoipDerivedStateInteractively(postbox: Postbox, _ f: @escaping (VoipDerivedState) -> VoipDerivedState) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.voipDerivedState, { entry in
let currentSettings: VoipDerivedState
if let entry = entry?.get(VoipDerivedState.self) {
currentSettings = entry
} else {
currentSettings = .default
}
return PreferencesEntry(f(currentSettings))
})
}
}

View File

@ -755,7 +755,7 @@ public final class OngoingCallContext {
}
}
public init(account: Account, callSessionManager: CallSessionManager, callId: CallId, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal<NetworkType, NoError>, serializedData: String?, dataSaving: VoiceCallDataSaving, derivedState: VoipDerivedState, key: Data, isOutgoing: Bool, video: OngoingCallVideoCapturer?, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, allowP2P: Bool, enableTCP: Bool, enableStunMarking: Bool, audioSessionActive: Signal<Bool, NoError>, logName: String, preferredVideoCodec: String?) {
public init(account: Account, callSessionManager: CallSessionManager, callId: CallId, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal<NetworkType, NoError>, serializedData: String?, dataSaving: VoiceCallDataSaving, key: Data, isOutgoing: Bool, video: OngoingCallVideoCapturer?, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, allowP2P: Bool, enableTCP: Bool, enableStunMarking: Bool, audioSessionActive: Signal<Bool, NoError>, logName: String, preferredVideoCodec: String?) {
let _ = setupLogs
OngoingCallThreadLocalContext.applyServerConfig(serializedData)
@ -871,7 +871,7 @@ public final class OngoingCallContext {
}
}
let context = OngoingCallThreadLocalContextWebrtc(version: version, queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForTypeWebrtc(initialNetworkType), dataSaving: ongoingDataSavingForTypeWebrtc(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, connections: filteredConnections, maxLayer: maxLayer, allowP2P: allowP2P, allowTCP: enableTCP, enableStunMarking: enableStunMarking, logPath: tempLogPath, statsLogPath: tempStatsLogPath, sendSignalingData: { [weak callSessionManager] data in
let context = OngoingCallThreadLocalContextWebrtc(version: version, queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForTypeWebrtc(initialNetworkType), dataSaving: ongoingDataSavingForTypeWebrtc(dataSaving), derivedState: Data(), key: key, isOutgoing: isOutgoing, connections: filteredConnections, maxLayer: maxLayer, allowP2P: allowP2P, allowTCP: enableTCP, enableStunMarking: enableStunMarking, logPath: tempLogPath, statsLogPath: tempStatsLogPath, sendSignalingData: { [weak callSessionManager] data in
queue.async {
guard let strongSelf = self else {
return
@ -966,7 +966,7 @@ public final class OngoingCallContext {
break
}
}
let context = OngoingCallThreadLocalContext(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForType(initialNetworkType), dataSaving: ongoingDataSavingForType(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescription(connections.primary)!, alternativeConnections: connections.alternatives.compactMap(callConnectionDescription), maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath)
let context = OngoingCallThreadLocalContext(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForType(initialNetworkType), dataSaving: ongoingDataSavingForType(dataSaving), derivedState: Data(), key: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescription(connections.primary)!, alternativeConnections: connections.alternatives.compactMap(callConnectionDescription), maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath)
strongSelf.contextRef = Unmanaged.passRetained(OngoingCallThreadLocalContextHolder(context))
context.stateChanged = { state in
@ -1089,10 +1089,6 @@ public final class OngoingCallContext {
})
}
}
let derivedState = context.nativeGetDerivedState()
let _ = updateVoipDerivedStateInteractively(postbox: self.account.postbox, { _ in
return VoipDerivedState(data: derivedState)
}).start()
}
}

View File

@ -94,16 +94,10 @@ public final class CachedChannelAdminRanks: Codable {
}
}
private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 100, highWaterItemCount: 200)
public func cachedChannelAdminRanksEntryId(peerId: PeerId) -> ItemCacheEntryId {
return ItemCacheEntryId(collectionId: 100, key: CachedChannelAdminRanks.cacheKey(peerId: peerId))
}
func updateCachedChannelAdminRanks(postbox: Postbox, peerId: PeerId, ranks: Dictionary<PeerId, CachedChannelAdminRank>) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
if let entry = CodableEntry(CachedChannelAdminRanks(ranks: ranks)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: 100, key: CachedChannelAdminRanks.cacheKey(peerId: peerId)), entry: entry, collectionSpec: collectionSpec)
}
}
func updateCachedChannelAdminRanks(engine: TelegramEngine, peerId: PeerId, ranks: Dictionary<PeerId, CachedChannelAdminRank>) -> Signal<Never, NoError> {
return engine.itemCache.put(collectionId: 100, id: CachedChannelAdminRanks.cacheKey(peerId: peerId), item: CachedChannelAdminRanks(ranks: ranks))
}

View File

@ -132,7 +132,7 @@ private final class ChannelMemberSingleCategoryListContext: ChannelMemberCategor
return ranks
}
if ranks != previousRanks {
let _ = updateCachedChannelAdminRanks(postbox: self.postbox, peerId: self.peerId, ranks: ranks).start()
let _ = updateCachedChannelAdminRanks(engine: self.engine, peerId: self.peerId, ranks: ranks).start()
}
}
}

View File

@ -727,8 +727,8 @@ public func resolveUrlImpl(context: AccountContext, peerId: PeerId?, url: String
return ApplicationSpecificNotice.getSecretChatLinkPreviews(accountManager: context.sharedContext.accountManager)
|> mapToSignal { linkPreviews -> Signal<ResolvedUrl, NoError> in
return context.account.postbox.transaction { transaction -> Signal<ResolvedUrl, NoError> in
let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue
return context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.App())
|> mapToSignal { appConfiguration -> Signal<ResolvedUrl, NoError> in
let urlHandlingConfiguration = UrlHandlingConfiguration.with(appConfiguration: appConfiguration)
var skipUrlAuth = skipUrlAuth
@ -786,7 +786,7 @@ public func resolveUrlImpl(context: AccountContext, peerId: PeerId?, url: String
}
}
return .single(.externalUrl(url))
} |> switchToLatest
}
}
}

View File

@ -27,8 +27,6 @@ public final class CachedWallpaper: Codable {
}
}
private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 10000, highWaterItemCount: 20000)
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)
@ -58,7 +56,7 @@ public func cachedWallpaper(account: Account, slug: String, settings: WallpaperS
break
}
if let entry = CodableEntry(CachedWallpaper(wallpaper: wallpaper)) {
transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec)
transaction.putItemCacheEntry(id: id, entry: entry)
}
if let settings = settings {
return CachedWallpaper(wallpaper: wallpaper.withUpdatedSettings(settings))
@ -75,16 +73,12 @@ public func cachedWallpaper(account: Account, slug: String, settings: WallpaperS
} |> switchToLatest
}
public func updateCachedWallpaper(account: Account, wallpaper: TelegramWallpaper) {
public func updateCachedWallpaper(engine: TelegramEngine, wallpaper: TelegramWallpaper) {
guard case let .file(file) = wallpaper, file.id != 0 else {
return
}
let _ = (account.postbox.transaction { transaction in
let key = ValueBoxKey(length: 8)
key.setInt64(0, value: Int64(bitPattern: file.slug.persistentHashValue))
let id = ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedWallpapers, key: key)
if let entry = CodableEntry(CachedWallpaper(wallpaper: wallpaper)) {
transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec)
}
}).start()
let key = ValueBoxKey(length: 8)
key.setInt64(0, value: Int64(bitPattern: file.slug.persistentHashValue))
let _ = engine.itemCache.put(collectionId: ApplicationSpecificItemCacheCollectionId.cachedWallpapers, id: key, item: CachedWallpaper(wallpaper: wallpaper)).start()
}

View File

@ -280,7 +280,7 @@ public final class WebSearchController: ViewController {
}
}, deleteRecentQuery: { [weak self] query in
if let strongSelf = self {
_ = removeRecentWebSearchQuery(postbox: strongSelf.context.account.postbox, string: query).start()
let _ = removeRecentWebSearchQuery(engine: strongSelf.context.engine, string: query).start()
}
}, toggleSelection: { [weak self] result, value in
if let strongSelf = self {
@ -415,7 +415,7 @@ public final class WebSearchController: ViewController {
private func updateSearchQuery(_ query: String) {
if !query.isEmpty {
let _ = addRecentWebSearchQuery(postbox: self.context.account.postbox, string: query).start()
let _ = addRecentWebSearchQuery(engine: self.context.engine, string: query).start()
}
let scope: Signal<WebSearchScope?, NoError>

View File

@ -291,7 +291,7 @@ class WebSearchControllerNode: ASDisplayNode {
}
let header = ChatListSearchItemHeader(type: .recentPeers, theme: interfaceState.presentationData.theme, strings: interfaceState.presentationData.strings, actionTitle: interfaceState.presentationData.strings.WebSearch_RecentSectionClear, action: {
_ = clearRecentWebSearchQueries(postbox: strongSelf.context.account.postbox).start()
let _ = clearRecentWebSearchQueries(engine: strongSelf.context.engine).start()
})
let previousEntries = previousRecentItems.swap(entries)

View File

@ -1,6 +1,7 @@
import Foundation
import UIKit
import Postbox
import TelegramCore
import SwiftSignalKit
import TelegramUIPreferences
@ -35,42 +36,36 @@ public final class RecentWebSearchQueryItem: Codable {
}
}
func addRecentWebSearchQuery(postbox: Postbox, string: String) -> Signal<Void, NoError> {
return postbox.transaction { transaction in
if let itemId = WebSearchRecentQueryItemId(string) {
if let entry = CodableEntry(RecentWebSearchQueryItem()) {
transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: ApplicationSpecificOrderedItemListCollectionId.webSearchRecentQueries, item: OrderedItemListEntry(id: itemId.rawValue, contents: entry), removeTailIfCountExceeds: 100)
}
}
func addRecentWebSearchQuery(engine: TelegramEngine, string: String) -> Signal<Never, NoError> {
if let itemId = WebSearchRecentQueryItemId(string) {
return engine.orderedLists.addOrMoveToFirstPosition(collectionId: ApplicationSpecificOrderedItemListCollectionId.webSearchRecentQueries, id: itemId.rawValue, item: RecentWebSearchQueryItem(), removeTailIfCountExceeds: 100)
} else {
return .complete()
}
}
func removeRecentWebSearchQuery(postbox: Postbox, string: String) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
if let itemId = WebSearchRecentQueryItemId(string) {
transaction.removeOrderedItemListItem(collectionId: ApplicationSpecificOrderedItemListCollectionId.webSearchRecentQueries, itemId: itemId.rawValue)
}
func removeRecentWebSearchQuery(engine: TelegramEngine, string: String) -> Signal<Never, NoError> {
if let itemId = WebSearchRecentQueryItemId(string) {
return engine.orderedLists.removeItem(collectionId: ApplicationSpecificOrderedItemListCollectionId.webSearchRecentQueries, id: itemId.rawValue)
} else {
return .complete()
}
}
func clearRecentWebSearchQueries(postbox: Postbox) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
transaction.replaceOrderedItemListItems(collectionId: ApplicationSpecificOrderedItemListCollectionId.webSearchRecentQueries, items: [])
}
func clearRecentWebSearchQueries(engine: TelegramEngine) -> Signal<Never, NoError> {
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
return postbox.transaction { transaction -> [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)
}
}
return result
|> mapToSignal { view -> Signal<[String], NoError> 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)
}
}
return .single(result)
}
}